zynq-sandbox

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

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:
MMakefile | 7+++++++
Ahdl/axi_pattern_writer.sv | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahdl/axi_sram.sv | 196+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahdl/test/axi_write_to_sram.sv | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
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 +