commit 4fcfd480baf7e35fc0e6e0c126c0cb485d613fee
parent e4436d66cd11e9aa7feec3c9feb6722daeba86a8
Author: Brian Swetland <swetland@frotz.net>
Date: Thu, 3 Jul 2014 23:02:31 -0700
axi_sram and axi_pattern_writer and a simple test for them
Diffstat:
4 files changed, 389 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -24,5 +24,12 @@ MODULE_SRCS += $(HDMI_SRCS)
MODULE_SRCS += hdl/zybo_hdmi.xdc
include build/vivado-bitfile.mk
+MODULE_NAME := axi-write-to-sram
+MODULE_SRCS := hdl/test/axi_write_to_sram.sv
+MODULE_SRCS += hdl/axi_ifc.sv
+MODULE_SRCS += hdl/axi_sram.sv
+MODULE_SRCS += hdl/axi_pattern_writer.sv
+include build/verilator-sim.mk
+
clean::
rm -rf sim synth out
diff --git a/hdl/axi_pattern_writer.sv b/hdl/axi_pattern_writer.sv
@@ -0,0 +1,132 @@
+// Copyright 2014 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+`timescale 1ns/1ps
+
+module axi_pattern_writer(
+ input trigger,
+ input clk,
+ axi_ifc.master m
+ );
+
+parameter ADDR = 32'h00000000;
+parameter PTTN = 32'h12345678;
+
+localparam STATE_IDLE = 4'd0;
+localparam STATE_WADDR = 4'd1;
+localparam STATE_WDATA = 4'd2;
+localparam STATE_ACK = 4'd3;
+
+initial m.awvalid = 0;
+initial m.wvalid = 0;
+
+reg [31:0]waddr = ADDR;
+reg [31:0]wdata = PTTN;
+reg [31:0]wdata_next;
+
+reg [3:0]state = STATE_IDLE;
+reg [3:0]state_next;
+
+reg awvalid_next;
+reg wvalid_next;
+reg bready_next;
+reg wlast_next;
+
+reg [3:0]count = 15;
+reg [3:0]count_next;
+
+wire count_is_zero = (count == 4'h0);
+wire count_is_one = (count == 4'h1);
+
+always_comb begin
+ state_next = state;
+ count_next = count;
+ wdata_next = wdata;
+ awvalid_next = 0;
+ wvalid_next = 0;
+ bready_next = 0;
+ wlast_next = 0;
+
+ case (state)
+ STATE_IDLE: begin
+ if (trigger) begin
+ state_next = STATE_WADDR;
+ awvalid_next = 1;
+ end
+ end
+ STATE_WADDR: begin
+ if (m.awready) begin
+ state_next = STATE_WDATA;
+ wvalid_next = 1;
+ end else begin
+ awvalid_next = 1;
+ end
+ end
+ STATE_WDATA: begin
+ if (count_is_zero) begin
+ if (m.wready) begin
+ state_next = STATE_ACK;
+ bready_next = 1;
+ end else begin
+ wvalid_next = 1;
+ wlast_next = 1;
+ end
+ end else begin
+ wvalid_next = 1;
+ if (m.wready) begin
+ if (count_is_one) begin
+ wlast_next = 1;
+ end
+ count_next = count - 1;
+ wdata_next = { wdata[3:0], wdata[31:4] };
+ end
+ end
+ end
+ STATE_ACK: begin
+ if (m.bvalid) begin
+ state_next = STATE_IDLE;
+ count_next = 15;
+ wdata_next = 32'h12345678;
+ end else begin
+ bready_next = 1;
+ end
+ end
+ default: state_next = STATE_IDLE;
+ endcase
+end
+
+assign m.awid = 0;
+assign m.awburst = 1;
+assign m.awcache = 0;
+assign m.awsize = 2;
+assign m.awlen = 15;
+assign m.awlock = 0;
+
+assign m.awaddr = waddr;
+assign m.wdata = wdata;
+assign m.wstrb = 4'b1111;
+
+always_ff @(posedge clk) begin
+ state <= state_next;
+ count <= count_next;
+ wdata <= wdata_next;
+ m.awvalid <= awvalid_next;
+ m.wvalid <= wvalid_next;
+ m.bready <= bready_next;
+ m.wlast <= wlast_next;
+end
+
+assign m.arvalid = 0;
+
+endmodule
diff --git a/hdl/axi_sram.sv b/hdl/axi_sram.sv
@@ -0,0 +1,196 @@
+// Copyright 2014 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+`timescale 1ns/1ps
+
+module axi_sram(
+ input clk,
+ axi_ifc.slave s
+ );
+
+// inherit configuration from AXI interface
+// sadly this does not work with localparam (at least in verilator)
+`define IWIDTH $bits(s.awid)
+`define AWIDTH $bits(s.awaddr)
+`define DWIDTH $bits(s.wdata)
+
+// LIMITATIONS / TODO
+// - only supports INCR bursts (and treats all bursts as INCR type)
+// - investigate raising BVALID earlier to possibly save a cycle at EOB
+
+typedef enum reg[1:0] { W_IDLE, W_DATA, W_ACK } wstate_t;
+wstate_t wstate = W_IDLE;
+wstate_t next_wstate;
+
+wire do_mem_wr;
+
+reg [`IWIDTH-1:0]next_bid;
+reg next_awready;
+reg next_wready;
+reg next_bvalid;
+
+reg [`AWIDTH-1:0]waddr = 0;
+reg [`AWIDTH-1:0]next_waddr;
+
+wire [`AWIDTH-1:0]waddr_plus_four;
+assign waddr_plus_four = waddr + 32'h4;
+
+assign do_mem_wr = s.wvalid & s.wready;
+
+always_comb begin
+ next_wstate = wstate;
+ next_waddr = waddr;
+ next_bid = s.bid;
+ next_awready = 0;
+ next_wready = 0;
+ next_bvalid = 0;
+ case (wstate)
+ W_IDLE: begin
+ if (s.awvalid & s.awready) begin
+ next_waddr = s.awaddr;
+ next_bid = s.awid;
+ next_wstate = W_DATA;
+ next_wready = 1;
+ end else begin
+ next_awready = 1;
+ end
+ end
+ W_DATA: begin
+ if (s.wvalid) begin
+ next_waddr = waddr_plus_four;
+ if (s.wlast) begin
+ next_wstate = W_ACK;
+ next_bvalid = 1;
+ end else begin
+ next_wready = 1;
+ end
+ end else begin
+ next_wready = 1;
+ end
+ end
+ W_ACK: begin
+ if (s.bready) begin
+ next_wstate = W_IDLE;
+ next_waddr = s.awaddr;
+ next_awready = 1;
+ end else begin
+ next_bvalid = 1;
+ end
+ end
+ default: next_wstate = W_IDLE;
+ endcase
+end
+
+typedef enum reg[0:0] { R_IDLE, R_DATA } rstate_t;
+rstate_t rstate = R_IDLE;
+rstate_t next_rstate;
+
+reg [`IWIDTH-1:0]next_rid;
+reg next_arready;
+reg next_rvalid;
+reg next_rlast;
+
+reg [7:0]rcount = 0;
+reg [7:0]next_rcount;
+reg [`AWIDTH-1:0]raddr = 0;
+reg [`AWIDTH-1:0]next_raddr;
+
+wire [`AWIDTH-1:0]raddr_plus_four;
+assign raddr_plus_four = raddr + 32'h4;
+
+wire rcount_is_zero;
+assign rcount_is_zero = (rcount == 0);
+
+wire rcount_is_one;
+assign rcount_is_one = (rcount == 1);
+
+always_comb begin
+ next_rstate = rstate;
+ next_raddr = raddr;
+ next_rid = s.rid;
+ next_rcount = rcount;
+ next_arready = 0;
+ next_rvalid = 0;
+ next_rlast = 0;
+ case (rstate)
+ R_IDLE: begin
+ if (s.arready & s.arvalid) begin
+ next_rstate = R_DATA;
+ next_raddr = s.araddr;
+ next_rid = s.arid;
+ next_rcount = s.arlen;
+ next_rvalid = 1;
+
+ // special case for 1-beat bursts
+ if (s.arlen == 0)
+ next_rlast = 1;
+ end else begin
+ next_arready = 1;
+ end
+ end
+ R_DATA: begin
+ if (s.rready & s.rvalid) begin
+ next_raddr = raddr_plus_four;
+ next_rcount = rcount - 1;
+ if (rcount_is_zero) begin
+ next_rstate = R_IDLE;
+ next_arready = 1;
+ end else begin
+ if (rcount_is_one)
+ next_rlast = 1;
+ next_rvalid = 1;
+ end
+ end else begin
+ if (rcount_is_zero)
+ next_rlast = 1;
+ next_rvalid = 1;
+ end
+ end
+ endcase
+end
+
+assign s.bresp = 0; // always OK
+assign s.rresp = 0; // always OK
+
+always_ff @(posedge clk) begin
+ wstate <= next_wstate;
+ waddr <= next_waddr;
+ s.awready <= next_awready;
+ s.wready <= next_wready;
+ s.bvalid <= next_bvalid;
+ s.bid <= next_bid;
+
+ rstate <= next_rstate;
+ raddr <= next_raddr;
+ rcount <= next_rcount;
+ s.arready <= next_arready;
+ s.rvalid <= next_rvalid;
+ s.rlast <= next_rlast;
+ s.rid <= next_rid;
+end
+
+// --- sram ----
+
+reg [`DWIDTH-1:0]memory[0:4095];
+
+always @(posedge clk) begin
+ if (do_mem_wr) begin
+ $display("mem[%x] = %x", waddr, s.wdata);
+ memory[waddr[13:2]] <= s.wdata;
+ end
+ //TODO: only when needed:
+ s.rdata <= memory[next_raddr[13:2]];
+end
+
+endmodule
diff --git a/hdl/test/axi_write_to_sram.sv b/hdl/test/axi_write_to_sram.sv
@@ -0,0 +1,54 @@
+// Copyright 2014 Brian Swetland <swetland@frotz.net>
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+`timescale 1ns / 1ps
+
+`ifdef verilator
+module testbench(inout clk);
+`else
+module testbench();
+reg clk = 0;
+always #5 clk = ~clk;
+`endif
+
+reg go = 0;
+
+axi_ifc axi0();
+
+axi_pattern_writer writer0(
+ .clk(clk),
+ .trigger(go),
+ .m(axi0)
+ );
+
+axi_sram sram0(
+ .clk(clk),
+ .s(axi0)
+ );
+
+integer count = 0;
+
+always_ff @(posedge clk) begin
+ count <= count + 1;
+ case (count)
+ 5: go <= 1;
+ 6: go <= 0;
+ 30: go <= 1;
+ 31: go <= 0;
+ 100: $finish();
+ endcase
+end
+
+endmodule
+