mirror of
https://github.com/alexforencich/verilog-axi.git
synced 2025-01-14 06:42:55 +08:00
Initial commit
This commit is contained in:
commit
f4cca52660
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
*~
|
||||
*.lxt
|
||||
*.pyc
|
||||
*.vvp
|
||||
*.kate-swp
|
||||
|
19
COPYING
Normal file
19
COPYING
Normal file
@ -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.
|
162
README.md
Normal file
162
README.md
Normal file
@ -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
|
385
rtl/axi_ram.v
Normal file
385
rtl/axi_ram.v
Normal file
@ -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
|
783
tb/axi.py
Normal file
783
tb/axi.py
Normal file
@ -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()
|
||||
|
293
tb/test_axi.py
Executable file
293
tb/test_axi.py
Executable file
@ -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()
|
||||
|
257
tb/test_axi_ram.py
Executable file
257
tb/test_axi_ram.py
Executable file
@ -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()
|
179
tb/test_axi_ram.v
Normal file
179
tb/test_axi_ram.v
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user