diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..964df4d --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*~ +*.lxt +*.pyc +*.vvp +*.kate-swp + diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..7dab2b3 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Alex Forencich diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..6923387 --- /dev/null +++ b/COPYING @@ -0,0 +1,19 @@ +Copyright (c) 2018 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README b/README new file mode 120000 index 0000000..42061c0 --- /dev/null +++ b/README @@ -0,0 +1 @@ +README.md \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..62d23d5 --- /dev/null +++ b/README.md @@ -0,0 +1,162 @@ +# Verilog AXI Components Readme + +For more information and updates: http://alexforencich.com/wiki/en/verilog/axi/start + +GitHub repository: https://github.com/alexforencich/verilog-axi + +## Introduction + +Collection of AXI4 bus components. Most components are fully parametrizable +in interface widths. Includes full MyHDL testbench with intelligent bus +cosimulation endpoints. + +## Documentation + +### axi_ram module + +RAM with parametrizable data and address interface widths. Supports FIXED and +INCR burst types as well as narrow bursts. + +### Common signals + + awid : Write address ID + awaddr : Write address + awlen : Write burst length + awsize : Write burst size + awburst : Write burst type + awlock : Write locking + awcache : Write cache handling + awprot : Write protection level + awqos : Write QoS setting + awregion : Write region + awuser : Write user sideband signal + awvalid : Write address valid + awready : Write address ready (from slave) + wdata : Write data + wstrb : Write data strobe (byte select) + wlast : Write data last transfer in burst + wuser : Write data user sideband signal + wvalid : Write data valid + wready : Write data ready (from slave) + bid : Write response ID + bresp : Write response + buser : Write response user sideband signal + bvalid : Write response valid + bready : Write response ready (from master) + arid : Read address ID + araddr : Read address + arlen : Read burst length + arsize : Read burst size + arburst : Read burst type + arlock : Read locking + arcache : Read cache handling + arprot : Read protection level + arqos : Read QoS setting + arregion : Read region + aruser : Read user sideband signal + arvalid : Read address valid + arready : Read address ready (from slave) + rid : Read data ID + rdata : Read data + rresp : Read response + rlast : Read data last transfer in burst + ruser : Read data user sideband signal + rvalid : Read response valid + rready : Read response ready (from master) + +### Common parameters + + ADDR_WIDTH : width of awaddr and araddr signals + DATA_WIDTH : width of wdata and rdata signals + STRB_WIDTH : width of wstrb signal + ID_WIDTH : width of *id signals + USER_WIDTH : width of *user signals + +### Source Files + + rtl/arbiter.v : Parametrizable arbiter + rtl/axi_ram.v : Parametrizable AXI RAM + rtl/priority_encoder.v : Parametrizable priority encoder + +### AXI4-Lite Interface Example + +Write + + ___ ___ ___ ___ ___ + clk ___/ \___/ \___/ \___/ \___/ \___ + _______ + awid XXXX_ID____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + _______ + awaddr XXXX_ADDR__XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + _______ + awlen XXXX_00____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + _______ + awsize XXXX_0_____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + _______ + awburst XXXX_0_____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + _______ + awprot XXXX_PROT__XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + _______ + awvalid ___/ \_______________________________ + ___________ _______________________ + awready \_______/ + _______________ + wdata XXXX_DATA__________XXXXXXXXXXXXXXXXXXXXXXXX + _______________ + wstrb XXXX_STRB__________XXXXXXXXXXXXXXXXXXXXXXXX + _______________ + wvalid ___/ \_______________________ + _______ + wready ___________/ \_______________________ + _______ + bid XXXXXXXXXXXXXXXXXXXXXXXXXXXX_ID____XXXXXXXX + _______ + bresp XXXXXXXXXXXXXXXXXXXXXXXXXXXX_RESP__XXXXXXXX + _______ + bvalid ___________________________/ \_______ + ___________________________________________ + bready + + +Read + + ___ ___ ___ ___ ___ + clk ___/ \___/ \___/ \___/ \___/ \___ + _______ + arid XXXX_ID____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + _______ + araddr XXXX_ADDR__XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + _______ + arlen XXXX_00____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + _______ + arsize XXXX_0_____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + _______ + arburst XXXX_0_____XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + _______ + arprot XXXX_PROT__XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + _______ + arvalid ___/ \_______________________________ + ___________________________________________ + arready + _______ + rid XXXXXXXXXXXXXXXXXXXXXXXXXXXX_ID____XXXXXXXX + _______ + rdata XXXXXXXXXXXXXXXXXXXXXXXXXXXX_DATA__XXXXXXXX + _______ + rresp XXXXXXXXXXXXXXXXXXXXXXXXXXXX_RESP__XXXXXXXX + _______ + rvalid ___________________________/ \_______ + ___________________________________________ + rready + + +## Testing + +Running the included testbenches requires MyHDL and Icarus Verilog. Make sure +that myhdl.vpi is installed properly for cosimulation to work correctly. The +testbenches can be run with a Python test runner like nose or py.test, or the +individual test scripts can be run with python directly. + +### Testbench Files + + tb/axi.py : MyHDL AXI4 master and memory BFM diff --git a/rtl/axi_ram.v b/rtl/axi_ram.v new file mode 100644 index 0000000..bb717a7 --- /dev/null +++ b/rtl/axi_ram.v @@ -0,0 +1,385 @@ +/* + +Copyright (c) 2018 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * AXI4 RAM + */ +module axi_ram # +( + parameter DATA_WIDTH = 32, // width of data bus in bits + parameter ADDR_WIDTH = 16, // width of address bus in bits + parameter STRB_WIDTH = (DATA_WIDTH/8), + parameter ID_WIDTH = 8 +) +( + input wire clk, + input wire rst, + + input wire [ID_WIDTH-1:0] s_axi_awid, + input wire [ADDR_WIDTH-1:0] s_axi_awaddr, + input wire [7:0] s_axi_awlen, + input wire [2:0] s_axi_awsize, + input wire [1:0] s_axi_awburst, + input wire s_axi_awlock, + input wire [3:0] s_axi_awcache, + input wire [2:0] s_axi_awprot, + input wire s_axi_awvalid, + output wire s_axi_awready, + input wire [DATA_WIDTH-1:0] s_axi_wdata, + input wire [STRB_WIDTH-1:0] s_axi_wstrb, + input wire s_axi_wlast, + input wire s_axi_wvalid, + output wire s_axi_wready, + output wire [ID_WIDTH-1:0] s_axi_bid, + output wire [1:0] s_axi_bresp, + output wire s_axi_bvalid, + input wire s_axi_bready, + input wire [ID_WIDTH-1:0] s_axi_arid, + input wire [ADDR_WIDTH-1:0] s_axi_araddr, + input wire [7:0] s_axi_arlen, + input wire [2:0] s_axi_arsize, + input wire [1:0] s_axi_arburst, + input wire s_axi_arlock, + input wire [3:0] s_axi_arcache, + input wire [2:0] s_axi_arprot, + input wire s_axi_arvalid, + output wire s_axi_arready, + output wire [ID_WIDTH-1:0] s_axi_rid, + output wire [DATA_WIDTH-1:0] s_axi_rdata, + output wire [1:0] s_axi_rresp, + output wire s_axi_rlast, + output wire s_axi_rvalid, + input wire s_axi_rready +); + +parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(STRB_WIDTH); +parameter WORD_WIDTH = STRB_WIDTH; +parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH; + +// bus width assertions +initial begin + if (WORD_SIZE * STRB_WIDTH != DATA_WIDTH) begin + $error("Error: AXI data width not evenly divisble"); + $finish; + end + + if (2**$clog2(WORD_WIDTH) != WORD_WIDTH) begin + $error("Error: AXI word width must be even power of two"); + $finish; + end +end + +localparam [0:0] + READ_STATE_IDLE = 1'd0, + READ_STATE_BURST = 1'd1; + +reg [0:0] read_state_reg = READ_STATE_IDLE, read_state_next; + +localparam [0:0] + WRITE_STATE_IDLE = 1'd0, + WRITE_STATE_BURST = 1'd1; + +reg [0:0] write_state_reg = WRITE_STATE_IDLE, write_state_next; + +reg mem_wr_en; +reg mem_rd_en; + +reg [ID_WIDTH-1:0] read_id_reg = {ID_WIDTH{1'b0}}, read_id_next; +reg [ADDR_WIDTH-1:0] read_addr_reg = {ADDR_WIDTH{1'b0}}, read_addr_next; +reg read_addr_valid_reg = 1'b0, read_addr_valid_next; +reg read_addr_ready; +reg read_last_reg = 1'b0, read_last_next; +reg [7:0] read_count_reg = 8'd0, read_count_next; +reg [2:0] read_size_reg = 3'd0, read_size_next; +reg [1:0] read_burst_reg = 2'd0, read_burst_next; +reg [ID_WIDTH-1:0] write_id_reg = {ID_WIDTH{1'b0}}, write_id_next; +reg [ADDR_WIDTH-1:0] write_addr_reg = {ADDR_WIDTH{1'b0}}, write_addr_next; +reg write_addr_valid_reg = 1'b0, write_addr_valid_next; +reg write_addr_ready; +reg [7:0] write_count_reg = 8'd0, write_count_next; +reg [2:0] write_size_reg = 3'd0, write_size_next; +reg [1:0] write_burst_reg = 2'd0, write_burst_next; + +reg s_axi_awready_reg = 1'b0, s_axi_awready_next; +reg s_axi_wready_reg = 1'b0, s_axi_wready_next; +reg [ID_WIDTH-1:0] s_axi_bid_reg = {ID_WIDTH{1'b0}}, s_axi_bid_next; +reg [1:0] s_axi_bresp_reg = 2'b00, s_axi_bresp_next; +reg s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next; +reg s_axi_arready_reg = 1'b0, s_axi_arready_next; +reg [ID_WIDTH-1:0] s_axi_rid_reg = {ID_WIDTH{1'b0}}, s_axi_rid_next; +reg [DATA_WIDTH-1:0] s_axi_rdata_reg = {DATA_WIDTH{1'b0}}, s_axi_rdata_next; +reg [1:0] s_axi_rresp_reg = 2'b00, s_axi_rresp_next; +reg s_axi_rlast_reg = 1'b0, s_axi_rlast_next; +reg s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next; + +// (* RAM_STYLE="BLOCK" *) +reg [DATA_WIDTH-1:0] mem[(2**VALID_ADDR_WIDTH)-1:0]; + +wire [VALID_ADDR_WIDTH-1:0] s_axi_awaddr_valid = s_axi_awaddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH); +wire [VALID_ADDR_WIDTH-1:0] s_axi_araddr_valid = s_axi_araddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH); +wire [VALID_ADDR_WIDTH-1:0] read_addr_valid = read_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH); +wire [VALID_ADDR_WIDTH-1:0] write_addr_valid = write_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH); + +assign s_axi_awready = s_axi_awready_reg; +assign s_axi_wready = s_axi_wready_reg; +assign s_axi_bid = s_axi_bid_reg; +assign s_axi_bresp = s_axi_bresp_reg; +assign s_axi_bvalid = s_axi_bvalid_reg; +assign s_axi_arready = s_axi_arready_reg; +assign s_axi_rid = s_axi_rid_reg; +assign s_axi_rdata = s_axi_rdata_reg; +assign s_axi_rresp = s_axi_rresp_reg; +assign s_axi_rlast = s_axi_rlast_reg; +assign s_axi_rvalid = s_axi_rvalid_reg; + +integer i, j; + +initial begin + // two nested loops for smaller number of iterations per loop + // workaround for synthesizer complaints about large loop counts + for (i = 0; i < 2**ADDR_WIDTH; i = i + 2**(ADDR_WIDTH/2)) begin + for (j = i; j < i + 2**(ADDR_WIDTH/2); j = j + 1) begin + mem[j] = 0; + end + end +end + +always @* begin + write_state_next = WRITE_STATE_IDLE; + + mem_wr_en = 1'b0; + + write_addr_ready = 1'b0; + + if (s_axi_wready & s_axi_wvalid) begin + write_addr_ready = 1'b1; + mem_wr_en = 1'b1; + end + + write_id_next = write_id_reg; + write_addr_next = write_addr_reg; + write_addr_valid_next = write_addr_valid_reg & ~write_addr_ready; + write_count_next = write_count_reg; + write_size_next = write_size_reg; + write_burst_next = write_burst_reg; + + s_axi_awready_next = 1'b0; + s_axi_wready_next = write_addr_valid_next; + s_axi_bid_next = s_axi_bid_reg; + s_axi_bresp_next = s_axi_bresp_reg; + s_axi_bvalid_next = s_axi_bvalid_reg & ~s_axi_bready; + + case (write_state_reg) + WRITE_STATE_IDLE: begin + s_axi_awready_next = (write_addr_ready || ~write_addr_valid_reg) & (~s_axi_bvalid | s_axi_bready); + + write_id_next = s_axi_awid; + write_addr_next = s_axi_awaddr; + write_count_next = s_axi_awlen; + write_size_next = s_axi_awsize < $clog2(STRB_WIDTH) ? s_axi_awsize : $clog2(STRB_WIDTH); + write_burst_next = s_axi_awburst; + + if (s_axi_awready & s_axi_awvalid) begin + s_axi_awready_next = write_addr_ready; + write_addr_valid_next = 1'b1; + s_axi_wready_next = 1'b1; + if (s_axi_awlen > 0) begin + write_state_next = WRITE_STATE_BURST; + end else begin + s_axi_bid_next = write_id_next; + s_axi_bresp_next = 2'b00; + s_axi_bvalid_next = 1'b1; + write_state_next = WRITE_STATE_IDLE; + end + end else begin + write_state_next = WRITE_STATE_IDLE; + end + end + WRITE_STATE_BURST: begin + s_axi_awready_next = 1'b0; + + if (write_addr_ready) begin + if (write_burst_reg != 2'b00) begin + write_addr_next = write_addr_reg + (1 << write_size_reg); + end + write_count_next = write_count_reg - 1; + write_addr_valid_next = 1'b1; + s_axi_wready_next = 1'b1; + if (write_count_next > 0) begin + write_state_next = WRITE_STATE_BURST; + end else begin + s_axi_bid_next = write_id_reg; + s_axi_bresp_next = 2'b00; + s_axi_bvalid_next = 1'b1; + write_state_next = WRITE_STATE_IDLE; + end + end else begin + write_state_next = WRITE_STATE_BURST; + end + end + endcase +end + +always @(posedge clk) begin + if (rst) begin + write_state_reg <= WRITE_STATE_IDLE; + write_addr_valid_reg <= 1'b0; + s_axi_awready_reg <= 1'b0; + s_axi_wready_reg <= 1'b0; + s_axi_bvalid_reg <= 1'b0; + end else begin + write_state_reg <= write_state_next; + write_addr_valid_reg <= write_addr_valid_next; + s_axi_awready_reg <= s_axi_awready_next; + s_axi_wready_reg <= s_axi_wready_next; + s_axi_bvalid_reg <= s_axi_bvalid_next; + end + + write_id_reg <= write_id_next; + write_addr_reg <= write_addr_next; + write_count_reg <= write_count_next; + write_size_reg <= write_size_next; + write_burst_reg <= write_burst_next; + + s_axi_bid_reg <= s_axi_bid_next; + s_axi_bresp_reg <= s_axi_bresp_next; + + for (i = 0; i < WORD_WIDTH; i = i + 1) begin + if (mem_wr_en & s_axi_wstrb[i]) begin + mem[write_addr_valid][8*i +: 8] <= s_axi_wdata[8*i +: 8]; + end + end +end + +always @* begin + read_state_next = READ_STATE_IDLE; + + mem_rd_en = 1'b0; + + read_addr_ready = s_axi_rready; + + s_axi_rid_next = s_axi_rid_reg; + s_axi_rresp_next = s_axi_rresp_reg; + s_axi_rlast_next = s_axi_rlast_reg; + s_axi_rvalid_next = s_axi_rvalid_reg & ~s_axi_rready; + + if (read_addr_valid_reg & (s_axi_rready || ~s_axi_rvalid)) begin + read_addr_ready = 1'b1; + mem_rd_en = 1'b1; + s_axi_rvalid_next = 1'b1; + s_axi_rid_next = read_id_reg; + s_axi_rlast_next = read_last_reg; + end + + read_id_next = read_id_reg; + read_addr_next = read_addr_reg; + read_addr_valid_next = read_addr_valid_reg & ~read_addr_ready; + read_last_next = read_last_reg; + read_count_next = read_count_reg; + read_size_next = read_size_reg; + read_burst_next = read_burst_reg; + + s_axi_arready_next = 1'b0; + + case (read_state_reg) + READ_STATE_IDLE: begin + s_axi_arready_next = (read_addr_ready || ~read_addr_valid_reg); + + read_id_next = s_axi_arid; + read_addr_next = s_axi_araddr; + read_count_next = s_axi_arlen; + read_size_next = s_axi_arsize < $clog2(STRB_WIDTH) ? s_axi_arsize : $clog2(STRB_WIDTH); + read_burst_next = s_axi_arburst; + + if (s_axi_arready & s_axi_arvalid) begin + s_axi_arready_next = read_addr_ready; + read_addr_valid_next = 1'b1; + if (s_axi_arlen > 0) begin + read_last_next = 1'b0; + read_state_next = READ_STATE_BURST; + end else begin + read_last_next = 1'b1; + read_state_next = READ_STATE_IDLE; + end + end else begin + read_state_next = READ_STATE_IDLE; + end + end + READ_STATE_BURST: begin + s_axi_arready_next = 1'b0; + + if (read_addr_ready) begin + if (read_burst_reg != 2'b00) begin + read_addr_next = read_addr_reg + (1 << read_size_reg); + end + read_count_next = read_count_reg - 1; + read_addr_valid_next = 1'b1; + if (read_count_next > 0) begin + read_last_next = 1'b0; + read_state_next = READ_STATE_BURST; + end else begin + read_last_next = 1'b1; + read_state_next = READ_STATE_IDLE; + end + end else begin + read_state_next = READ_STATE_BURST; + end + end + endcase +end + +always @(posedge clk) begin + if (rst) begin + read_state_reg <= READ_STATE_IDLE; + read_addr_valid_reg <= 1'b0; + s_axi_arready_reg <= 1'b0; + s_axi_rvalid_reg <= 1'b0; + end else begin + read_state_reg <= read_state_next; + read_addr_valid_reg <= read_addr_valid_next; + s_axi_arready_reg <= s_axi_arready_next; + s_axi_rvalid_reg <= s_axi_rvalid_next; + end + + read_id_reg <= read_id_next; + read_addr_reg <= read_addr_next; + read_last_reg <= read_last_next; + read_count_reg <= read_count_next; + read_size_reg <= read_size_next; + read_burst_reg <= read_burst_next; + + s_axi_rid_reg <= s_axi_rid_next; + s_axi_rresp_reg <= s_axi_rresp_next; + s_axi_rlast_reg <= s_axi_rlast_next; + + if (mem_rd_en) begin + s_axi_rdata_reg <= mem[read_addr_valid]; + end +end + +endmodule diff --git a/tb/axi.py b/tb/axi.py new file mode 100644 index 0000000..8b5ce85 --- /dev/null +++ b/tb/axi.py @@ -0,0 +1,783 @@ +""" + +Copyright (c) 2018 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +""" + +from myhdl import * +import math +import mmap + +BURST_FIXED = 0b00 +BURST_INCR = 0b01 +BURST_WRAP = 0b10 + +BURST_SIZE_1 = 0b000 +BURST_SIZE_2 = 0b001 +BURST_SIZE_4 = 0b010 +BURST_SIZE_8 = 0b011 +BURST_SIZE_16 = 0b100 +BURST_SIZE_32 = 0b101 +BURST_SIZE_64 = 0b110 +BURST_SIZE_128 = 0b111 + +LOCK_NORMAL = 0b0 +LOCK_EXCLUSIVE = 0b1 + +CACHE_B = 0b0001 +CACHE_M = 0b0010 +CACHE_RA = 0b0100 +CACHE_WA = 0b1000 + +ARCACHE_DEVICE_NON_BUFFERABLE = 0b0000 +ARCACHE_DEVICE_BUFFERABLE = 0b0001 +ARCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 0b0010 +ARCACHE_NORMAL_NON_CACHEABLE_BUFFERABLE = 0b0011 +ARCACHE_WRITE_THROUGH_NO_ALLOC = 0b1010 +ARCACHE_WRITE_THROUGH_READ_ALLOC = 0b1110 +ARCACHE_WRITE_THROUGH_WRITE_ALLOC = 0b1010 +ARCACHE_WRITE_THROUGH_READ_AND_WRITE_ALLOC = 0b1110 +ARCACHE_WRITE_BACK_NO_ALLOC = 0b1011 +ARCACHE_WRITE_BACK_READ_ALLOC = 0b1111 +ARCACHE_WRITE_BACK_WRITE_ALLOC = 0b1011 +ARCACHE_WRITE_BACK_READ_AND_WRIE_ALLOC = 0b1111 + +AWCACHE_DEVICE_NON_BUFFERABLE = 0b0000 +AWCACHE_DEVICE_BUFFERABLE = 0b0001 +AWCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE = 0b0010 +AWCACHE_NORMAL_NON_CACHEABLE_BUFFERABLE = 0b0011 +AWCACHE_WRITE_THROUGH_NO_ALLOC = 0b0110 +AWCACHE_WRITE_THROUGH_READ_ALLOC = 0b0110 +AWCACHE_WRITE_THROUGH_WRITE_ALLOC = 0b1110 +AWCACHE_WRITE_THROUGH_READ_AND_WRITE_ALLOC = 0b1110 +AWCACHE_WRITE_BACK_NO_ALLOC = 0b0111 +AWCACHE_WRITE_BACK_READ_ALLOC = 0b0111 +AWCACHE_WRITE_BACK_WRITE_ALLOC = 0b1111 +AWCACHE_WRITE_BACK_READ_AND_WRIE_ALLOC = 0b1111 + +class AXIMaster(object): + def __init__(self): + self.write_command_queue = [] + self.write_command_sync = Signal(False) + self.write_resp_queue = [] + self.write_resp_sync = Signal(False) + + self.read_command_queue = [] + self.read_command_sync = Signal(False) + self.read_data_queue = [] + self.read_data_sync = Signal(False) + + self.cur_write_id = 0 + self.cur_read_id = 0 + + self.int_write_addr_queue = [] + self.int_write_addr_sync = Signal(False) + self.int_write_data_queue = [] + self.int_write_data_sync = Signal(False) + self.int_write_resp_command_queue = [] + self.int_write_resp_command_sync = Signal(False) + self.int_write_resp_queue = [] + self.int_write_resp_sync = Signal(False) + + self.int_read_addr_queue = [] + self.int_read_addr_sync = Signal(False) + self.int_read_resp_command_queue = [] + self.int_read_resp_command_sync = Signal(False) + self.int_read_resp_queue = [] + self.int_read_resp_sync = Signal(False) + + self.in_flight_operations = 0 + + self.has_logic = False + self.clk = None + + def init_read(self, address, length, burst=0b01, size=None, lock=0b0, cache=0b0000, prot=0b010, qos=0b0000, region=0b0000, user=None): + self.read_command_queue.append((address, length, burst, size, lock, cache, prot, qos, region, user)) + self.read_command_sync.next = not self.read_command_sync + + def init_write(self, address, data, burst=0b01, size=None, lock=0b0, cache=0b0000, prot=0b010, qos=0b0000, region=0b0000, user=None): + self.write_command_queue.append((address, data, burst, size, lock, cache, prot, qos, region, user)) + self.write_command_sync.next = not self.write_command_sync + + def idle(self): + return not self.write_command_queue and not self.read_command_queue and not self.in_flight_operations + + def wait(self): + while not self.idle(): + yield self.clk.posedge + + def read_data_ready(self): + return bool(self.read_data_queue) + + def get_read_data(self): + if self.read_data_queue: + return self.read_data_queue.pop(0) + return None + + def create_logic(self, + clk, + rst, + m_axi_awid=None, + m_axi_awaddr=None, + m_axi_awlen=Signal(intbv(0)[8:]), + m_axi_awsize=Signal(intbv(0)[3:]), + m_axi_awburst=Signal(intbv(0)[2:]), + m_axi_awlock=Signal(intbv(0)[1:]), + m_axi_awcache=Signal(intbv(0)[4:]), + m_axi_awprot=Signal(intbv(0)[3:]), + m_axi_awqos=Signal(intbv(0)[4:]), + m_axi_awregion=Signal(intbv(0)[4:]), + m_axi_awuser=None, + m_axi_awvalid=Signal(bool(False)), + m_axi_awready=Signal(bool(True)), + m_axi_wdata=None, + m_axi_wstrb=Signal(intbv(1)[1:]), + m_axi_wlast=Signal(bool(True)), + m_axi_wuser=None, + m_axi_wvalid=Signal(bool(False)), + m_axi_wready=Signal(bool(True)), + m_axi_bid=None, + m_axi_bresp=Signal(intbv(0)[2:]), + m_axi_buser=None, + m_axi_bvalid=Signal(bool(False)), + m_axi_bready=Signal(bool(False)), + m_axi_arid=None, + m_axi_araddr=None, + m_axi_arlen=Signal(intbv(0)[8:]), + m_axi_arsize=Signal(intbv(0)[3:]), + m_axi_arburst=Signal(intbv(0)[2:]), + m_axi_arlock=Signal(intbv(0)[1:]), + m_axi_arcache=Signal(intbv(0)[4:]), + m_axi_arprot=Signal(intbv(0)[3:]), + m_axi_arqos=Signal(intbv(0)[4:]), + m_axi_arregion=Signal(intbv(0)[4:]), + m_axi_aruser=None, + m_axi_arvalid=Signal(bool(False)), + m_axi_arready=Signal(bool(True)), + m_axi_rid=None, + m_axi_rdata=None, + m_axi_rresp=Signal(intbv(0)[2:]), + m_axi_rlast=Signal(bool(True)), + m_axi_ruser=None, + m_axi_rvalid=Signal(bool(False)), + m_axi_rready=Signal(bool(False)), + name=None + ): + + if self.has_logic: + raise Exception("Logic already instantiated!") + + if m_axi_wdata is not None: + assert m_axi_awid is not None + assert m_axi_bid is not None + assert len(m_axi_awid) == len(m_axi_bid) + assert m_axi_awaddr is not None + assert len(m_axi_wdata) % 8 == 0 + assert len(m_axi_wdata) / 8 == len(m_axi_wstrb) + w = len(m_axi_wdata) + + if m_axi_rdata is not None: + assert m_axi_arid is not None + assert m_axi_rid is not None + assert len(m_axi_arid) == len(m_axi_rid) + assert m_axi_araddr is not None + assert len(m_axi_rdata) % 8 == 0 + w = len(m_axi_rdata) + + if m_axi_wdata is not None: + assert len(m_axi_wdata) == len(m_axi_rdata) + assert len(m_axi_awid) == len(m_axi_arid) + assert len(m_axi_awaddr) == len(m_axi_araddr) + + bw = int(w/8) + + assert bw in (1, 2, 4, 8, 16, 32, 64, 128) + + self.has_logic = True + self.clk = clk + + @instance + def write_logic(): + while True: + if not self.write_command_queue: + yield self.write_command_sync + + addr, data, burst, size, lock, cache, prot, qos, region, user = self.write_command_queue.pop(0) + self.in_flight_operations += 1 + + num_bytes = bw + + if size is None: + size = int(math.log(bw, 2)) + else: + num_bytes = 2**size + assert 0 < num_bytes <= bw + + aligned_addr = int(addr/num_bytes)*num_bytes + word_addr = int(addr/bw)*bw + + start_offset = addr % bw + end_offset = ((addr + len(data) - 1) % bw) + 1 + + cycles = int((len(data) + num_bytes-1 + (addr % num_bytes)) / num_bytes) + + cur_addr = aligned_addr + offset = 0 + cycle_offset = aligned_addr-word_addr + n = 0 + transfer_count = 0 + + burst_length = 0 + + if name is not None: + print("[%s] Write data addr: 0x%08x prot: 0x%x data: %s" % (name, addr, prot, " ".join(("{:02x}".format(c) for c in bytearray(data))))) + + for k in range(cycles): + start = cycle_offset + stop = cycle_offset+num_bytes + + if k == 0: + start = start_offset + if k == cycles-1: + stop = end_offset + + strb = ((2**bw-1) << start) & (2**bw-1) & (2**bw-1) >> (bw - stop) + + val = 0 + for j in range(start, stop): + val |= bytearray(data)[offset] << j*8 + offset += 1 + + if n >= burst_length: + transfer_count += 1 + n = 0 + burst_length = min(cycles-k, 256) # max len + burst_length = min(burst_length, 0x1000-(cur_addr&0xfff)) # 4k align + awid = self.cur_write_id + self.cur_write_id = (self.cur_write_id + 1) % 2**len(m_axi_awid) + self.int_write_addr_queue.append((cur_addr, awid, burst_length-1, size, burst, lock, cache, prot, qos, region, user)) + self.int_write_addr_sync.next = not self.int_write_addr_sync + n += 1 + self.int_write_data_queue.append((val, strb, n >= burst_length)) + self.int_write_data_sync.next = not self.int_write_data_sync + + cur_addr += num_bytes + cycle_offset = (cycle_offset + num_bytes) % bw + + self.int_write_resp_command_queue.append((addr, len(data), transfer_count, prot)) + self.int_write_resp_command_sync.next = not self.int_write_resp_command_sync + + @instance + def write_resp_logic(): + while True: + if not self.int_write_resp_command_queue: + yield self.int_write_resp_command_sync + + addr, length, transfer_count, prot = self.int_write_resp_command_queue.pop(0) + + resp = 0 + + for k in range(transfer_count): + while not self.int_write_resp_queue: + yield clk.posedge + + cycle_resp = self.int_write_resp_queue.pop(0) + + if cycle_resp != 0: + resp = cycle_resp + + self.write_resp_queue.append((addr, length, prot, resp)) + self.write_resp_sync.next = not self.write_resp_sync + self.in_flight_operations -= 1 + + @instance + def write_addr_interface_logic(): + while True: + while not self.int_write_addr_queue: + yield clk.posedge + + addr, awid, length, size, burst, lock, cache, prot, qos, region, user = self.int_write_addr_queue.pop(0) + m_axi_awaddr.next = addr + m_axi_awid.next = awid + m_axi_awlen.next = length + m_axi_awsize.next = size + m_axi_awburst.next = burst + m_axi_awlock.next = lock + m_axi_awcache.next = cache + m_axi_awprot.next = prot + m_axi_awqos.next = qos + m_axi_awregion.next = region + if m_axi_awuser is not None: + m_axi_awuser.next = user + m_axi_awvalid.next = True + + yield clk.posedge + + while m_axi_awvalid and not m_axi_awready: + yield clk.posedge + + m_axi_awvalid.next = False + + @instance + def write_data_interface_logic(): + while True: + while not self.int_write_data_queue: + yield clk.posedge + + m_axi_wdata.next, m_axi_wstrb.next, m_axi_wlast.next = self.int_write_data_queue.pop(0) + m_axi_wvalid.next = True + + yield clk.posedge + + while m_axi_wvalid and not m_axi_wready: + yield clk.posedge + + m_axi_wvalid.next = False + + @instance + def write_resp_interface_logic(): + while True: + m_axi_bready.next = True + + yield clk.posedge + + if m_axi_bready & m_axi_bvalid: + self.int_write_resp_queue.append(int(m_axi_bresp)) + self.int_write_resp_sync.next = not self.int_write_resp_sync + + @instance + def read_logic(): + while True: + if not self.read_command_queue: + yield self.read_command_sync + + addr, length, burst, size, lock, cache, prot, qos, region, user = self.read_command_queue.pop(0) + self.in_flight_operations += 1 + + num_bytes = bw + + if size is None: + size = int(math.log(bw, 2)) + else: + num_bytes = 2**size + assert 0 < num_bytes <= bw + + aligned_addr = int(addr/num_bytes)*num_bytes + word_addr = int(addr/bw)*bw + + cycles = int((length + num_bytes-1 + (addr % num_bytes)) / num_bytes) + + self.int_read_resp_command_queue.append((addr, length, size, cycles, prot)) + self.int_read_resp_command_sync.next = not self.int_read_resp_command_sync + + cur_addr = aligned_addr + n = 0 + + burst_length = 0 + + for k in range(cycles): + + n += 1 + if n >= burst_length: + n = 0 + burst_length = min(cycles-k, 256) # max len + burst_length = min(burst_length, 0x1000-((aligned_addr+k*num_bytes)&0xfff))# 4k align + arid = self.cur_read_id + self.cur_read_id = (self.cur_read_id + 1) % 2**len(m_axi_arid) + self.int_read_addr_queue.append((cur_addr, arid, burst_length-1, size, burst, lock, cache, prot, qos, region, user)) + self.int_read_addr_sync.next = not self.int_read_addr_sync + + cur_addr += num_bytes + + @instance + def read_resp_logic(): + while True: + if not self.int_read_resp_command_queue: + yield self.int_read_resp_command_sync + + addr, length, size, cycles, prot = self.int_read_resp_command_queue.pop(0) + + num_bytes = 2**size + assert 0 <= size <= int(math.log(bw, 2)) + + aligned_addr = int(addr/num_bytes)*num_bytes + word_addr = int(addr/bw)*bw + + start_offset = addr % bw + end_offset = ((addr + length - 1) % bw) + 1 + + cycle_offset = aligned_addr-word_addr + data = b'' + + resp = 0 + + for k in range(cycles): + if not self.int_read_resp_queue: + yield self.int_read_resp_sync + + cycle_data, cycle_resp, cycle_last = self.int_read_resp_queue.pop(0) + + if cycle_resp != 0: + resp = cycle_resp + + start = cycle_offset + stop = cycle_offset+num_bytes + + if k == 0: + start = start_offset + if k == cycles-1: + stop = end_offset + + assert cycle_last == (k == cycles - 1) + + for j in range(start, stop): + data += bytearray([(cycle_data >> j*8) & 0xff]) + + cycle_offset = (cycle_offset + num_bytes) % bw + + if name is not None: + print("[%s] Read data addr: 0x%08x prot: 0x%x data: %s" % (name, addr, prot, " ".join(("{:02x}".format(c) for c in bytearray(data))))) + + self.read_data_queue.append((addr, data, prot, resp)) + self.read_data_sync.next = not self.read_data_sync + self.in_flight_operations -= 1 + + @instance + def read_addr_interface_logic(): + while True: + while not self.int_read_addr_queue: + yield clk.posedge + + addr, arid, length, size, burst, lock, cache, prot, qos, region, user = self.int_read_addr_queue.pop(0) + m_axi_araddr.next = addr + m_axi_arid.next = arid + m_axi_arlen.next = length + m_axi_arsize.next = size + m_axi_arburst.next = burst + m_axi_arlock.next = lock + m_axi_arcache.next = cache + m_axi_arprot.next = prot + m_axi_arqos.next = qos + m_axi_arregion.next = region + if m_axi_aruser is not None: + m_axi_aruser.next = user + m_axi_arvalid.next = True + + yield clk.posedge + + while m_axi_arvalid and not m_axi_arready: + yield clk.posedge + + m_axi_arvalid.next = False + + @instance + def read_resp_interface_logic(): + while True: + m_axi_rready.next = True + + yield clk.posedge + + if m_axi_rready & m_axi_rvalid: + self.int_read_resp_queue.append((int(m_axi_rdata), int(m_axi_rresp), int(m_axi_rlast))) + self.int_read_resp_sync.next = not self.int_read_resp_sync + + return instances() + + +class AXIRam(object): + def __init__(self, size = 1024): + self.size = size + self.mem = mmap.mmap(-1, size) + + self.int_write_addr_queue = [] + self.int_write_addr_sync = Signal(False) + self.int_write_data_queue = [] + self.int_write_data_sync = Signal(False) + self.int_write_resp_queue = [] + self.int_write_resp_sync = Signal(False) + + self.int_read_addr_queue = [] + self.int_read_addr_sync = Signal(False) + self.int_read_resp_queue = [] + self.int_read_resp_sync = Signal(False) + + def read_mem(self, address, length): + self.mem.seek(address % self.size) + return self.mem.read(length) + + def write_mem(self, address, data): + self.mem.seek(address % self.size) + self.mem.write(data) + + def create_port(self, + clk, + s_axi_awid=None, + s_axi_awaddr=None, + s_axi_awlen=Signal(intbv(0)[8:]), + s_axi_awsize=Signal(intbv(0)[3:]), + s_axi_awburst=Signal(intbv(0)[2:]), + s_axi_awlock=Signal(intbv(0)[1:]), + s_axi_awcache=Signal(intbv(0)[4:]), + s_axi_awprot=Signal(intbv(0)[3:]), + s_axi_awvalid=Signal(bool(False)), + s_axi_awready=Signal(bool(True)), + s_axi_wdata=None, + s_axi_wstrb=Signal(intbv(1)[1:]), + s_axi_wlast=Signal(bool(True)), + s_axi_wvalid=Signal(bool(False)), + s_axi_wready=Signal(bool(True)), + s_axi_bid=None, + s_axi_bresp=Signal(intbv(0)[2:]), + s_axi_bvalid=Signal(bool(False)), + s_axi_bready=Signal(bool(False)), + s_axi_arid=None, + s_axi_araddr=None, + s_axi_arlen=Signal(intbv(0)[8:]), + s_axi_arsize=Signal(intbv(0)[3:]), + s_axi_arburst=Signal(intbv(0)[2:]), + s_axi_arlock=Signal(intbv(0)[1:]), + s_axi_arcache=Signal(intbv(0)[4:]), + s_axi_arprot=Signal(intbv(0)[3:]), + s_axi_arvalid=Signal(bool(False)), + s_axi_arready=Signal(bool(True)), + s_axi_rid=None, + s_axi_rdata=None, + s_axi_rresp=Signal(intbv(0)[2:]), + s_axi_rlast=Signal(bool(True)), + s_axi_rvalid=Signal(bool(False)), + s_axi_rready=Signal(bool(False)), + name=None + ): + + if s_axi_wdata is not None: + assert s_axi_awid is not None + assert s_axi_bid is not None + assert len(s_axi_awid) == len(s_axi_bid) + assert s_axi_awaddr is not None + assert len(s_axi_wdata) % 8 == 0 + assert len(s_axi_wdata) / 8 == len(s_axi_wstrb) + w = len(s_axi_wdata) + + if s_axi_rdata is not None: + assert s_axi_arid is not None + assert s_axi_rid is not None + assert len(s_axi_arid) == len(s_axi_rid) + assert s_axi_araddr is not None + assert len(s_axi_rdata) % 8 == 0 + w = len(s_axi_rdata) + + if s_axi_wdata is not None: + assert len(s_axi_wdata) == len(s_axi_rdata) + assert len(s_axi_awid) == len(s_axi_arid) + assert len(s_axi_awaddr) == len(s_axi_araddr) + + bw = int(w/8) + + assert bw in (1, 2, 4, 8, 16, 32, 64, 128) + + @instance + def write_logic(): + while True: + if not self.int_write_addr_queue: + yield self.int_write_addr_sync + + addr, awid, length, size, burst, lock, cache, prot = self.int_write_addr_queue.pop(0) + + num_bytes = 2**size + assert 0 < num_bytes <= bw + + aligned_addr = int(addr/num_bytes)*num_bytes + length = length+1 + + transfer_size = num_bytes*length + + if burst == BURST_WRAP: + lower_wrap_boundary = int(addr/transfer_size)*transfer_size + upper_wrap_boundary = lower_wrap_boundary+transfer_size + + if burst == BURST_INCR: + # check for 4k boundary crossing + assert 0x1000-(addr&0xfff) >= transfer_size + + cur_addr = aligned_addr + + for n in range(length): + cur_word_addr = int(cur_addr/bw)*bw + + self.mem.seek(cur_word_addr % self.size) + + if not self.int_write_data_queue: + yield self.int_write_data_sync + + wdata, strb, last = self.int_write_data_queue.pop(0) + + data = bytearray() + for i in range(bw): + data.extend(bytearray([wdata & 0xff])) + wdata >>= 8 + for i in range(bw): + if strb & (1 << i): + self.mem.write(data[i:i+1]) + else: + self.mem.seek(1, 1) + if n == length-1: + self.int_write_resp_queue.append((awid, 0b00)) + self.int_write_resp_sync.next = not self.int_write_resp_sync + assert last == (n == length-1) + if name is not None: + print("[%s] Write word id: %d addr: 0x%08x prot: 0x%x wstrb: 0x%02x data: %s" % (name, awid, cur_addr, prot, s_axi_wstrb, " ".join(("{:02x}".format(c) for c in bytearray(data))))) + + if burst != BURST_FIXED: + cur_addr += num_bytes + + if burst == BURST_WRAP: + if cur_addr == upper_wrap_boundary: + cur_addr = lower_wrap_boundary + + @instance + def write_addr_interface_logic(): + while True: + s_axi_awready.next = True + + yield clk.posedge + + if s_axi_awready & s_axi_awvalid: + addr = int(s_axi_awaddr) + awid = int(s_axi_awid) + length = int(s_axi_awlen) + size = int(s_axi_awsize) + burst = int(s_axi_awburst) + lock = int(s_axi_awlock) + cache = int(s_axi_awcache) + prot = int(s_axi_awprot) + self.int_write_addr_queue.append((addr, awid, length, size, burst, lock, cache, prot)) + self.int_write_addr_sync.next = not self.int_write_addr_sync + + @instance + def write_data_interface_logic(): + while True: + s_axi_wready.next = True + + yield clk.posedge + + if s_axi_wready & s_axi_wvalid: + data = int(s_axi_wdata) + strb = int(s_axi_wstrb) + last = bool(s_axi_wlast) + self.int_write_data_queue.append((data, strb, last)) + self.int_write_data_sync.next = not self.int_write_data_sync + + @instance + def write_resp_interface_logic(): + while True: + while not self.int_write_resp_queue: + yield clk.posedge + + s_axi_bid.next, s_axi_bresp.next = self.int_write_resp_queue.pop(0) + s_axi_bvalid.next = True + + yield clk.posedge + + while s_axi_bvalid and not s_axi_bready: + yield clk.posedge + + s_axi_bvalid.next = False + + @instance + def read_logic(): + while True: + if not self.int_read_addr_queue: + yield self.int_read_addr_sync + + addr, arid, length, size, burst, lock, cache, prot = self.int_read_addr_queue.pop(0) + + num_bytes = 2**size + assert 0 < num_bytes <= bw + + aligned_addr = int(addr/num_bytes)*num_bytes + length = length+1 + + if burst == BURST_WRAP: + transfer_size = num_bytes*length + lower_wrap_boundary = int(addr/transfer_size)*transfer_size + upper_wrap_boundary = lower_wrap_boundary+transfer_size + + cur_addr = aligned_addr + + for n in range(length): + cur_word_addr = int(cur_addr/bw)*bw + + self.mem.seek(cur_word_addr % self.size) + + data = bytearray(self.mem.read(bw)) + val = 0 + for i in range(bw-1,-1,-1): + val <<= 8 + val += data[i] + self.int_read_resp_queue.append((arid, val, 0x00, n == length-1)) + self.int_read_resp_sync.next = not self.int_read_resp_sync + if name is not None: + print("[%s] Read word id: %d addr: 0x%08x prot: 0x%x data: %s" % (name, arid, cur_addr, prot, " ".join(("{:02x}".format(c) for c in bytearray(data))))) + + if burst != BURST_FIXED: + cur_addr += num_bytes + + if burst == BURST_WRAP: + if cur_addr == upper_wrap_boundary: + cur_addr = lower_wrap_boundary + + @instance + def read_addr_interface_logic(): + while True: + s_axi_arready.next = True + + yield clk.posedge + + if s_axi_arready & s_axi_arvalid: + addr = int(s_axi_araddr) + arid = int(s_axi_arid) + length = int(s_axi_arlen) + size = int(s_axi_arsize) + burst = int(s_axi_arburst) + lock = int(s_axi_arlock) + cache = int(s_axi_arcache) + prot = int(s_axi_arprot) + self.int_read_addr_queue.append((addr, arid, length, size, burst, lock, cache, prot)) + self.int_read_addr_sync.next = not self.int_read_addr_sync + + @instance + def read_resp_interface_logic(): + while True: + while not self.int_read_resp_queue: + yield clk.posedge + + s_axi_rid.next, s_axi_rdata.next, s_axi_rresp.next, s_axi_rlast.next = self.int_read_resp_queue.pop(0) + s_axi_rvalid.next = True + + yield clk.posedge + + while s_axi_rvalid and not s_axi_rready: + yield clk.posedge + + s_axi_rvalid.next = False + + return instances() + diff --git a/tb/test_axi.py b/tb/test_axi.py new file mode 100755 index 0000000..2aed608 --- /dev/null +++ b/tb/test_axi.py @@ -0,0 +1,293 @@ +#!/usr/bin/env python +""" + +Copyright (c) 2015 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +""" + +from myhdl import * +import os + +import axi + +def bench(): + + # Inputs + clk = Signal(bool(0)) + rst = Signal(bool(0)) + current_test = Signal(intbv(0)[8:]) + + port0_axi_awid = Signal(intbv(0)[8:]) + port0_axi_awaddr = Signal(intbv(0)[32:]) + port0_axi_awlen = Signal(intbv(0)[8:]) + port0_axi_awsize = Signal(intbv(0)[3:]) + port0_axi_awburst = Signal(intbv(0)[2:]) + port0_axi_awlock = Signal(intbv(0)[1:]) + port0_axi_awcache = Signal(intbv(0)[4:]) + port0_axi_awprot = Signal(intbv(0)[3:]) + port0_axi_awqos = Signal(intbv(0)[4:]) + port0_axi_awregion = Signal(intbv(0)[4:]) + port0_axi_awvalid = Signal(bool(False)) + port0_axi_wdata = Signal(intbv(0)[32:]) + port0_axi_wstrb = Signal(intbv(0)[4:]) + port0_axi_wlast = Signal(bool(False)) + port0_axi_wvalid = Signal(bool(False)) + port0_axi_bready = Signal(bool(False)) + port0_axi_arid = Signal(intbv(0)[8:]) + port0_axi_araddr = Signal(intbv(0)[32:]) + port0_axi_arlen = Signal(intbv(0)[8:]) + port0_axi_arsize = Signal(intbv(0)[3:]) + port0_axi_arburst = Signal(intbv(0)[2:]) + port0_axi_arlock = Signal(intbv(0)[1:]) + port0_axi_arcache = Signal(intbv(0)[4:]) + port0_axi_arprot = Signal(intbv(0)[3:]) + port0_axi_arqos = Signal(intbv(0)[4:]) + port0_axi_arregion = Signal(intbv(0)[4:]) + port0_axi_arvalid = Signal(bool(False)) + port0_axi_rready = Signal(bool(False)) + + # Outputs + port0_axi_awready = Signal(bool(False)) + port0_axi_wready = Signal(bool(False)) + port0_axi_bid = Signal(intbv(0)[8:]) + port0_axi_bresp = Signal(intbv(0)[2:]) + port0_axi_bvalid = Signal(bool(False)) + port0_axi_arready = Signal(bool(False)) + port0_axi_rid = Signal(intbv(0)[8:]) + port0_axi_rdata = Signal(intbv(0)[32:]) + port0_axi_rresp = Signal(intbv(0)[2:]) + port0_axi_rlast = Signal(bool(False)) + port0_axi_rvalid = Signal(bool(False)) + + # AXI4 master + axi_master_inst = axi.AXIMaster() + + axi_master_logic = axi_master_inst.create_logic( + clk, + rst, + m_axi_awid=port0_axi_awid, + m_axi_awaddr=port0_axi_awaddr, + m_axi_awlen=port0_axi_awlen, + m_axi_awsize=port0_axi_awsize, + m_axi_awburst=port0_axi_awburst, + m_axi_awlock=port0_axi_awlock, + m_axi_awcache=port0_axi_awcache, + m_axi_awprot=port0_axi_awprot, + m_axi_awqos=port0_axi_awqos, + m_axi_awregion=port0_axi_awregion, + m_axi_awvalid=port0_axi_awvalid, + m_axi_awready=port0_axi_awready, + m_axi_wdata=port0_axi_wdata, + m_axi_wstrb=port0_axi_wstrb, + m_axi_wlast=port0_axi_wlast, + m_axi_wvalid=port0_axi_wvalid, + m_axi_wready=port0_axi_wready, + m_axi_bid=port0_axi_bid, + m_axi_bresp=port0_axi_bresp, + m_axi_bvalid=port0_axi_bvalid, + m_axi_bready=port0_axi_bready, + m_axi_arid=port0_axi_arid, + m_axi_araddr=port0_axi_araddr, + m_axi_arlen=port0_axi_arlen, + m_axi_arsize=port0_axi_arsize, + m_axi_arburst=port0_axi_arburst, + m_axi_arlock=port0_axi_arlock, + m_axi_arcache=port0_axi_arcache, + m_axi_arprot=port0_axi_arprot, + m_axi_arqos=port0_axi_arqos, + m_axi_arregion=port0_axi_arregion, + m_axi_arvalid=port0_axi_arvalid, + m_axi_arready=port0_axi_arready, + m_axi_rid=port0_axi_rid, + m_axi_rdata=port0_axi_rdata, + m_axi_rresp=port0_axi_rresp, + m_axi_rlast=port0_axi_rlast, + m_axi_rvalid=port0_axi_rvalid, + m_axi_rready=port0_axi_rready, + name='master' + ) + + # AXI4 RAM model + axi_ram_inst = axi.AXIRam(2**16) + + axi_ram_port0 = axi_ram_inst.create_port( + clk, + s_axi_awid=port0_axi_awid, + s_axi_awaddr=port0_axi_awaddr, + s_axi_awlen=port0_axi_awlen, + s_axi_awsize=port0_axi_awsize, + s_axi_awburst=port0_axi_awburst, + s_axi_awlock=port0_axi_awlock, + s_axi_awcache=port0_axi_awcache, + s_axi_awprot=port0_axi_awprot, + s_axi_awvalid=port0_axi_awvalid, + s_axi_awready=port0_axi_awready, + s_axi_wdata=port0_axi_wdata, + s_axi_wstrb=port0_axi_wstrb, + s_axi_wlast=port0_axi_wlast, + s_axi_wvalid=port0_axi_wvalid, + s_axi_wready=port0_axi_wready, + s_axi_bid=port0_axi_bid, + s_axi_bresp=port0_axi_bresp, + s_axi_bvalid=port0_axi_bvalid, + s_axi_bready=port0_axi_bready, + s_axi_arid=port0_axi_arid, + s_axi_araddr=port0_axi_araddr, + s_axi_arlen=port0_axi_arlen, + s_axi_arsize=port0_axi_arsize, + s_axi_arburst=port0_axi_arburst, + s_axi_arlock=port0_axi_arlock, + s_axi_arcache=port0_axi_arcache, + s_axi_arprot=port0_axi_arprot, + s_axi_arvalid=port0_axi_arvalid, + s_axi_arready=port0_axi_arready, + s_axi_rid=port0_axi_rid, + s_axi_rdata=port0_axi_rdata, + s_axi_rresp=port0_axi_rresp, + s_axi_rlast=port0_axi_rlast, + s_axi_rvalid=port0_axi_rvalid, + s_axi_rready=port0_axi_rready, + name='port0' + ) + + @always(delay(4)) + def clkgen(): + clk.next = not clk + + @instance + def check(): + yield delay(100) + yield clk.posedge + rst.next = 1 + yield clk.posedge + rst.next = 0 + yield clk.posedge + yield delay(100) + yield clk.posedge + + yield clk.posedge + print("test 1: baseline") + current_test.next = 1 + + data = axi_ram_inst.read_mem(0, 32) + for i in range(0, len(data), 16): + print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16])))) + + yield delay(100) + + yield clk.posedge + print("test 2: direct write") + current_test.next = 2 + + axi_ram_inst.write_mem(0, b'test') + + data = axi_ram_inst.read_mem(0, 32) + for i in range(0, len(data), 16): + print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16])))) + + assert axi_ram_inst.read_mem(0,4) == b'test' + + yield clk.posedge + print("test 3: write via port0") + current_test.next = 3 + + axi_master_inst.init_write(4, b'\x11\x22\x33\x44') + + yield axi_master_inst.wait() + yield clk.posedge + + data = axi_ram_inst.read_mem(0, 32) + for i in range(0, len(data), 16): + print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16])))) + + assert axi_ram_inst.read_mem(4,4) == b'\x11\x22\x33\x44' + + yield delay(100) + + yield clk.posedge + print("test 4: read via port0") + current_test.next = 4 + + axi_master_inst.init_read(4, 4) + + yield axi_master_inst.wait() + yield clk.posedge + + data = axi_master_inst.get_read_data() + assert data[0] == 4 + assert data[1] == b'\x11\x22\x33\x44' + + yield delay(100) + + yield clk.posedge + print("test 5: various writes") + current_test.next = 5 + + for length in range(1,8): + for offset in range(4,8): + for size in (2, 1, 0): + axi_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*32) + axi_master_inst.init_write(256*(16*offset+length)+offset, b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length], size=size) + + yield axi_master_inst.wait() + yield clk.posedge + + data = axi_ram_inst.read_mem(256*(16*offset+length), 32) + for i in range(0, len(data), 16): + print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16])))) + + assert axi_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length] + assert axi_ram_inst.read_mem(256*(16*offset+length)+offset-1, 1) == b'\xAA' + assert axi_ram_inst.read_mem(256*(16*offset+length)+offset+length, 1) == b'\xAA' + + yield delay(100) + + yield clk.posedge + print("test 6: various reads") + current_test.next = 6 + + for length in range(1,8): + for offset in range(4,8): + for size in (2, 1, 0): + axi_master_inst.init_read(256*(16*offset+length)+offset, length, size=size) + + yield axi_master_inst.wait() + yield clk.posedge + + data = axi_master_inst.get_read_data() + assert data[0] == 256*(16*offset+length)+offset + assert data[1] == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length] + + yield delay(100) + + raise StopSimulation + + return instances() + +def test_bench(): + os.chdir(os.path.dirname(os.path.abspath(__file__))) + sim = Simulation(bench()) + sim.run() + +if __name__ == '__main__': + print("Running test...") + test_bench() + diff --git a/tb/test_axi_ram.py b/tb/test_axi_ram.py new file mode 100755 index 0000000..8b70561 --- /dev/null +++ b/tb/test_axi_ram.py @@ -0,0 +1,257 @@ +#!/usr/bin/env python +""" + +Copyright (c) 2018 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +""" + +from myhdl import * +import os + +import axi + +module = 'axi_ram' +testbench = 'test_%s' % module + +srcs = [] + +srcs.append("../rtl/%s.v" % module) +srcs.append("%s.v" % testbench) + +src = ' '.join(srcs) + +build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) + +def bench(): + + # Parameters + DATA_WIDTH = 32 + ADDR_WIDTH = 16 + STRB_WIDTH = (DATA_WIDTH/8) + ID_WIDTH = 8 + + # Inputs + clk = Signal(bool(0)) + rst = Signal(bool(0)) + current_test = Signal(intbv(0)[8:]) + + s_axi_awid = Signal(intbv(0)[ID_WIDTH:]) + s_axi_awaddr = Signal(intbv(0)[ADDR_WIDTH:]) + s_axi_awlen = Signal(intbv(0)[8:]) + s_axi_awsize = Signal(intbv(0)[3:]) + s_axi_awburst = Signal(intbv(0)[2:]) + s_axi_awlock = Signal(bool(0)) + s_axi_awcache = Signal(intbv(0)[4:]) + s_axi_awprot = Signal(intbv(0)[3:]) + s_axi_awvalid = Signal(bool(0)) + s_axi_wdata = Signal(intbv(0)[DATA_WIDTH:]) + s_axi_wstrb = Signal(intbv(0)[STRB_WIDTH:]) + s_axi_wlast = Signal(bool(0)) + s_axi_wvalid = Signal(bool(0)) + s_axi_bready = Signal(bool(0)) + s_axi_arid = Signal(intbv(0)[ID_WIDTH:]) + s_axi_araddr = Signal(intbv(0)[ADDR_WIDTH:]) + s_axi_arlen = Signal(intbv(0)[8:]) + s_axi_arsize = Signal(intbv(0)[3:]) + s_axi_arburst = Signal(intbv(0)[2:]) + s_axi_arlock = Signal(bool(0)) + s_axi_arcache = Signal(intbv(0)[4:]) + s_axi_arprot = Signal(intbv(0)[3:]) + s_axi_arvalid = Signal(bool(0)) + s_axi_rready = Signal(bool(0)) + + # Outputs + s_axi_awready = Signal(bool(0)) + s_axi_wready = Signal(bool(0)) + s_axi_bid = Signal(intbv(0)[ID_WIDTH:]) + s_axi_bresp = Signal(intbv(0)[2:]) + s_axi_bvalid = Signal(bool(0)) + s_axi_arready = Signal(bool(0)) + s_axi_rid = Signal(intbv(0)[ID_WIDTH:]) + s_axi_rdata = Signal(intbv(0)[DATA_WIDTH:]) + s_axi_rresp = Signal(intbv(0)[2:]) + s_axi_rlast = Signal(bool(0)) + s_axi_rvalid = Signal(bool(0)) + + # AXI4 master + axi_master_inst = axi.AXIMaster() + + axi_master_logic = axi_master_inst.create_logic( + clk, + rst, + m_axi_awid=s_axi_awid, + m_axi_awaddr=s_axi_awaddr, + m_axi_awlen=s_axi_awlen, + m_axi_awsize=s_axi_awsize, + m_axi_awburst=s_axi_awburst, + m_axi_awlock=s_axi_awlock, + m_axi_awcache=s_axi_awcache, + m_axi_awprot=s_axi_awprot, + m_axi_awvalid=s_axi_awvalid, + m_axi_awready=s_axi_awready, + m_axi_wdata=s_axi_wdata, + m_axi_wstrb=s_axi_wstrb, + m_axi_wlast=s_axi_wlast, + m_axi_wvalid=s_axi_wvalid, + m_axi_wready=s_axi_wready, + m_axi_bid=s_axi_bid, + m_axi_bresp=s_axi_bresp, + m_axi_bvalid=s_axi_bvalid, + m_axi_bready=s_axi_bready, + m_axi_arid=s_axi_arid, + m_axi_araddr=s_axi_araddr, + m_axi_arlen=s_axi_arlen, + m_axi_arsize=s_axi_arsize, + m_axi_arburst=s_axi_arburst, + m_axi_arlock=s_axi_arlock, + m_axi_arcache=s_axi_arcache, + m_axi_arprot=s_axi_arprot, + m_axi_arvalid=s_axi_arvalid, + m_axi_arready=s_axi_arready, + m_axi_rid=s_axi_rid, + m_axi_rdata=s_axi_rdata, + m_axi_rresp=s_axi_rresp, + m_axi_rlast=s_axi_rlast, + m_axi_rvalid=s_axi_rvalid, + m_axi_rready=s_axi_rready, + name='master' + ) + + # DUT + if os.system(build_cmd): + raise Exception("Error running build command") + + dut = Cosimulation( + "vvp -m myhdl %s.vvp -lxt2" % testbench, + clk=clk, + rst=rst, + current_test=current_test, + s_axi_awid=s_axi_awid, + s_axi_awaddr=s_axi_awaddr, + s_axi_awlen=s_axi_awlen, + s_axi_awsize=s_axi_awsize, + s_axi_awburst=s_axi_awburst, + s_axi_awlock=s_axi_awlock, + s_axi_awcache=s_axi_awcache, + s_axi_awprot=s_axi_awprot, + s_axi_awvalid=s_axi_awvalid, + s_axi_awready=s_axi_awready, + s_axi_wdata=s_axi_wdata, + s_axi_wstrb=s_axi_wstrb, + s_axi_wlast=s_axi_wlast, + s_axi_wvalid=s_axi_wvalid, + s_axi_wready=s_axi_wready, + s_axi_bid=s_axi_bid, + s_axi_bresp=s_axi_bresp, + s_axi_bvalid=s_axi_bvalid, + s_axi_bready=s_axi_bready, + s_axi_arid=s_axi_arid, + s_axi_araddr=s_axi_araddr, + s_axi_arlen=s_axi_arlen, + s_axi_arsize=s_axi_arsize, + s_axi_arburst=s_axi_arburst, + s_axi_arlock=s_axi_arlock, + s_axi_arcache=s_axi_arcache, + s_axi_arprot=s_axi_arprot, + s_axi_arvalid=s_axi_arvalid, + s_axi_arready=s_axi_arready, + s_axi_rid=s_axi_rid, + s_axi_rdata=s_axi_rdata, + s_axi_rresp=s_axi_rresp, + s_axi_rlast=s_axi_rlast, + s_axi_rvalid=s_axi_rvalid, + s_axi_rready=s_axi_rready + ) + + @always(delay(4)) + def clkgen(): + clk.next = not clk + + @instance + def check(): + yield delay(100) + yield clk.posedge + rst.next = 1 + yield clk.posedge + rst.next = 0 + yield clk.posedge + yield delay(100) + yield clk.posedge + + # testbench stimulus + + yield clk.posedge + print("test 1: read and write") + current_test.next = 1 + + axi_master_inst.init_write(4, b'\x11\x22\x33\x44') + + yield axi_master_inst.wait() + yield clk.posedge + + axi_master_inst.init_read(4, 4) + + yield axi_master_inst.wait() + yield clk.posedge + + data = axi_master_inst.get_read_data() + assert data[0] == 4 + assert data[1] == b'\x11\x22\x33\x44' + + yield delay(100) + + yield clk.posedge + print("test 2: various reads and writes") + current_test.next = 2 + + for length in range(1,8): + for offset in range(4): + for size in (2, 1, 0): + axi_master_inst.init_write(256*(16*offset+length)+offset, b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length], size=size) + + yield axi_master_inst.wait() + yield clk.posedge + + for length in range(1,8): + for offset in range(4): + for size in (2, 1, 0): + axi_master_inst.init_read(256*(16*offset+length)+offset, length, size=size) + + yield axi_master_inst.wait() + yield clk.posedge + + data = axi_master_inst.get_read_data() + assert data[0] == 256*(16*offset+length)+offset + assert data[1] == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length] + + yield delay(100) + + raise StopSimulation + + return instances() + +def test_bench(): + sim = Simulation(bench()) + sim.run() + +if __name__ == '__main__': + print("Running test...") + test_bench() diff --git a/tb/test_axi_ram.v b/tb/test_axi_ram.v new file mode 100644 index 0000000..5741e49 --- /dev/null +++ b/tb/test_axi_ram.v @@ -0,0 +1,179 @@ +/* + +Copyright (c) 2018 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * Testbench for axi_ram + */ +module test_axi_ram; + +// Parameters +parameter DATA_WIDTH = 32; +parameter ADDR_WIDTH = 16; +parameter STRB_WIDTH = (DATA_WIDTH/8); +parameter ID_WIDTH = 8; + +// Inputs +reg clk = 0; +reg rst = 0; +reg [7:0] current_test = 0; + +reg [ID_WIDTH-1:0] s_axi_awid = 0; +reg [ADDR_WIDTH-1:0] s_axi_awaddr = 0; +reg [7:0] s_axi_awlen = 0; +reg [2:0] s_axi_awsize = 0; +reg [1:0] s_axi_awburst = 0; +reg s_axi_awlock = 0; +reg [3:0] s_axi_awcache = 0; +reg [2:0] s_axi_awprot = 0; +reg s_axi_awvalid = 0; +reg [DATA_WIDTH-1:0] s_axi_wdata = 0; +reg [STRB_WIDTH-1:0] s_axi_wstrb = 0; +reg s_axi_wlast = 0; +reg s_axi_wvalid = 0; +reg s_axi_bready = 0; +reg [ID_WIDTH-1:0] s_axi_arid = 0; +reg [ADDR_WIDTH-1:0] s_axi_araddr = 0; +reg [7:0] s_axi_arlen = 0; +reg [2:0] s_axi_arsize = 0; +reg [1:0] s_axi_arburst = 0; +reg s_axi_arlock = 0; +reg [3:0] s_axi_arcache = 0; +reg [2:0] s_axi_arprot = 0; +reg s_axi_arvalid = 0; +reg s_axi_rready = 0; + +// Outputs +wire s_axi_awready; +wire s_axi_wready; +wire [ID_WIDTH-1:0] s_axi_bid; +wire [1:0] s_axi_bresp; +wire s_axi_bvalid; +wire s_axi_arready; +wire [ID_WIDTH-1:0] s_axi_rid; +wire [DATA_WIDTH-1:0] s_axi_rdata; +wire [1:0] s_axi_rresp; +wire s_axi_rlast; +wire s_axi_rvalid; + +initial begin + // myhdl integration + $from_myhdl( + clk, + rst, + current_test, + s_axi_awid, + s_axi_awaddr, + s_axi_awlen, + s_axi_awsize, + s_axi_awburst, + s_axi_awlock, + s_axi_awcache, + s_axi_awprot, + s_axi_awvalid, + s_axi_wdata, + s_axi_wstrb, + s_axi_wlast, + s_axi_wvalid, + s_axi_bready, + s_axi_arid, + s_axi_araddr, + s_axi_arlen, + s_axi_arsize, + s_axi_arburst, + s_axi_arlock, + s_axi_arcache, + s_axi_arprot, + s_axi_arvalid, + s_axi_rready + ); + $to_myhdl( + s_axi_awready, + s_axi_wready, + s_axi_bid, + s_axi_bresp, + s_axi_bvalid, + s_axi_arready, + s_axi_rid, + s_axi_rdata, + s_axi_rresp, + s_axi_rlast, + s_axi_rvalid + ); + + // dump file + $dumpfile("test_axi_ram.lxt"); + $dumpvars(0, test_axi_ram); +end + +axi_ram #( + .DATA_WIDTH(DATA_WIDTH), + .ADDR_WIDTH(ADDR_WIDTH), + .STRB_WIDTH(STRB_WIDTH), + .ID_WIDTH(ID_WIDTH) +) +UUT ( + .clk(clk), + .rst(rst), + .s_axi_awid(s_axi_awid), + .s_axi_awaddr(s_axi_awaddr), + .s_axi_awlen(s_axi_awlen), + .s_axi_awsize(s_axi_awsize), + .s_axi_awburst(s_axi_awburst), + .s_axi_awlock(s_axi_awlock), + .s_axi_awcache(s_axi_awcache), + .s_axi_awprot(s_axi_awprot), + .s_axi_awvalid(s_axi_awvalid), + .s_axi_awready(s_axi_awready), + .s_axi_wdata(s_axi_wdata), + .s_axi_wstrb(s_axi_wstrb), + .s_axi_wlast(s_axi_wlast), + .s_axi_wvalid(s_axi_wvalid), + .s_axi_wready(s_axi_wready), + .s_axi_bid(s_axi_bid), + .s_axi_bresp(s_axi_bresp), + .s_axi_bvalid(s_axi_bvalid), + .s_axi_bready(s_axi_bready), + .s_axi_arid(s_axi_arid), + .s_axi_araddr(s_axi_araddr), + .s_axi_arlen(s_axi_arlen), + .s_axi_arsize(s_axi_arsize), + .s_axi_arburst(s_axi_arburst), + .s_axi_arlock(s_axi_arlock), + .s_axi_arcache(s_axi_arcache), + .s_axi_arprot(s_axi_arprot), + .s_axi_arvalid(s_axi_arvalid), + .s_axi_arready(s_axi_arready), + .s_axi_rid(s_axi_rid), + .s_axi_rdata(s_axi_rdata), + .s_axi_rresp(s_axi_rresp), + .s_axi_rlast(s_axi_rlast), + .s_axi_rvalid(s_axi_rvalid), + .s_axi_rready(s_axi_rready) +); + +endmodule