1
0
mirror of https://github.com/corundum/corundum.git synced 2025-01-30 08:32:52 +08:00

Add AXI nonblocking crossbar interconnect module and testbench

This commit is contained in:
Alex Forencich 2019-02-25 18:37:46 -08:00
parent 365e063bc7
commit 7b713199ad
6 changed files with 2998 additions and 0 deletions

331
rtl/axi_crossbar.v Normal file
View File

@ -0,0 +1,331 @@
/*
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 crossbar
*/
module axi_crossbar #
(
parameter S_COUNT = 4,
parameter M_COUNT = 4,
parameter DATA_WIDTH = 32,
parameter ADDR_WIDTH = 32,
parameter STRB_WIDTH = (DATA_WIDTH/8),
parameter S_ID_WIDTH = 8,
parameter M_ID_WIDTH = S_ID_WIDTH+$clog2(S_COUNT),
parameter AWUSER_ENABLE = 0,
parameter AWUSER_WIDTH = 1,
parameter WUSER_ENABLE = 0,
parameter WUSER_WIDTH = 1,
parameter BUSER_ENABLE = 0,
parameter BUSER_WIDTH = 1,
parameter ARUSER_ENABLE = 0,
parameter ARUSER_WIDTH = 1,
parameter RUSER_ENABLE = 0,
parameter RUSER_WIDTH = 1,
parameter S_THREADS = {S_COUNT{32'd2}},
parameter S_ACCEPT = {S_COUNT{32'd16}},
parameter M_REGIONS = 1,
parameter M_BASE_ADDR = {32'h03000000, 32'h02000000, 32'h01000000, 32'h00000000},
parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}},
parameter M_CONNECT_READ = {M_COUNT{{S_COUNT{1'b1}}}},
parameter M_CONNECT_WRITE = {M_COUNT{{S_COUNT{1'b1}}}},
parameter M_ISSUE = {M_COUNT{32'd4}},
parameter M_SECURE = {M_COUNT{1'b0}},
parameter S_AW_REG_TYPE = {S_COUNT{2'd0}},
parameter S_W_REG_TYPE = {S_COUNT{2'd0}},
parameter S_B_REG_TYPE = {S_COUNT{2'd1}},
parameter S_AR_REG_TYPE = {S_COUNT{2'd0}},
parameter S_R_REG_TYPE = {S_COUNT{2'd2}},
parameter M_AW_REG_TYPE = {M_COUNT{2'd1}},
parameter M_W_REG_TYPE = {M_COUNT{2'd2}},
parameter M_B_REG_TYPE = {M_COUNT{2'd0}},
parameter M_AR_REG_TYPE = {M_COUNT{2'd1}},
parameter M_R_REG_TYPE = {M_COUNT{2'd0}}
)
(
input wire clk,
input wire rst,
/*
* AXI slave interfaces
*/
input wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_awid,
input wire [S_COUNT*ADDR_WIDTH-1:0] s_axi_awaddr,
input wire [S_COUNT*8-1:0] s_axi_awlen,
input wire [S_COUNT*3-1:0] s_axi_awsize,
input wire [S_COUNT*2-1:0] s_axi_awburst,
input wire [S_COUNT-1:0] s_axi_awlock,
input wire [S_COUNT*4-1:0] s_axi_awcache,
input wire [S_COUNT*3-1:0] s_axi_awprot,
input wire [S_COUNT*4-1:0] s_axi_awqos,
input wire [S_COUNT*AWUSER_WIDTH-1:0] s_axi_awuser,
input wire [S_COUNT-1:0] s_axi_awvalid,
output wire [S_COUNT-1:0] s_axi_awready,
input wire [S_COUNT*DATA_WIDTH-1:0] s_axi_wdata,
input wire [S_COUNT*STRB_WIDTH-1:0] s_axi_wstrb,
input wire [S_COUNT-1:0] s_axi_wlast,
input wire [S_COUNT*WUSER_WIDTH-1:0] s_axi_wuser,
input wire [S_COUNT-1:0] s_axi_wvalid,
output wire [S_COUNT-1:0] s_axi_wready,
output wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_bid,
output wire [S_COUNT*2-1:0] s_axi_bresp,
output wire [S_COUNT*BUSER_WIDTH-1:0] s_axi_buser,
output wire [S_COUNT-1:0] s_axi_bvalid,
input wire [S_COUNT-1:0] s_axi_bready,
input wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_arid,
input wire [S_COUNT*ADDR_WIDTH-1:0] s_axi_araddr,
input wire [S_COUNT*8-1:0] s_axi_arlen,
input wire [S_COUNT*3-1:0] s_axi_arsize,
input wire [S_COUNT*2-1:0] s_axi_arburst,
input wire [S_COUNT-1:0] s_axi_arlock,
input wire [S_COUNT*4-1:0] s_axi_arcache,
input wire [S_COUNT*3-1:0] s_axi_arprot,
input wire [S_COUNT*4-1:0] s_axi_arqos,
input wire [S_COUNT*ARUSER_WIDTH-1:0] s_axi_aruser,
input wire [S_COUNT-1:0] s_axi_arvalid,
output wire [S_COUNT-1:0] s_axi_arready,
output wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_rid,
output wire [S_COUNT*DATA_WIDTH-1:0] s_axi_rdata,
output wire [S_COUNT*2-1:0] s_axi_rresp,
output wire [S_COUNT-1:0] s_axi_rlast,
output wire [S_COUNT*RUSER_WIDTH-1:0] s_axi_ruser,
output wire [S_COUNT-1:0] s_axi_rvalid,
input wire [S_COUNT-1:0] s_axi_rready,
/*
* AXI master interfaces
*/
output wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_awid,
output wire [M_COUNT*ADDR_WIDTH-1:0] m_axi_awaddr,
output wire [M_COUNT*8-1:0] m_axi_awlen,
output wire [M_COUNT*3-1:0] m_axi_awsize,
output wire [M_COUNT*2-1:0] m_axi_awburst,
output wire [M_COUNT-1:0] m_axi_awlock,
output wire [M_COUNT*4-1:0] m_axi_awcache,
output wire [M_COUNT*3-1:0] m_axi_awprot,
output wire [M_COUNT*4-1:0] m_axi_awqos,
output wire [M_COUNT*4-1:0] m_axi_awregion,
output wire [M_COUNT*AWUSER_WIDTH-1:0] m_axi_awuser,
output wire [M_COUNT-1:0] m_axi_awvalid,
input wire [M_COUNT-1:0] m_axi_awready,
output wire [M_COUNT*DATA_WIDTH-1:0] m_axi_wdata,
output wire [M_COUNT*STRB_WIDTH-1:0] m_axi_wstrb,
output wire [M_COUNT-1:0] m_axi_wlast,
output wire [M_COUNT*WUSER_WIDTH-1:0] m_axi_wuser,
output wire [M_COUNT-1:0] m_axi_wvalid,
input wire [M_COUNT-1:0] m_axi_wready,
input wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_bid,
input wire [M_COUNT*2-1:0] m_axi_bresp,
input wire [M_COUNT*BUSER_WIDTH-1:0] m_axi_buser,
input wire [M_COUNT-1:0] m_axi_bvalid,
output wire [M_COUNT-1:0] m_axi_bready,
output wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_arid,
output wire [M_COUNT*ADDR_WIDTH-1:0] m_axi_araddr,
output wire [M_COUNT*8-1:0] m_axi_arlen,
output wire [M_COUNT*3-1:0] m_axi_arsize,
output wire [M_COUNT*2-1:0] m_axi_arburst,
output wire [M_COUNT-1:0] m_axi_arlock,
output wire [M_COUNT*4-1:0] m_axi_arcache,
output wire [M_COUNT*3-1:0] m_axi_arprot,
output wire [M_COUNT*4-1:0] m_axi_arqos,
output wire [M_COUNT*4-1:0] m_axi_arregion,
output wire [M_COUNT*ARUSER_WIDTH-1:0] m_axi_aruser,
output wire [M_COUNT-1:0] m_axi_arvalid,
input wire [M_COUNT-1:0] m_axi_arready,
input wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_rid,
input wire [M_COUNT*DATA_WIDTH-1:0] m_axi_rdata,
input wire [M_COUNT*2-1:0] m_axi_rresp,
input wire [M_COUNT-1:0] m_axi_rlast,
input wire [M_COUNT*RUSER_WIDTH-1:0] m_axi_ruser,
input wire [M_COUNT-1:0] m_axi_rvalid,
output wire [M_COUNT-1:0] m_axi_rready
);
axi_crossbar_wr #(
.S_COUNT(S_COUNT),
.M_COUNT(M_COUNT),
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.S_ID_WIDTH(S_ID_WIDTH),
.M_ID_WIDTH(M_ID_WIDTH),
.AWUSER_ENABLE(AWUSER_ENABLE),
.AWUSER_WIDTH(AWUSER_WIDTH),
.WUSER_ENABLE(WUSER_ENABLE),
.WUSER_WIDTH(WUSER_WIDTH),
.BUSER_ENABLE(BUSER_ENABLE),
.BUSER_WIDTH(BUSER_WIDTH),
.S_THREADS(S_THREADS),
.S_ACCEPT(S_ACCEPT),
.M_REGIONS(M_REGIONS),
.M_BASE_ADDR(M_BASE_ADDR),
.M_ADDR_WIDTH(M_ADDR_WIDTH),
.M_CONNECT(M_CONNECT_WRITE),
.M_ISSUE(M_ISSUE),
.M_SECURE(M_SECURE),
.S_AW_REG_TYPE(S_AW_REG_TYPE),
.S_W_REG_TYPE (S_W_REG_TYPE),
.S_B_REG_TYPE (S_B_REG_TYPE)
)
axi_crossbar_wr_inst (
.clk(clk),
.rst(rst),
/*
* AXI slave interfaces
*/
.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_awqos(s_axi_awqos),
.s_axi_awuser(s_axi_awuser),
.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_wuser(s_axi_wuser),
.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_buser(s_axi_buser),
.s_axi_bvalid(s_axi_bvalid),
.s_axi_bready(s_axi_bready),
/*
* AXI master interfaces
*/
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awqos(m_axi_awqos),
.m_axi_awregion(m_axi_awregion),
.m_axi_awuser(m_axi_awuser),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wuser(m_axi_wuser),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_buser(m_axi_buser),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready)
);
axi_crossbar_rd #(
.S_COUNT(S_COUNT),
.M_COUNT(M_COUNT),
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.S_ID_WIDTH(S_ID_WIDTH),
.M_ID_WIDTH(M_ID_WIDTH),
.ARUSER_ENABLE(ARUSER_ENABLE),
.ARUSER_WIDTH(ARUSER_WIDTH),
.RUSER_ENABLE(RUSER_ENABLE),
.RUSER_WIDTH(RUSER_WIDTH),
.S_THREADS(S_THREADS),
.S_ACCEPT(S_ACCEPT),
.M_REGIONS(M_REGIONS),
.M_BASE_ADDR(M_BASE_ADDR),
.M_ADDR_WIDTH(M_ADDR_WIDTH),
.M_CONNECT(M_CONNECT_READ),
.M_ISSUE(M_ISSUE),
.M_SECURE(M_SECURE),
.S_AR_REG_TYPE(S_AR_REG_TYPE),
.S_R_REG_TYPE (S_R_REG_TYPE)
)
axi_crossbar_rd_inst (
.clk(clk),
.rst(rst),
/*
* AXI slave interfaces
*/
.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_arqos(s_axi_arqos),
.s_axi_aruser(s_axi_aruser),
.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_ruser(s_axi_ruser),
.s_axi_rvalid(s_axi_rvalid),
.s_axi_rready(s_axi_rready),
/*
* AXI master interfaces
*/
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arqos(m_axi_arqos),
.m_axi_arregion(m_axi_arregion),
.m_axi_aruser(m_axi_aruser),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_ruser(m_axi_ruser),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready)
);
endmodule

326
rtl/axi_crossbar_addr.v Normal file
View File

@ -0,0 +1,326 @@
/*
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 crossbar address decode and admission control
*/
module axi_crossbar_addr #
(
parameter S = 0,
parameter S_COUNT = 4,
parameter M_COUNT = 4,
parameter ADDR_WIDTH = 32,
parameter ID_WIDTH = 8,
parameter S_THREADS = 32'd2,
parameter S_ACCEPT = 32'd16,
parameter M_REGIONS = 1,
parameter M_BASE_ADDR = {32'h03000000, 32'h02000000, 32'h01000000, 32'h00000000},
parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}},
parameter M_CONNECT = {M_COUNT{{S_COUNT{1'b1}}}},
parameter M_SECURE = {M_COUNT{1'b0}},
parameter WC_OUTPUT = 0
)
(
input wire clk,
input wire rst,
/*
* Address input
*/
input wire [ID_WIDTH-1:0] s_axi_aid,
input wire [ADDR_WIDTH-1:0] s_axi_aaddr,
input wire [2:0] s_axi_aprot,
input wire [3:0] s_axi_aqos,
input wire s_axi_avalid,
output wire s_axi_aready,
/*
* Address output
*/
output wire [3:0] m_axi_aregion,
output wire [$clog2(M_COUNT)-1:0] m_select,
output wire m_axi_avalid,
input wire m_axi_aready,
/*
* Write command output
*/
output wire [$clog2(M_COUNT)-1:0] m_wc_select,
output wire m_wc_decerr,
output wire m_wc_valid,
input wire m_wc_ready,
/*
* Reply command output
*/
output wire m_rc_decerr,
output wire m_rc_valid,
input wire m_rc_ready,
/*
* Completion input
*/
input wire [ID_WIDTH-1:0] s_cpl_id,
input wire s_cpl_valid
);
parameter CL_S_COUNT = $clog2(S_COUNT);
parameter CL_M_COUNT = $clog2(M_COUNT);
parameter S_INT_THREADS = S_THREADS > S_ACCEPT ? S_ACCEPT : S_THREADS;
parameter CL_S_INT_THREADS = $clog2(S_INT_THREADS);
parameter CL_S_ACCEPT = $clog2(S_ACCEPT);
integer i, j;
// check configuration
initial begin
if (S_ACCEPT < 1) begin
$error("Error: need at least 1 accept");
$finish;
end
if (S_THREADS < 1) begin
$error("Error: need at least 1 thread");
$finish;
end
if (S_THREADS > S_ACCEPT) begin
$warning("Warning: requested thread count larger than accept count; limiting thread count to accept count");
end
if (M_REGIONS < 1) begin
$error("Error: need at least 1 region");
$finish;
end
for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin
if (M_ADDR_WIDTH[i*32 +: 32] && (M_ADDR_WIDTH[i*32 +: 32] < 12 || M_ADDR_WIDTH[i*32 +: 32] > ADDR_WIDTH)) begin
$error("Error: address width out of range");
$finish;
end
end
for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin
for (j = i+1; j < M_COUNT*M_REGIONS; j = j + 1) begin
if (M_ADDR_WIDTH[i*32 +: 32] && M_ADDR_WIDTH[j*32 +: 32]) begin
if (((M_BASE_ADDR[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32])) <= (M_BASE_ADDR[j*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[j*32 +: 32])))) && ((M_BASE_ADDR[j*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[j*32 +: 32])) <= (M_BASE_ADDR[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32]))))) begin
$display("%d: %08x / %02d -- %08x-%08x", i, M_BASE_ADDR[i*ADDR_WIDTH +: ADDR_WIDTH], M_ADDR_WIDTH[i*32 +: 32], M_BASE_ADDR[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32]), M_BASE_ADDR[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32])));
$display("%d: %08x / %02d -- %08x-%08x", j, M_BASE_ADDR[j*ADDR_WIDTH +: ADDR_WIDTH], M_ADDR_WIDTH[j*32 +: 32], M_BASE_ADDR[j*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[j*32 +: 32]), M_BASE_ADDR[j*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[j*32 +: 32])));
$error("Error: address ranges overlap");
$finish;
end
end
end
end
end
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_DECODE = 3'd1;
reg [2:0] state_reg = STATE_IDLE, state_next;
reg match;
reg trans_start;
reg trans_complete;
reg [$clog2(S_ACCEPT+1)-1:0] trans_count_reg = 0;
wire trans_limit = trans_count_reg >= S_ACCEPT && !trans_complete;
// transfer ID thread tracking
reg [ID_WIDTH-1:0] thread_id_reg[S_INT_THREADS-1:0];
reg [CL_M_COUNT-1:0] thread_m_reg[S_INT_THREADS-1:0];
reg [3:0] thread_region_reg[S_INT_THREADS-1:0];
reg [$clog2(S_ACCEPT+1)-1:0] thread_count_reg[S_INT_THREADS-1:0];
wire [S_INT_THREADS-1:0] thread_active;
wire [S_INT_THREADS-1:0] thread_match;
wire [S_INT_THREADS-1:0] thread_cpl_match;
wire [S_INT_THREADS-1:0] thread_trans_start;
wire [S_INT_THREADS-1:0] thread_trans_complete;
generate
genvar n;
for (n = 0; n < S_INT_THREADS; n = n + 1) begin
initial begin
thread_count_reg[n] <= 0;
end
assign thread_active[n] = thread_count_reg[n] != 0;
assign thread_match[n] = thread_active[n] && thread_id_reg[n] == s_axi_aid;
assign thread_cpl_match[n] = thread_active[n] && thread_id_reg[n] == s_cpl_id;
assign thread_trans_start[n] = (thread_match[n] || (!thread_active[n] && !thread_match && !(thread_trans_start & ({S_INT_THREADS{1'b1}} >> (S_INT_THREADS-n))))) && trans_start;
assign thread_trans_complete[n] = thread_cpl_match[n] && trans_complete;
always @(posedge clk) begin
if (rst) begin
thread_count_reg[n] <= 0;
end else begin
if (thread_trans_start[n] && !thread_trans_complete[n]) begin
thread_count_reg[n] <= thread_count_reg[n] + 1;
end else if (!thread_trans_start[n] && thread_trans_complete[n]) begin
thread_count_reg[n] <= thread_count_reg[n] - 1;
end
end
if (thread_trans_start[n]) begin
thread_id_reg[n] <= s_axi_aid;
thread_m_reg[n] <= m_select_next;
thread_region_reg[n] <= m_axi_aregion_next;
end
end
end
endgenerate
reg s_axi_aready_reg = 0, s_axi_aready_next;
reg [3:0] m_axi_aregion_reg = 4'd0, m_axi_aregion_next;
reg [CL_M_COUNT-1:0] m_select_reg = {CL_M_COUNT{1'b0}}, m_select_next;
reg m_axi_avalid_reg = 1'b0, m_axi_avalid_next;
reg m_decerr_reg = 1'b0, m_decerr_next;
reg m_wc_valid_reg = 1'b0, m_wc_valid_next;
reg m_rc_valid_reg = 1'b0, m_rc_valid_next;
assign s_axi_aready = s_axi_aready_reg;
assign m_axi_aregion = m_axi_aregion_reg;
assign m_select = m_select_reg;
assign m_axi_avalid = m_axi_avalid_reg;
assign m_wc_select = m_select_reg;
assign m_wc_decerr = m_decerr_reg;
assign m_wc_valid = m_wc_valid_reg;
assign m_rc_decerr = m_decerr_reg;
assign m_rc_valid = m_rc_valid_reg;
always @* begin
state_next = STATE_IDLE;
match = 1'b0;
trans_start = 1'b0;
trans_complete = 1'b0;
s_axi_aready_next = 1'b0;
m_axi_aregion_next = m_axi_aregion_reg;
m_select_next = m_select_reg;
m_select_next = m_select_reg;
m_axi_avalid_next = m_axi_avalid_reg && !m_axi_aready;
m_decerr_next = m_decerr_reg;
m_wc_valid_next = m_wc_valid_reg && !m_wc_ready;
m_rc_valid_next = m_rc_valid_reg && !m_rc_ready;
case (state_reg)
STATE_IDLE: begin
// idle state, store values
s_axi_aready_next = 1'b0;
if (s_axi_avalid && !s_axi_aready) begin
match = 1'b0;
for (i = 0; i < M_COUNT; i = i + 1) begin
for (j = 0; j < M_REGIONS; j = j + 1) begin
if (M_ADDR_WIDTH[(i*M_REGIONS+j)*32 +: 32] && (!M_SECURE[i] || !s_axi_aprot[1]) && (M_CONNECT & (1 << (S+i*S_COUNT))) && (s_axi_aaddr >> M_ADDR_WIDTH[(i*M_REGIONS+j)*32 +: 32]) == (M_BASE_ADDR[(i*M_REGIONS+j)*ADDR_WIDTH +: ADDR_WIDTH] >> M_ADDR_WIDTH[(i*M_REGIONS+j)*32 +: 32])) begin
m_select_next = i;
m_axi_aregion_next = j;
match = 1'b1;
end
end
end
if (match) begin
// address decode successful
if (!trans_limit && (thread_match || !(&thread_active))) begin
// transaction limit not reached
m_axi_avalid_next = 1'b1;
m_decerr_next = 1'b0;
m_wc_valid_next = WC_OUTPUT;
m_rc_valid_next = 1'b0;
trans_start = 1'b1;
state_next = STATE_DECODE;
end else begin
// transaction limit reached; block in idle
state_next = STATE_IDLE;
end
end else begin
// decode error
m_axi_avalid_next = 1'b0;
m_decerr_next = 1'b1;
m_wc_valid_next = WC_OUTPUT;
m_rc_valid_next = 1'b1;
state_next = STATE_DECODE;
end
end else begin
state_next = STATE_IDLE;
end
end
STATE_DECODE: begin
if (!m_axi_avalid_next && (!m_wc_valid_next || !WC_OUTPUT) && !m_rc_valid_next) begin
s_axi_aready_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_DECODE;
end
end
endcase
// manage completions
trans_complete = s_cpl_valid;
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
s_axi_aready_reg <= 1'b0;
m_axi_avalid_reg <= 1'b0;
m_wc_valid_reg <= 1'b0;
m_rc_valid_reg <= 1'b0;
trans_count_reg <= 0;
end else begin
state_reg <= state_next;
s_axi_aready_reg <= s_axi_aready_next;
m_axi_avalid_reg <= m_axi_avalid_next;
m_wc_valid_reg <= m_wc_valid_next;
m_rc_valid_reg <= m_rc_valid_next;
if (trans_start && !trans_complete) begin
trans_count_reg <= trans_count_reg + 1;
end else if (!trans_start && trans_complete) begin
trans_count_reg <= trans_count_reg - 1;
end
end
m_axi_aregion_reg <= m_axi_aregion_next;
m_select_reg <= m_select_next;
m_decerr_reg <= m_decerr_next;
end
endmodule

527
rtl/axi_crossbar_rd.v Normal file
View File

@ -0,0 +1,527 @@
/*
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 crossbar (read)
*/
module axi_crossbar_rd #
(
parameter S_COUNT = 4,
parameter M_COUNT = 4,
parameter DATA_WIDTH = 32,
parameter ADDR_WIDTH = 32,
parameter STRB_WIDTH = (DATA_WIDTH/8),
parameter S_ID_WIDTH = 8,
parameter M_ID_WIDTH = S_ID_WIDTH+$clog2(S_COUNT),
parameter ARUSER_ENABLE = 0,
parameter ARUSER_WIDTH = 1,
parameter RUSER_ENABLE = 0,
parameter RUSER_WIDTH = 1,
parameter S_THREADS = {S_COUNT{32'd2}},
parameter S_ACCEPT = {S_COUNT{32'd16}},
parameter M_REGIONS = 1,
parameter M_BASE_ADDR = {32'h03000000, 32'h02000000, 32'h01000000, 32'h00000000},
parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}},
parameter M_CONNECT = {M_COUNT{{S_COUNT{1'b1}}}},
parameter M_ISSUE = {M_COUNT{32'd4}},
parameter M_SECURE = {M_COUNT{1'b0}},
parameter S_AR_REG_TYPE = {S_COUNT{2'd0}},
parameter S_R_REG_TYPE = {S_COUNT{2'd2}},
parameter M_AR_REG_TYPE = {M_COUNT{2'd1}},
parameter M_R_REG_TYPE = {M_COUNT{2'd0}}
)
(
input wire clk,
input wire rst,
/*
* AXI slave interfaces
*/
input wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_arid,
input wire [S_COUNT*ADDR_WIDTH-1:0] s_axi_araddr,
input wire [S_COUNT*8-1:0] s_axi_arlen,
input wire [S_COUNT*3-1:0] s_axi_arsize,
input wire [S_COUNT*2-1:0] s_axi_arburst,
input wire [S_COUNT-1:0] s_axi_arlock,
input wire [S_COUNT*4-1:0] s_axi_arcache,
input wire [S_COUNT*3-1:0] s_axi_arprot,
input wire [S_COUNT*4-1:0] s_axi_arqos,
input wire [S_COUNT*ARUSER_WIDTH-1:0] s_axi_aruser,
input wire [S_COUNT-1:0] s_axi_arvalid,
output wire [S_COUNT-1:0] s_axi_arready,
output wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_rid,
output wire [S_COUNT*DATA_WIDTH-1:0] s_axi_rdata,
output wire [S_COUNT*2-1:0] s_axi_rresp,
output wire [S_COUNT-1:0] s_axi_rlast,
output wire [S_COUNT*RUSER_WIDTH-1:0] s_axi_ruser,
output wire [S_COUNT-1:0] s_axi_rvalid,
input wire [S_COUNT-1:0] s_axi_rready,
/*
* AXI master interfaces
*/
output wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_arid,
output wire [M_COUNT*ADDR_WIDTH-1:0] m_axi_araddr,
output wire [M_COUNT*8-1:0] m_axi_arlen,
output wire [M_COUNT*3-1:0] m_axi_arsize,
output wire [M_COUNT*2-1:0] m_axi_arburst,
output wire [M_COUNT-1:0] m_axi_arlock,
output wire [M_COUNT*4-1:0] m_axi_arcache,
output wire [M_COUNT*3-1:0] m_axi_arprot,
output wire [M_COUNT*4-1:0] m_axi_arqos,
output wire [M_COUNT*4-1:0] m_axi_arregion,
output wire [M_COUNT*ARUSER_WIDTH-1:0] m_axi_aruser,
output wire [M_COUNT-1:0] m_axi_arvalid,
input wire [M_COUNT-1:0] m_axi_arready,
input wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_rid,
input wire [M_COUNT*DATA_WIDTH-1:0] m_axi_rdata,
input wire [M_COUNT*2-1:0] m_axi_rresp,
input wire [M_COUNT-1:0] m_axi_rlast,
input wire [M_COUNT*RUSER_WIDTH-1:0] m_axi_ruser,
input wire [M_COUNT-1:0] m_axi_rvalid,
output wire [M_COUNT-1:0] m_axi_rready
);
parameter CL_S_COUNT = $clog2(S_COUNT);
parameter CL_M_COUNT = $clog2(M_COUNT);
parameter M_COUNT_P1 = M_COUNT+1;
parameter CL_M_COUNT_P1 = $clog2(M_COUNT_P1);
integer i;
// check configuration
initial begin
if (M_ID_WIDTH < S_ID_WIDTH+$clog2(S_COUNT)) begin
$error("Error: M_ID_WIDTH must be at least $clog2(S_COUNT) larger than S_ID_WIDTH");
$finish;
end
for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin
if (M_ADDR_WIDTH[i*32 +: 32] && (M_ADDR_WIDTH[i*32 +: 32] < 12 || M_ADDR_WIDTH[i*32 +: 32] > ADDR_WIDTH)) begin
$error("Error: value out of range");
$finish;
end
end
end
wire [S_COUNT*S_ID_WIDTH-1:0] int_s_axi_arid;
wire [S_COUNT*ADDR_WIDTH-1:0] int_s_axi_araddr;
wire [S_COUNT*8-1:0] int_s_axi_arlen;
wire [S_COUNT*3-1:0] int_s_axi_arsize;
wire [S_COUNT*2-1:0] int_s_axi_arburst;
wire [S_COUNT-1:0] int_s_axi_arlock;
wire [S_COUNT*4-1:0] int_s_axi_arcache;
wire [S_COUNT*3-1:0] int_s_axi_arprot;
wire [S_COUNT*4-1:0] int_s_axi_arqos;
wire [S_COUNT*4-1:0] int_s_axi_arregion;
wire [S_COUNT*ARUSER_WIDTH-1:0] int_s_axi_aruser;
wire [S_COUNT-1:0] int_s_axi_arvalid;
wire [S_COUNT-1:0] int_s_axi_arready;
wire [S_COUNT*M_COUNT-1:0] int_axi_arvalid;
wire [M_COUNT*S_COUNT-1:0] int_axi_arready;
wire [M_COUNT*M_ID_WIDTH-1:0] int_m_axi_rid;
wire [M_COUNT*DATA_WIDTH-1:0] int_m_axi_rdata;
wire [M_COUNT*2-1:0] int_m_axi_rresp;
wire [M_COUNT-1:0] int_m_axi_rlast;
wire [M_COUNT*RUSER_WIDTH-1:0] int_m_axi_ruser;
wire [M_COUNT-1:0] int_m_axi_rvalid;
wire [M_COUNT-1:0] int_m_axi_rready;
wire [M_COUNT*S_COUNT-1:0] int_axi_rvalid;
wire [S_COUNT*M_COUNT-1:0] int_axi_rready;
generate
genvar m, n;
for (m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces
// address decode and admission control
wire [CL_M_COUNT-1:0] a_select;
wire m_axi_avalid;
wire m_axi_aready;
wire m_rc_decerr;
wire m_rc_valid;
wire m_rc_ready;
wire [S_ID_WIDTH-1:0] s_cpl_id;
wire s_cpl_valid;
axi_crossbar_addr #(
.S(m),
.S_COUNT(S_COUNT),
.M_COUNT(M_COUNT),
.ADDR_WIDTH(ADDR_WIDTH),
.ID_WIDTH(S_ID_WIDTH),
.S_THREADS(S_THREADS[m*32 +: 32]),
.S_ACCEPT(S_ACCEPT[m*32 +: 32]),
.M_REGIONS(M_REGIONS),
.M_BASE_ADDR(M_BASE_ADDR),
.M_ADDR_WIDTH(M_ADDR_WIDTH),
.M_CONNECT(M_CONNECT),
.M_SECURE(M_SECURE),
.WC_OUTPUT(0)
)
addr_inst (
.clk(clk),
.rst(rst),
/*
* Address input
*/
.s_axi_aid(int_s_axi_arid[m*S_ID_WIDTH +: S_ID_WIDTH]),
.s_axi_aaddr(int_s_axi_araddr[m*ADDR_WIDTH +: ADDR_WIDTH]),
.s_axi_aprot(int_s_axi_arprot[m*3 +: 3]),
.s_axi_aqos(int_s_axi_arqos[m*4 +: 4]),
.s_axi_avalid(int_s_axi_arvalid[m]),
.s_axi_aready(int_s_axi_arready[m]),
/*
* Address output
*/
.m_axi_aregion(int_s_axi_arregion[m*4 +: 4]),
.m_select(a_select),
.m_axi_avalid(m_axi_avalid),
.m_axi_aready(m_axi_aready),
/*
* Write command output
*/
.m_wc_select(),
.m_wc_decerr(),
.m_wc_valid(),
.m_wc_ready(1'b1),
/*
* Response command output
*/
.m_rc_decerr(m_rc_decerr),
.m_rc_valid(m_rc_valid),
.m_rc_ready(m_rc_ready),
/*
* Completion input
*/
.s_cpl_id(s_cpl_id),
.s_cpl_valid(s_cpl_valid)
);
assign int_axi_arvalid[m*M_COUNT +: M_COUNT] = m_axi_avalid << a_select;
assign m_axi_aready = int_axi_arready[a_select*S_COUNT+m];
// decode error handling
reg [S_ID_WIDTH-1:0] decerr_m_axi_rid_reg = {S_ID_WIDTH{1'b0}}, decerr_m_axi_rid_next;
reg decerr_m_axi_rlast_reg = 1'b0, decerr_m_axi_rlast_next;
reg decerr_m_axi_rvalid_reg = 1'b0, decerr_m_axi_rvalid_next;
wire decerr_m_axi_rready;
reg [7:0] decerr_len_reg = 8'd0, decerr_len_next;
assign m_rc_ready = !decerr_m_axi_rvalid_reg;
always @* begin
decerr_len_next = decerr_len_reg;
decerr_m_axi_rid_next = decerr_m_axi_rid_reg;
decerr_m_axi_rlast_next = decerr_m_axi_rlast_reg;
decerr_m_axi_rvalid_next = decerr_m_axi_rvalid_reg;
if (decerr_m_axi_rvalid_reg) begin
if (decerr_m_axi_rready) begin
if (decerr_len_reg > 0) begin
decerr_len_next = decerr_len_reg-1;
decerr_m_axi_rlast_next = (decerr_len_next == 0);
decerr_m_axi_rvalid_next = 1'b1;
end else begin
decerr_m_axi_rvalid_next = 1'b0;
end
end
end else if (m_rc_valid && m_rc_ready) begin
decerr_len_next = int_s_axi_arlen[m*8 +: 8];
decerr_m_axi_rid_next = int_s_axi_arid[m*S_ID_WIDTH +: S_ID_WIDTH];
decerr_m_axi_rlast_next = (decerr_len_next == 0);
decerr_m_axi_rvalid_next = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
decerr_m_axi_rvalid_reg <= 1'b0;
end else begin
decerr_m_axi_rvalid_reg <= decerr_m_axi_rvalid_next;
end
decerr_m_axi_rid_reg <= decerr_m_axi_rid_next;
decerr_m_axi_rlast_reg <= decerr_m_axi_rlast_next;
decerr_len_reg <= decerr_len_next;
end
// read response arbitration
wire [M_COUNT_P1-1:0] r_request;
wire [M_COUNT_P1-1:0] r_acknowledge;
wire [M_COUNT_P1-1:0] r_grant;
wire r_grant_valid;
wire [CL_M_COUNT_P1-1:0] r_grant_encoded;
arbiter #(
.PORTS(M_COUNT_P1),
.TYPE("ROUND_ROBIN"),
.BLOCK("ACKNOWLEDGE"),
.LSB_PRIORITY("HIGH")
)
r_arb_inst (
.clk(clk),
.rst(rst),
.request(r_request),
.acknowledge(r_acknowledge),
.grant(r_grant),
.grant_valid(r_grant_valid),
.grant_encoded(r_grant_encoded)
);
// read response mux
wire [S_ID_WIDTH-1:0] m_axi_rid_mux = {decerr_m_axi_rid_reg, int_m_axi_rid} >> r_grant_encoded*M_ID_WIDTH;
wire [DATA_WIDTH-1:0] m_axi_rdata_mux = {{DATA_WIDTH{1'b0}}, int_m_axi_rdata} >> r_grant_encoded*DATA_WIDTH;
wire [1:0] m_axi_rresp_mux = {2'b11, int_m_axi_rresp} >> r_grant_encoded*2;
wire m_axi_rlast_mux = {decerr_m_axi_rlast_reg, int_m_axi_rlast} >> r_grant_encoded;
wire [RUSER_WIDTH-1:0] m_axi_ruser_mux = {{RUSER_WIDTH{1'b0}}, int_m_axi_ruser} >> r_grant_encoded*RUSER_WIDTH;
wire m_axi_rvalid_mux = ({decerr_m_axi_rvalid_reg, int_m_axi_rvalid} >> r_grant_encoded) && r_grant_valid;
wire m_axi_rready_mux;
assign int_axi_rready[m*M_COUNT +: M_COUNT] = (r_grant_valid && m_axi_rready_mux) << r_grant_encoded;
assign decerr_m_axi_rready = (r_grant_valid && m_axi_rready_mux) && (r_grant_encoded == M_COUNT_P1-1);
for (n = 0; n < M_COUNT; n = n + 1) begin
assign r_request[n] = int_axi_rvalid[n*S_COUNT+m] && !r_grant[n];
assign r_acknowledge[n] = r_grant[n] && int_axi_rvalid[n*S_COUNT+m] && m_axi_rlast_mux && m_axi_rready_mux;
end
assign r_request[M_COUNT_P1-1] = decerr_m_axi_rvalid_reg && !r_grant[M_COUNT_P1-1];
assign r_acknowledge[M_COUNT_P1-1] = r_grant[M_COUNT_P1-1] && decerr_m_axi_rvalid_reg && decerr_m_axi_rlast_reg && m_axi_rready_mux;
assign s_cpl_id = m_axi_rid_mux;
assign s_cpl_valid = m_axi_rvalid_mux && m_axi_rready_mux && m_axi_rlast_mux;
// S side register
axi_register_rd #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.ID_WIDTH(S_ID_WIDTH),
.ARUSER_ENABLE(ARUSER_ENABLE),
.ARUSER_WIDTH(ARUSER_WIDTH),
.RUSER_ENABLE(RUSER_ENABLE),
.RUSER_WIDTH(RUSER_WIDTH),
.AR_REG_TYPE(S_AR_REG_TYPE),
.R_REG_TYPE(S_R_REG_TYPE)
)
reg_inst (
.clk(clk),
.rst(rst),
.s_axi_arid(s_axi_arid[m*S_ID_WIDTH +: S_ID_WIDTH]),
.s_axi_araddr(s_axi_araddr[m*ADDR_WIDTH +: ADDR_WIDTH]),
.s_axi_arlen(s_axi_arlen[m*8 +: 8]),
.s_axi_arsize(s_axi_arsize[m*3 +: 3]),
.s_axi_arburst(s_axi_arburst[m*2 +: 2]),
.s_axi_arlock(s_axi_arlock[m]),
.s_axi_arcache(s_axi_arcache[m*4 +: 4]),
.s_axi_arprot(s_axi_arprot[m*3 +: 3]),
.s_axi_arqos(s_axi_arqos[m*4 +: 4]),
.s_axi_arregion(4'd0),
.s_axi_aruser(s_axi_aruser[m*ARUSER_WIDTH +: ARUSER_WIDTH]),
.s_axi_arvalid(s_axi_arvalid[m]),
.s_axi_arready(s_axi_arready[m]),
.s_axi_rid(s_axi_rid[m*S_ID_WIDTH +: S_ID_WIDTH]),
.s_axi_rdata(s_axi_rdata[m*DATA_WIDTH +: DATA_WIDTH]),
.s_axi_rresp(s_axi_rresp[m*2 +: 2]),
.s_axi_rlast(s_axi_rlast[m]),
.s_axi_ruser(s_axi_ruser[m*RUSER_WIDTH +: RUSER_WIDTH]),
.s_axi_rvalid(s_axi_rvalid[m]),
.s_axi_rready(s_axi_rready[m]),
.m_axi_arid(int_s_axi_arid[m*S_ID_WIDTH +: S_ID_WIDTH]),
.m_axi_araddr(int_s_axi_araddr[m*ADDR_WIDTH +: ADDR_WIDTH]),
.m_axi_arlen(int_s_axi_arlen[m*8 +: 8]),
.m_axi_arsize(int_s_axi_arsize[m*3 +: 3]),
.m_axi_arburst(int_s_axi_arburst[m*2 +: 2]),
.m_axi_arlock(int_s_axi_arlock[m]),
.m_axi_arcache(int_s_axi_arcache[m*4 +: 4]),
.m_axi_arprot(int_s_axi_arprot[m*3 +: 3]),
.m_axi_arqos(int_s_axi_arqos[m*4 +: 4]),
.m_axi_arregion(),
.m_axi_aruser(int_s_axi_aruser[m*ARUSER_WIDTH +: ARUSER_WIDTH]),
.m_axi_arvalid(int_s_axi_arvalid[m]),
.m_axi_arready(int_s_axi_arready[m]),
.m_axi_rid(m_axi_rid_mux),
.m_axi_rdata(m_axi_rdata_mux),
.m_axi_rresp(m_axi_rresp_mux),
.m_axi_rlast(m_axi_rlast_mux),
.m_axi_ruser(m_axi_ruser_mux),
.m_axi_rvalid(m_axi_rvalid_mux),
.m_axi_rready(m_axi_rready_mux)
);
end // s_ifaces
for (n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces
// in-flight transaction count
wire trans_start;
wire trans_complete;
reg [$clog2(M_ISSUE[n*32 +: 32]+1)-1:0] trans_count_reg = 0;
wire trans_limit = trans_count_reg >= M_ISSUE[n*32 +: 32] && !trans_complete;
always @(posedge clk) begin
if (rst) begin
trans_count_reg <= 0;
end else begin
if (trans_start && !trans_complete) begin
trans_count_reg <= trans_count_reg + 1;
end else if (!trans_start && trans_complete) begin
trans_count_reg <= trans_count_reg - 1;
end
end
end
// address arbitration
wire [S_COUNT-1:0] a_request;
wire [S_COUNT-1:0] a_acknowledge;
wire [S_COUNT-1:0] a_grant;
wire a_grant_valid;
wire [CL_S_COUNT-1:0] a_grant_encoded;
arbiter #(
.PORTS(S_COUNT),
.TYPE("ROUND_ROBIN"),
.BLOCK("ACKNOWLEDGE"),
.LSB_PRIORITY("HIGH")
)
a_arb_inst (
.clk(clk),
.rst(rst),
.request(a_request),
.acknowledge(a_acknowledge),
.grant(a_grant),
.grant_valid(a_grant_valid),
.grant_encoded(a_grant_encoded)
);
// address mux
wire [M_ID_WIDTH-1:0] s_axi_arid_mux = int_s_axi_arid[a_grant_encoded*S_ID_WIDTH +: S_ID_WIDTH] | (a_grant_encoded << S_ID_WIDTH);
wire [ADDR_WIDTH-1:0] s_axi_araddr_mux = int_s_axi_araddr[a_grant_encoded*ADDR_WIDTH +: ADDR_WIDTH];
wire [7:0] s_axi_arlen_mux = int_s_axi_arlen[a_grant_encoded*8 +: 8];
wire [2:0] s_axi_arsize_mux = int_s_axi_arsize[a_grant_encoded*3 +: 3];
wire [1:0] s_axi_arburst_mux = int_s_axi_arburst[a_grant_encoded*2 +: 2];
wire s_axi_arlock_mux = int_s_axi_arlock[a_grant_encoded];
wire [3:0] s_axi_arcache_mux = int_s_axi_arcache[a_grant_encoded*4 +: 4];
wire [2:0] s_axi_arprot_mux = int_s_axi_arprot[a_grant_encoded*3 +: 3];
wire [3:0] s_axi_arqos_mux = int_s_axi_arqos[a_grant_encoded*4 +: 4];
wire [3:0] s_axi_arregion_mux = int_s_axi_arregion[a_grant_encoded*4 +: 4];
wire [ARUSER_WIDTH-1:0] s_axi_aruser_mux = int_s_axi_aruser[a_grant_encoded*ARUSER_WIDTH +: ARUSER_WIDTH];
wire s_axi_arvalid_mux = int_axi_arvalid[a_grant_encoded*M_COUNT+n] && a_grant_valid;
wire s_axi_arready_mux;
assign int_axi_arready[n*S_COUNT +: S_COUNT] = (a_grant_valid && s_axi_arready_mux) << a_grant_encoded;
for (m = 0; m < S_COUNT; m = m + 1) begin
assign a_request[m] = int_axi_arvalid[m*M_COUNT+n] && !a_grant[m] && !trans_limit;
assign a_acknowledge[m] = a_grant[m] && int_axi_arvalid[m*M_COUNT+n] && s_axi_arready_mux;
end
assign trans_start = s_axi_arvalid_mux && s_axi_arready_mux && a_grant_valid;
// read response forwarding
wire [CL_S_COUNT-1:0] r_select = m_axi_rid[n*M_ID_WIDTH +: M_ID_WIDTH] >> S_ID_WIDTH;
assign int_axi_rvalid[n*S_COUNT +: S_COUNT] = int_m_axi_rvalid[n] << r_select;
assign int_m_axi_rready[n] = int_axi_rready[r_select*M_COUNT+n];
assign trans_complete = int_m_axi_rvalid[n] && int_m_axi_rready[n] && int_m_axi_rlast[n];
// M side register
axi_register_rd #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.ID_WIDTH(M_ID_WIDTH),
.ARUSER_ENABLE(ARUSER_ENABLE),
.ARUSER_WIDTH(ARUSER_WIDTH),
.RUSER_ENABLE(RUSER_ENABLE),
.RUSER_WIDTH(RUSER_WIDTH),
.AR_REG_TYPE(M_AR_REG_TYPE),
.R_REG_TYPE(M_R_REG_TYPE)
)
reg_inst (
.clk(clk),
.rst(rst),
.s_axi_arid(s_axi_arid_mux),
.s_axi_araddr(s_axi_araddr_mux),
.s_axi_arlen(s_axi_arlen_mux),
.s_axi_arsize(s_axi_arsize_mux),
.s_axi_arburst(s_axi_arburst_mux),
.s_axi_arlock(s_axi_arlock_mux),
.s_axi_arcache(s_axi_arcache_mux),
.s_axi_arprot(s_axi_arprot_mux),
.s_axi_arqos(s_axi_arqos_mux),
.s_axi_arregion(s_axi_arregion_mux),
.s_axi_aruser(s_axi_aruser_mux),
.s_axi_arvalid(s_axi_arvalid_mux),
.s_axi_arready(s_axi_arready_mux),
.s_axi_rid(int_m_axi_rid[n*M_ID_WIDTH +: M_ID_WIDTH]),
.s_axi_rdata(int_m_axi_rdata[n*DATA_WIDTH +: DATA_WIDTH]),
.s_axi_rresp(int_m_axi_rresp[n*2 +: 2]),
.s_axi_rlast(int_m_axi_rlast[n]),
.s_axi_ruser(int_m_axi_ruser[n*RUSER_WIDTH +: RUSER_WIDTH]),
.s_axi_rvalid(int_m_axi_rvalid[n]),
.s_axi_rready(int_m_axi_rready[n]),
.m_axi_arid(m_axi_arid[n*M_ID_WIDTH +: M_ID_WIDTH]),
.m_axi_araddr(m_axi_araddr[n*ADDR_WIDTH +: ADDR_WIDTH]),
.m_axi_arlen(m_axi_arlen[n*8 +: 8]),
.m_axi_arsize(m_axi_arsize[n*3 +: 3]),
.m_axi_arburst(m_axi_arburst[n*2 +: 2]),
.m_axi_arlock(m_axi_arlock[n]),
.m_axi_arcache(m_axi_arcache[n*4 +: 4]),
.m_axi_arprot(m_axi_arprot[n*3 +: 3]),
.m_axi_arqos(m_axi_arqos[n*4 +: 4]),
.m_axi_arregion(m_axi_arregion[n*4 +: 4]),
.m_axi_aruser(m_axi_aruser[n*ARUSER_WIDTH +: ARUSER_WIDTH]),
.m_axi_arvalid(m_axi_arvalid[n]),
.m_axi_arready(m_axi_arready[n]),
.m_axi_rid(m_axi_rid[n*M_ID_WIDTH +: M_ID_WIDTH]),
.m_axi_rdata(m_axi_rdata[n*DATA_WIDTH +: DATA_WIDTH]),
.m_axi_rresp(m_axi_rresp[n*2 +: 2]),
.m_axi_rlast(m_axi_rlast[n]),
.m_axi_ruser(m_axi_ruser[n*RUSER_WIDTH +: RUSER_WIDTH]),
.m_axi_rvalid(m_axi_rvalid[n]),
.m_axi_rready(m_axi_rready[n])
);
end // m_ifaces
endgenerate
endmodule

630
rtl/axi_crossbar_wr.v Normal file
View File

@ -0,0 +1,630 @@
/*
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 crossbar (write)
*/
module axi_crossbar_wr #
(
parameter S_COUNT = 4,
parameter M_COUNT = 4,
parameter DATA_WIDTH = 32,
parameter ADDR_WIDTH = 32,
parameter STRB_WIDTH = (DATA_WIDTH/8),
parameter S_ID_WIDTH = 8,
parameter M_ID_WIDTH = S_ID_WIDTH+$clog2(S_COUNT),
parameter AWUSER_ENABLE = 0,
parameter AWUSER_WIDTH = 1,
parameter WUSER_ENABLE = 0,
parameter WUSER_WIDTH = 1,
parameter BUSER_ENABLE = 0,
parameter BUSER_WIDTH = 1,
parameter S_THREADS = {S_COUNT{32'd2}},
parameter S_ACCEPT = {S_COUNT{32'd16}},
parameter M_REGIONS = 1,
parameter M_BASE_ADDR = {32'h03000000, 32'h02000000, 32'h01000000, 32'h00000000},
parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}},
parameter M_CONNECT = {M_COUNT{{S_COUNT{1'b1}}}},
parameter M_ISSUE = {M_COUNT{32'd4}},
parameter M_SECURE = {M_COUNT{1'b0}},
parameter S_AW_REG_TYPE = {S_COUNT{2'd0}},
parameter S_W_REG_TYPE = {S_COUNT{2'd0}},
parameter S_B_REG_TYPE = {S_COUNT{2'd1}},
parameter M_AW_REG_TYPE = {M_COUNT{2'd1}},
parameter M_W_REG_TYPE = {M_COUNT{2'd2}},
parameter M_B_REG_TYPE = {M_COUNT{2'd0}}
)
(
input wire clk,
input wire rst,
/*
* AXI slave interfaces
*/
input wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_awid,
input wire [S_COUNT*ADDR_WIDTH-1:0] s_axi_awaddr,
input wire [S_COUNT*8-1:0] s_axi_awlen,
input wire [S_COUNT*3-1:0] s_axi_awsize,
input wire [S_COUNT*2-1:0] s_axi_awburst,
input wire [S_COUNT-1:0] s_axi_awlock,
input wire [S_COUNT*4-1:0] s_axi_awcache,
input wire [S_COUNT*3-1:0] s_axi_awprot,
input wire [S_COUNT*4-1:0] s_axi_awqos,
input wire [S_COUNT*AWUSER_WIDTH-1:0] s_axi_awuser,
input wire [S_COUNT-1:0] s_axi_awvalid,
output wire [S_COUNT-1:0] s_axi_awready,
input wire [S_COUNT*DATA_WIDTH-1:0] s_axi_wdata,
input wire [S_COUNT*STRB_WIDTH-1:0] s_axi_wstrb,
input wire [S_COUNT-1:0] s_axi_wlast,
input wire [S_COUNT*WUSER_WIDTH-1:0] s_axi_wuser,
input wire [S_COUNT-1:0] s_axi_wvalid,
output wire [S_COUNT-1:0] s_axi_wready,
output wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_bid,
output wire [S_COUNT*2-1:0] s_axi_bresp,
output wire [S_COUNT*BUSER_WIDTH-1:0] s_axi_buser,
output wire [S_COUNT-1:0] s_axi_bvalid,
input wire [S_COUNT-1:0] s_axi_bready,
/*
* AXI master interfaces
*/
output wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_awid,
output wire [M_COUNT*ADDR_WIDTH-1:0] m_axi_awaddr,
output wire [M_COUNT*8-1:0] m_axi_awlen,
output wire [M_COUNT*3-1:0] m_axi_awsize,
output wire [M_COUNT*2-1:0] m_axi_awburst,
output wire [M_COUNT-1:0] m_axi_awlock,
output wire [M_COUNT*4-1:0] m_axi_awcache,
output wire [M_COUNT*3-1:0] m_axi_awprot,
output wire [M_COUNT*4-1:0] m_axi_awqos,
output wire [M_COUNT*4-1:0] m_axi_awregion,
output wire [M_COUNT*AWUSER_WIDTH-1:0] m_axi_awuser,
output wire [M_COUNT-1:0] m_axi_awvalid,
input wire [M_COUNT-1:0] m_axi_awready,
output wire [M_COUNT*DATA_WIDTH-1:0] m_axi_wdata,
output wire [M_COUNT*STRB_WIDTH-1:0] m_axi_wstrb,
output wire [M_COUNT-1:0] m_axi_wlast,
output wire [M_COUNT*WUSER_WIDTH-1:0] m_axi_wuser,
output wire [M_COUNT-1:0] m_axi_wvalid,
input wire [M_COUNT-1:0] m_axi_wready,
input wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_bid,
input wire [M_COUNT*2-1:0] m_axi_bresp,
input wire [M_COUNT*BUSER_WIDTH-1:0] m_axi_buser,
input wire [M_COUNT-1:0] m_axi_bvalid,
output wire [M_COUNT-1:0] m_axi_bready
);
parameter CL_S_COUNT = $clog2(S_COUNT);
parameter CL_M_COUNT = $clog2(M_COUNT);
parameter M_COUNT_P1 = M_COUNT+1;
parameter CL_M_COUNT_P1 = $clog2(M_COUNT_P1);
integer i;
// check configuration
initial begin
if (M_ID_WIDTH < S_ID_WIDTH+$clog2(S_COUNT)) begin
$error("Error: M_ID_WIDTH must be at least $clog2(S_COUNT) larger than S_ID_WIDTH");
$finish;
end
for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin
if (M_ADDR_WIDTH[i*32 +: 32] && (M_ADDR_WIDTH[i*32 +: 32] < 12 || M_ADDR_WIDTH[i*32 +: 32] > ADDR_WIDTH)) begin
$error("Error: value out of range");
$finish;
end
end
end
wire [S_COUNT*S_ID_WIDTH-1:0] int_s_axi_awid;
wire [S_COUNT*ADDR_WIDTH-1:0] int_s_axi_awaddr;
wire [S_COUNT*8-1:0] int_s_axi_awlen;
wire [S_COUNT*3-1:0] int_s_axi_awsize;
wire [S_COUNT*2-1:0] int_s_axi_awburst;
wire [S_COUNT-1:0] int_s_axi_awlock;
wire [S_COUNT*4-1:0] int_s_axi_awcache;
wire [S_COUNT*3-1:0] int_s_axi_awprot;
wire [S_COUNT*4-1:0] int_s_axi_awqos;
wire [S_COUNT*4-1:0] int_s_axi_awregion;
wire [S_COUNT*AWUSER_WIDTH-1:0] int_s_axi_awuser;
wire [S_COUNT-1:0] int_s_axi_awvalid;
wire [S_COUNT-1:0] int_s_axi_awready;
wire [S_COUNT*M_COUNT-1:0] int_axi_awvalid;
wire [M_COUNT*S_COUNT-1:0] int_axi_awready;
wire [S_COUNT*DATA_WIDTH-1:0] int_s_axi_wdata;
wire [S_COUNT*STRB_WIDTH-1:0] int_s_axi_wstrb;
wire [S_COUNT-1:0] int_s_axi_wlast;
wire [S_COUNT*WUSER_WIDTH-1:0] int_s_axi_wuser;
wire [S_COUNT-1:0] int_s_axi_wvalid;
wire [S_COUNT-1:0] int_s_axi_wready;
wire [S_COUNT*M_COUNT-1:0] int_axi_wvalid;
wire [M_COUNT*S_COUNT-1:0] int_axi_wready;
wire [M_COUNT*M_ID_WIDTH-1:0] int_m_axi_bid;
wire [M_COUNT*2-1:0] int_m_axi_bresp;
wire [M_COUNT*BUSER_WIDTH-1:0] int_m_axi_buser;
wire [M_COUNT-1:0] int_m_axi_bvalid;
wire [M_COUNT-1:0] int_m_axi_bready;
wire [M_COUNT*S_COUNT-1:0] int_axi_bvalid;
wire [S_COUNT*M_COUNT-1:0] int_axi_bready;
generate
genvar m, n;
for (m = 0; m < S_COUNT; m = m + 1) begin : s_ifaces
// address decode and admission control
wire [CL_M_COUNT-1:0] a_select;
wire m_axi_avalid;
wire m_axi_aready;
wire [CL_M_COUNT-1:0] m_wc_select;
wire m_wc_decerr;
wire m_wc_valid;
wire m_wc_ready;
wire m_rc_decerr;
wire m_rc_valid;
wire m_rc_ready;
wire [S_ID_WIDTH-1:0] s_cpl_id;
wire s_cpl_valid;
axi_crossbar_addr #(
.S(m),
.S_COUNT(S_COUNT),
.M_COUNT(M_COUNT),
.ADDR_WIDTH(ADDR_WIDTH),
.ID_WIDTH(S_ID_WIDTH),
.S_THREADS(S_THREADS[m*32 +: 32]),
.S_ACCEPT(S_ACCEPT[m*32 +: 32]),
.M_REGIONS(M_REGIONS),
.M_BASE_ADDR(M_BASE_ADDR),
.M_ADDR_WIDTH(M_ADDR_WIDTH),
.M_CONNECT(M_CONNECT),
.M_SECURE(M_SECURE),
.WC_OUTPUT(1)
)
addr_inst (
.clk(clk),
.rst(rst),
/*
* Address input
*/
.s_axi_aid(int_s_axi_awid[m*S_ID_WIDTH +: S_ID_WIDTH]),
.s_axi_aaddr(int_s_axi_awaddr[m*ADDR_WIDTH +: ADDR_WIDTH]),
.s_axi_aprot(int_s_axi_awprot[m*3 +: 3]),
.s_axi_aqos(int_s_axi_awqos[m*4 +: 4]),
.s_axi_avalid(int_s_axi_awvalid[m]),
.s_axi_aready(int_s_axi_awready[m]),
/*
* Address output
*/
.m_axi_aregion(int_s_axi_awregion[m*4 +: 4]),
.m_select(a_select),
.m_axi_avalid(m_axi_avalid),
.m_axi_aready(m_axi_aready),
/*
* Write command output
*/
.m_wc_select(m_wc_select),
.m_wc_decerr(m_wc_decerr),
.m_wc_valid(m_wc_valid),
.m_wc_ready(m_wc_ready),
/*
* Response command output
*/
.m_rc_decerr(m_rc_decerr),
.m_rc_valid(m_rc_valid),
.m_rc_ready(m_rc_ready),
/*
* Completion input
*/
.s_cpl_id(s_cpl_id),
.s_cpl_valid(s_cpl_valid)
);
assign int_axi_awvalid[m*M_COUNT +: M_COUNT] = m_axi_avalid << a_select;
assign m_axi_aready = int_axi_awready[a_select*S_COUNT+m];
// write command handling
reg [CL_M_COUNT-1:0] w_select_reg = 0, w_select_next;
reg w_drop_reg = 1'b0, w_drop_next;
reg w_select_valid_reg = 1'b0, w_select_valid_next;
assign m_wc_ready = !w_select_valid_reg;
always @* begin
w_select_next = w_select_reg;
w_drop_next = w_drop_reg && !(int_s_axi_wvalid[m] && int_s_axi_wready[m] && int_s_axi_wlast[m]);
w_select_valid_next = w_select_valid_reg && !(int_s_axi_wvalid[m] && int_s_axi_wready[m] && int_s_axi_wlast[m]);
if (m_wc_valid && !w_select_valid_reg) begin
w_select_next = m_wc_select;
w_drop_next = m_wc_decerr;
w_select_valid_next = m_wc_valid;
end
end
always @(posedge clk) begin
if (rst) begin
w_select_valid_reg <= 1'b0;
end else begin
w_select_valid_reg <= w_select_valid_next;
end
w_select_reg <= w_select_next;
w_drop_reg <= w_drop_next;
end
// write data forwarding
assign int_axi_wvalid[m*M_COUNT +: M_COUNT] = (int_s_axi_wvalid[m] && w_select_valid_reg && !w_drop_reg) << w_select_reg;
assign int_s_axi_wready[m] = int_axi_wready[w_select_reg*S_COUNT+m] || w_drop_reg;
// decode error handling
reg [S_ID_WIDTH-1:0] decerr_m_axi_bid_reg = {S_ID_WIDTH{1'b0}}, decerr_m_axi_bid_next;
reg decerr_m_axi_bvalid_reg = 1'b0, decerr_m_axi_bvalid_next;
wire decerr_m_axi_bready;
assign m_rc_ready = !decerr_m_axi_bvalid_reg;
always @* begin
decerr_m_axi_bid_next = decerr_m_axi_bid_reg;
decerr_m_axi_bvalid_next = decerr_m_axi_bvalid_reg;
if (decerr_m_axi_bvalid_reg) begin
if (decerr_m_axi_bready) begin
decerr_m_axi_bvalid_next = 1'b0;
end
end else if (m_rc_valid && m_rc_ready) begin
decerr_m_axi_bid_next = int_s_axi_awid[m*S_ID_WIDTH +: S_ID_WIDTH];
decerr_m_axi_bvalid_next = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
decerr_m_axi_bvalid_reg <= 1'b0;
end else begin
decerr_m_axi_bvalid_reg <= decerr_m_axi_bvalid_next;
end
decerr_m_axi_bid_reg <= decerr_m_axi_bid_next;
end
// write response arbitration
wire [M_COUNT_P1-1:0] b_request;
wire [M_COUNT_P1-1:0] b_acknowledge;
wire [M_COUNT_P1-1:0] b_grant;
wire b_grant_valid;
wire [CL_M_COUNT_P1-1:0] b_grant_encoded;
arbiter #(
.PORTS(M_COUNT_P1),
.TYPE("ROUND_ROBIN"),
.BLOCK("ACKNOWLEDGE"),
.LSB_PRIORITY("HIGH")
)
b_arb_inst (
.clk(clk),
.rst(rst),
.request(b_request),
.acknowledge(b_acknowledge),
.grant(b_grant),
.grant_valid(b_grant_valid),
.grant_encoded(b_grant_encoded)
);
// write response mux
wire [S_ID_WIDTH-1:0] m_axi_bid_mux = {decerr_m_axi_bid_reg, int_m_axi_bid} >> b_grant_encoded*M_ID_WIDTH;
wire [1:0] m_axi_bresp_mux = {2'b11, int_m_axi_bresp} >> b_grant_encoded*2;
wire [BUSER_WIDTH-1:0] m_axi_buser_mux = {{BUSER_WIDTH{1'b0}}, int_m_axi_buser} >> b_grant_encoded*BUSER_WIDTH;
wire m_axi_bvalid_mux = ({decerr_m_axi_bvalid_reg, int_m_axi_bvalid} >> b_grant_encoded) && b_grant_valid;
wire m_axi_bready_mux;
assign int_axi_bready[m*M_COUNT +: M_COUNT] = (b_grant_valid && m_axi_bready_mux) << b_grant_encoded;
assign decerr_m_axi_bready = (b_grant_valid && m_axi_bready_mux) && (b_grant_encoded == M_COUNT_P1-1);
for (n = 0; n < M_COUNT; n = n + 1) begin
assign b_request[n] = int_axi_bvalid[n*S_COUNT+m] && !b_grant[n];
assign b_acknowledge[n] = b_grant[n] && int_axi_bvalid[n*S_COUNT+m] && m_axi_bready_mux;
end
assign b_request[M_COUNT_P1-1] = decerr_m_axi_bvalid_reg && !b_grant[M_COUNT_P1-1];
assign b_acknowledge[M_COUNT_P1-1] = b_grant[M_COUNT_P1-1] && decerr_m_axi_bvalid_reg && m_axi_bready_mux;
assign s_cpl_id = m_axi_bid_mux;
assign s_cpl_valid = m_axi_bvalid_mux && m_axi_bready_mux;
// S side register
axi_register_wr #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.ID_WIDTH(S_ID_WIDTH),
.AWUSER_ENABLE(AWUSER_ENABLE),
.AWUSER_WIDTH(AWUSER_WIDTH),
.WUSER_ENABLE(WUSER_ENABLE),
.WUSER_WIDTH(WUSER_WIDTH),
.BUSER_ENABLE(BUSER_ENABLE),
.BUSER_WIDTH(BUSER_WIDTH),
.AW_REG_TYPE(S_AW_REG_TYPE[m*2 +: 2]),
.W_REG_TYPE(S_W_REG_TYPE[m*2 +: 2]),
.B_REG_TYPE(S_B_REG_TYPE[m*2 +: 2])
)
reg_inst (
.clk(clk),
.rst(rst),
.s_axi_awid(s_axi_awid[m*S_ID_WIDTH +: S_ID_WIDTH]),
.s_axi_awaddr(s_axi_awaddr[m*ADDR_WIDTH +: ADDR_WIDTH]),
.s_axi_awlen(s_axi_awlen[m*8 +: 8]),
.s_axi_awsize(s_axi_awsize[m*3 +: 3]),
.s_axi_awburst(s_axi_awburst[m*2 +: 2]),
.s_axi_awlock(s_axi_awlock[m]),
.s_axi_awcache(s_axi_awcache[m*4 +: 4]),
.s_axi_awprot(s_axi_awprot[m*3 +: 3]),
.s_axi_awqos(s_axi_awqos[m*4 +: 4]),
.s_axi_awregion(4'd0),
.s_axi_awuser(s_axi_awuser[m*AWUSER_WIDTH +: AWUSER_WIDTH]),
.s_axi_awvalid(s_axi_awvalid[m]),
.s_axi_awready(s_axi_awready[m]),
.s_axi_wdata(s_axi_wdata[m*DATA_WIDTH +: DATA_WIDTH]),
.s_axi_wstrb(s_axi_wstrb[m*STRB_WIDTH +: STRB_WIDTH]),
.s_axi_wlast(s_axi_wlast[m]),
.s_axi_wuser(s_axi_wuser[m*WUSER_WIDTH +: WUSER_WIDTH]),
.s_axi_wvalid(s_axi_wvalid[m]),
.s_axi_wready(s_axi_wready[m]),
.s_axi_bid(s_axi_bid[m*S_ID_WIDTH +: S_ID_WIDTH]),
.s_axi_bresp(s_axi_bresp[m*2 +: 2]),
.s_axi_buser(s_axi_buser[m*BUSER_WIDTH +: BUSER_WIDTH]),
.s_axi_bvalid(s_axi_bvalid[m]),
.s_axi_bready(s_axi_bready[m]),
.m_axi_awid(int_s_axi_awid[m*S_ID_WIDTH +: S_ID_WIDTH]),
.m_axi_awaddr(int_s_axi_awaddr[m*ADDR_WIDTH +: ADDR_WIDTH]),
.m_axi_awlen(int_s_axi_awlen[m*8 +: 8]),
.m_axi_awsize(int_s_axi_awsize[m*3 +: 3]),
.m_axi_awburst(int_s_axi_awburst[m*2 +: 2]),
.m_axi_awlock(int_s_axi_awlock[m]),
.m_axi_awcache(int_s_axi_awcache[m*4 +: 4]),
.m_axi_awprot(int_s_axi_awprot[m*3 +: 3]),
.m_axi_awqos(int_s_axi_awqos[m*4 +: 4]),
.m_axi_awregion(),
.m_axi_awuser(int_s_axi_awuser[m*AWUSER_WIDTH +: AWUSER_WIDTH]),
.m_axi_awvalid(int_s_axi_awvalid[m]),
.m_axi_awready(int_s_axi_awready[m]),
.m_axi_wdata(int_s_axi_wdata[m*DATA_WIDTH +: DATA_WIDTH]),
.m_axi_wstrb(int_s_axi_wstrb[m*STRB_WIDTH +: STRB_WIDTH]),
.m_axi_wlast(int_s_axi_wlast[m]),
.m_axi_wuser(int_s_axi_wuser[m*WUSER_WIDTH +: WUSER_WIDTH]),
.m_axi_wvalid(int_s_axi_wvalid[m]),
.m_axi_wready(int_s_axi_wready[m]),
.m_axi_bid(m_axi_bid_mux),
.m_axi_bresp(m_axi_bresp_mux),
.m_axi_buser(m_axi_buser_mux),
.m_axi_bvalid(m_axi_bvalid_mux),
.m_axi_bready(m_axi_bready_mux)
);
end // s_ifaces
for (n = 0; n < M_COUNT; n = n + 1) begin : m_ifaces
// in-flight transaction count
wire trans_start;
wire trans_complete;
reg [$clog2(M_ISSUE[n*32 +: 32]+1)-1:0] trans_count_reg = 0;
wire trans_limit = trans_count_reg >= M_ISSUE[n*32 +: 32] && !trans_complete;
always @(posedge clk) begin
if (rst) begin
trans_count_reg <= 0;
end else begin
if (trans_start && !trans_complete) begin
trans_count_reg <= trans_count_reg + 1;
end else if (!trans_start && trans_complete) begin
trans_count_reg <= trans_count_reg - 1;
end
end
end
// address arbitration
reg [CL_S_COUNT-1:0] w_select_reg = 0, w_select_next;
reg w_select_valid_reg = 1'b0, w_select_valid_next;
reg w_select_new_reg = 1'b0, w_select_new_next;
wire [S_COUNT-1:0] a_request;
wire [S_COUNT-1:0] a_acknowledge;
wire [S_COUNT-1:0] a_grant;
wire a_grant_valid;
wire [CL_S_COUNT-1:0] a_grant_encoded;
arbiter #(
.PORTS(S_COUNT),
.TYPE("ROUND_ROBIN"),
.BLOCK("ACKNOWLEDGE"),
.LSB_PRIORITY("HIGH")
)
a_arb_inst (
.clk(clk),
.rst(rst),
.request(a_request),
.acknowledge(a_acknowledge),
.grant(a_grant),
.grant_valid(a_grant_valid),
.grant_encoded(a_grant_encoded)
);
// address mux
wire [M_ID_WIDTH-1:0] s_axi_awid_mux = int_s_axi_awid[a_grant_encoded*S_ID_WIDTH +: S_ID_WIDTH] | (a_grant_encoded << S_ID_WIDTH);
wire [ADDR_WIDTH-1:0] s_axi_awaddr_mux = int_s_axi_awaddr[a_grant_encoded*ADDR_WIDTH +: ADDR_WIDTH];
wire [7:0] s_axi_awlen_mux = int_s_axi_awlen[a_grant_encoded*8 +: 8];
wire [2:0] s_axi_awsize_mux = int_s_axi_awsize[a_grant_encoded*3 +: 3];
wire [1:0] s_axi_awburst_mux = int_s_axi_awburst[a_grant_encoded*2 +: 2];
wire s_axi_awlock_mux = int_s_axi_awlock[a_grant_encoded];
wire [3:0] s_axi_awcache_mux = int_s_axi_awcache[a_grant_encoded*4 +: 4];
wire [2:0] s_axi_awprot_mux = int_s_axi_awprot[a_grant_encoded*3 +: 3];
wire [3:0] s_axi_awqos_mux = int_s_axi_awqos[a_grant_encoded*4 +: 4];
wire [3:0] s_axi_awregion_mux = int_s_axi_awregion[a_grant_encoded*4 +: 4];
wire [AWUSER_WIDTH-1:0] s_axi_awuser_mux = int_s_axi_awuser[a_grant_encoded*AWUSER_WIDTH +: AWUSER_WIDTH];
wire s_axi_awvalid_mux = int_axi_awvalid[a_grant_encoded*M_COUNT+n] && a_grant_valid;
wire s_axi_awready_mux;
assign int_axi_awready[n*S_COUNT +: S_COUNT] = (a_grant_valid && s_axi_awready_mux) << a_grant_encoded;
for (m = 0; m < S_COUNT; m = m + 1) begin
assign a_request[m] = int_axi_awvalid[m*M_COUNT+n] && !a_grant[m] && !trans_limit && !w_select_valid_next;
assign a_acknowledge[m] = a_grant[m] && int_axi_awvalid[m*M_COUNT+n] && s_axi_awready_mux;
end
assign trans_start = s_axi_awvalid_mux && s_axi_awready_mux && a_grant_valid;
// write data routing
always @* begin
w_select_next = w_select_reg;
w_select_valid_next = w_select_valid_reg && !(s_axi_wvalid_mux && s_axi_wready_mux && s_axi_wlast_mux);
w_select_new_next = w_select_new_reg || !a_grant_valid || a_acknowledge;
if (a_grant_valid && !w_select_valid_reg && w_select_new_reg) begin
w_select_next = a_grant_encoded;
w_select_valid_next = a_grant_valid;
w_select_new_next = 1'b0;
end
end
always @(posedge clk) begin
if (rst) begin
w_select_valid_reg <= 1'b0;
w_select_new_reg <= 1'b1;
end else begin
w_select_valid_reg <= w_select_valid_next;
w_select_new_reg <= w_select_new_next;
end
w_select_reg <= w_select_next;
end
// write data mux
wire [DATA_WIDTH-1:0] s_axi_wdata_mux = int_s_axi_wdata[w_select_reg*DATA_WIDTH +: DATA_WIDTH];
wire [STRB_WIDTH-1:0] s_axi_wstrb_mux = int_s_axi_wstrb[w_select_reg*STRB_WIDTH +: STRB_WIDTH];
wire s_axi_wlast_mux = int_s_axi_wlast[w_select_reg];
wire [WUSER_WIDTH-1:0] s_axi_wuser_mux = int_s_axi_wuser[w_select_reg*WUSER_WIDTH +: WUSER_WIDTH];
wire s_axi_wvalid_mux = int_axi_wvalid[w_select_reg*M_COUNT+n] && w_select_valid_reg;
wire s_axi_wready_mux;
assign int_axi_wready[n*S_COUNT +: S_COUNT] = (w_select_valid_reg && s_axi_wready_mux) << w_select_reg;
// write response forwarding
wire [CL_S_COUNT-1:0] b_select = m_axi_bid[n*M_ID_WIDTH +: M_ID_WIDTH] >> S_ID_WIDTH;
assign int_axi_bvalid[n*S_COUNT +: S_COUNT] = int_m_axi_bvalid[n] << b_select;
assign int_m_axi_bready[n] = int_axi_bready[b_select*M_COUNT+n];
assign trans_complete = int_m_axi_bvalid[n] && int_m_axi_bready[n];
// M side register
axi_register_wr #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.ID_WIDTH(M_ID_WIDTH),
.AWUSER_ENABLE(AWUSER_ENABLE),
.AWUSER_WIDTH(AWUSER_WIDTH),
.WUSER_ENABLE(WUSER_ENABLE),
.WUSER_WIDTH(WUSER_WIDTH),
.BUSER_ENABLE(BUSER_ENABLE),
.BUSER_WIDTH(BUSER_WIDTH),
.AW_REG_TYPE(M_AW_REG_TYPE[n*2 +: 2]),
.W_REG_TYPE(M_W_REG_TYPE[n*2 +: 2]),
.B_REG_TYPE(M_B_REG_TYPE[n*2 +: 2])
)
reg_inst (
.clk(clk),
.rst(rst),
.s_axi_awid(s_axi_awid_mux),
.s_axi_awaddr(s_axi_awaddr_mux),
.s_axi_awlen(s_axi_awlen_mux),
.s_axi_awsize(s_axi_awsize_mux),
.s_axi_awburst(s_axi_awburst_mux),
.s_axi_awlock(s_axi_awlock_mux),
.s_axi_awcache(s_axi_awcache_mux),
.s_axi_awprot(s_axi_awprot_mux),
.s_axi_awqos(s_axi_awqos_mux),
.s_axi_awregion(s_axi_awregion_mux),
.s_axi_awuser(s_axi_awuser_mux),
.s_axi_awvalid(s_axi_awvalid_mux),
.s_axi_awready(s_axi_awready_mux),
.s_axi_wdata(s_axi_wdata_mux),
.s_axi_wstrb(s_axi_wstrb_mux),
.s_axi_wlast(s_axi_wlast_mux),
.s_axi_wuser(s_axi_wuser_mux),
.s_axi_wvalid(s_axi_wvalid_mux),
.s_axi_wready(s_axi_wready_mux),
.s_axi_bid(int_m_axi_bid[n*M_ID_WIDTH +: M_ID_WIDTH]),
.s_axi_bresp(int_m_axi_bresp[n*2 +: 2]),
.s_axi_buser(int_m_axi_buser[n*BUSER_WIDTH +: BUSER_WIDTH]),
.s_axi_bvalid(int_m_axi_bvalid[n]),
.s_axi_bready(int_m_axi_bready[n]),
.m_axi_awid(m_axi_awid[n*M_ID_WIDTH +: M_ID_WIDTH]),
.m_axi_awaddr(m_axi_awaddr[n*ADDR_WIDTH +: ADDR_WIDTH]),
.m_axi_awlen(m_axi_awlen[n*8 +: 8]),
.m_axi_awsize(m_axi_awsize[n*3 +: 3]),
.m_axi_awburst(m_axi_awburst[n*2 +: 2]),
.m_axi_awlock(m_axi_awlock[n]),
.m_axi_awcache(m_axi_awcache[n*4 +: 4]),
.m_axi_awprot(m_axi_awprot[n*3 +: 3]),
.m_axi_awqos(m_axi_awqos[n*4 +: 4]),
.m_axi_awregion(m_axi_awregion[n*4 +: 4]),
.m_axi_awuser(m_axi_awuser[n*AWUSER_WIDTH +: AWUSER_WIDTH]),
.m_axi_awvalid(m_axi_awvalid[n]),
.m_axi_awready(m_axi_awready[n]),
.m_axi_wdata(m_axi_wdata[n*DATA_WIDTH +: DATA_WIDTH]),
.m_axi_wstrb(m_axi_wstrb[n*STRB_WIDTH +: STRB_WIDTH]),
.m_axi_wlast(m_axi_wlast[n]),
.m_axi_wuser(m_axi_wuser[n*WUSER_WIDTH +: WUSER_WIDTH]),
.m_axi_wvalid(m_axi_wvalid[n]),
.m_axi_wready(m_axi_wready[n]),
.m_axi_bid(m_axi_bid[n*M_ID_WIDTH +: M_ID_WIDTH]),
.m_axi_bresp(m_axi_bresp[n*2 +: 2]),
.m_axi_buser(m_axi_buser[n*BUSER_WIDTH +: BUSER_WIDTH]),
.m_axi_bvalid(m_axi_bvalid[n]),
.m_axi_bready(m_axi_bready[n])
);
end // m_ifaces
endgenerate
endmodule

788
tb/test_axi_crossbar_4x4.py Executable file
View File

@ -0,0 +1,788 @@
#!/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
import math
module = 'axi_crossbar'
testbench = 'test_%s_4x4' % module
srcs = []
srcs.append("../rtl/%s.v" % module)
srcs.append("../rtl/axi_crossbar_addr.v")
srcs.append("../rtl/axi_crossbar_rd.v")
srcs.append("../rtl/axi_crossbar_wr.v")
srcs.append("../rtl/axi_register_rd.v")
srcs.append("../rtl/axi_register_wr.v")
srcs.append("../rtl/arbiter.v")
srcs.append("../rtl/priority_encoder.v")
srcs.append("%s.v" % testbench)
src = ' '.join(srcs)
build_cmd = "iverilog -o %s.vvp %s" % (testbench, src)
def bench():
# Parameters
S_COUNT = 4
M_COUNT = 4
DATA_WIDTH = 32
ADDR_WIDTH = 32
STRB_WIDTH = (DATA_WIDTH/8)
S_ID_WIDTH = 8
M_ID_WIDTH = S_ID_WIDTH+math.ceil(math.log(M_COUNT, 2))
AWUSER_ENABLE = 0
AWUSER_WIDTH = 1
WUSER_ENABLE = 0
WUSER_WIDTH = 1
BUSER_ENABLE = 0
BUSER_WIDTH = 1
ARUSER_ENABLE = 0
ARUSER_WIDTH = 1
RUSER_ENABLE = 0
RUSER_WIDTH = 1
S_THREADS = [2]*S_COUNT
S_ACCEPT = [16]*S_COUNT
M_REGIONS = 1
M_BASE_ADDR = [0x00000000, 0x01000000, 0x02000000, 0x03000000]
M_ADDR_WIDTH = [24]*M_COUNT*M_REGIONS
M_CONNECT_READ = [0b1111]*M_COUNT
M_CONNECT_WRITE = [0b1111]*M_COUNT
M_ISSUE = [4]*M_COUNT
M_SECURE = [0]*M_COUNT
S_AW_REG_TYPE = [0]*S_COUNT
S_W_REG_TYPE = [0]*S_COUNT
S_B_REG_TYPE = [1]*S_COUNT
S_AR_REG_TYPE = [0]*S_COUNT
S_R_REG_TYPE = [1]*S_COUNT
M_AW_REG_TYPE = [1]*M_COUNT
M_W_REG_TYPE = [2]*M_COUNT
M_B_REG_TYPE = [0]*M_COUNT
M_AR_REG_TYPE = [1]*M_COUNT
M_R_REG_TYPE = [0]*M_COUNT
# Inputs
clk = Signal(bool(0))
rst = Signal(bool(0))
current_test = Signal(intbv(0)[8:])
s_axi_awid_list = [Signal(intbv(0)[S_ID_WIDTH:]) for i in range(S_COUNT)]
s_axi_awaddr_list = [Signal(intbv(0)[ADDR_WIDTH:]) for i in range(S_COUNT)]
s_axi_awlen_list = [Signal(intbv(0)[8:]) for i in range(S_COUNT)]
s_axi_awsize_list = [Signal(intbv(0)[3:]) for i in range(S_COUNT)]
s_axi_awburst_list = [Signal(intbv(0)[2:]) for i in range(S_COUNT)]
s_axi_awlock_list = [Signal(bool(0)) for i in range(S_COUNT)]
s_axi_awcache_list = [Signal(intbv(0)[4:]) for i in range(S_COUNT)]
s_axi_awprot_list = [Signal(intbv(0)[3:]) for i in range(S_COUNT)]
s_axi_awqos_list = [Signal(intbv(0)[4:]) for i in range(S_COUNT)]
s_axi_awuser_list = [Signal(intbv(0)[AWUSER_WIDTH:]) for i in range(S_COUNT)]
s_axi_awvalid_list = [Signal(bool(0)) for i in range(S_COUNT)]
s_axi_wdata_list = [Signal(intbv(0)[DATA_WIDTH:]) for i in range(S_COUNT)]
s_axi_wstrb_list = [Signal(intbv(0)[STRB_WIDTH:]) for i in range(S_COUNT)]
s_axi_wlast_list = [Signal(bool(0)) for i in range(S_COUNT)]
s_axi_wuser_list = [Signal(intbv(0)[WUSER_WIDTH:]) for i in range(S_COUNT)]
s_axi_wvalid_list = [Signal(bool(0)) for i in range(S_COUNT)]
s_axi_bready_list = [Signal(bool(0)) for i in range(S_COUNT)]
s_axi_arid_list = [Signal(intbv(0)[S_ID_WIDTH:]) for i in range(S_COUNT)]
s_axi_araddr_list = [Signal(intbv(0)[ADDR_WIDTH:]) for i in range(S_COUNT)]
s_axi_arlen_list = [Signal(intbv(0)[8:]) for i in range(S_COUNT)]
s_axi_arsize_list = [Signal(intbv(0)[3:]) for i in range(S_COUNT)]
s_axi_arburst_list = [Signal(intbv(0)[2:]) for i in range(S_COUNT)]
s_axi_arlock_list = [Signal(bool(0)) for i in range(S_COUNT)]
s_axi_arcache_list = [Signal(intbv(0)[4:]) for i in range(S_COUNT)]
s_axi_arprot_list = [Signal(intbv(0)[3:]) for i in range(S_COUNT)]
s_axi_arqos_list = [Signal(intbv(0)[4:]) for i in range(S_COUNT)]
s_axi_aruser_list = [Signal(intbv(0)[ARUSER_WIDTH:]) for i in range(S_COUNT)]
s_axi_arvalid_list = [Signal(bool(0)) for i in range(S_COUNT)]
s_axi_rready_list = [Signal(bool(0)) for i in range(S_COUNT)]
m_axi_awready_list = [Signal(bool(0)) for i in range(M_COUNT)]
m_axi_wready_list = [Signal(bool(0)) for i in range(M_COUNT)]
m_axi_bid_list = [Signal(intbv(0)[M_ID_WIDTH:]) for i in range(M_COUNT)]
m_axi_bresp_list = [Signal(intbv(0)[2:]) for i in range(M_COUNT)]
m_axi_buser_list = [Signal(intbv(0)[BUSER_WIDTH:]) for i in range(M_COUNT)]
m_axi_bvalid_list = [Signal(bool(0)) for i in range(M_COUNT)]
m_axi_arready_list = [Signal(bool(0)) for i in range(M_COUNT)]
m_axi_rid_list = [Signal(intbv(0)[M_ID_WIDTH:]) for i in range(M_COUNT)]
m_axi_rdata_list = [Signal(intbv(0)[DATA_WIDTH:]) for i in range(M_COUNT)]
m_axi_rresp_list = [Signal(intbv(0)[2:]) for i in range(M_COUNT)]
m_axi_rlast_list = [Signal(bool(0)) for i in range(M_COUNT)]
m_axi_ruser_list = [Signal(intbv(0)[RUSER_WIDTH:]) for i in range(M_COUNT)]
m_axi_rvalid_list = [Signal(bool(0)) for i in range(M_COUNT)]
s_axi_awid = ConcatSignal(*reversed(s_axi_awid_list))
s_axi_awaddr = ConcatSignal(*reversed(s_axi_awaddr_list))
s_axi_awlen = ConcatSignal(*reversed(s_axi_awlen_list))
s_axi_awsize = ConcatSignal(*reversed(s_axi_awsize_list))
s_axi_awburst = ConcatSignal(*reversed(s_axi_awburst_list))
s_axi_awlock = ConcatSignal(*reversed(s_axi_awlock_list))
s_axi_awcache = ConcatSignal(*reversed(s_axi_awcache_list))
s_axi_awprot = ConcatSignal(*reversed(s_axi_awprot_list))
s_axi_awqos = ConcatSignal(*reversed(s_axi_awqos_list))
s_axi_awuser = ConcatSignal(*reversed(s_axi_awuser_list))
s_axi_awvalid = ConcatSignal(*reversed(s_axi_awvalid_list))
s_axi_wdata = ConcatSignal(*reversed(s_axi_wdata_list))
s_axi_wstrb = ConcatSignal(*reversed(s_axi_wstrb_list))
s_axi_wlast = ConcatSignal(*reversed(s_axi_wlast_list))
s_axi_wuser = ConcatSignal(*reversed(s_axi_wuser_list))
s_axi_wvalid = ConcatSignal(*reversed(s_axi_wvalid_list))
s_axi_bready = ConcatSignal(*reversed(s_axi_bready_list))
s_axi_arid = ConcatSignal(*reversed(s_axi_arid_list))
s_axi_araddr = ConcatSignal(*reversed(s_axi_araddr_list))
s_axi_arlen = ConcatSignal(*reversed(s_axi_arlen_list))
s_axi_arsize = ConcatSignal(*reversed(s_axi_arsize_list))
s_axi_arburst = ConcatSignal(*reversed(s_axi_arburst_list))
s_axi_arlock = ConcatSignal(*reversed(s_axi_arlock_list))
s_axi_arcache = ConcatSignal(*reversed(s_axi_arcache_list))
s_axi_arprot = ConcatSignal(*reversed(s_axi_arprot_list))
s_axi_arqos = ConcatSignal(*reversed(s_axi_arqos_list))
s_axi_aruser = ConcatSignal(*reversed(s_axi_aruser_list))
s_axi_arvalid = ConcatSignal(*reversed(s_axi_arvalid_list))
s_axi_rready = ConcatSignal(*reversed(s_axi_rready_list))
m_axi_awready = ConcatSignal(*reversed(m_axi_awready_list))
m_axi_wready = ConcatSignal(*reversed(m_axi_wready_list))
m_axi_bid = ConcatSignal(*reversed(m_axi_bid_list))
m_axi_bresp = ConcatSignal(*reversed(m_axi_bresp_list))
m_axi_buser = ConcatSignal(*reversed(m_axi_buser_list))
m_axi_bvalid = ConcatSignal(*reversed(m_axi_bvalid_list))
m_axi_arready = ConcatSignal(*reversed(m_axi_arready_list))
m_axi_rid = ConcatSignal(*reversed(m_axi_rid_list))
m_axi_rdata = ConcatSignal(*reversed(m_axi_rdata_list))
m_axi_rresp = ConcatSignal(*reversed(m_axi_rresp_list))
m_axi_rlast = ConcatSignal(*reversed(m_axi_rlast_list))
m_axi_ruser = ConcatSignal(*reversed(m_axi_ruser_list))
m_axi_rvalid = ConcatSignal(*reversed(m_axi_rvalid_list))
# Outputs
s_axi_awready = Signal(intbv(0)[S_COUNT:])
s_axi_wready = Signal(intbv(0)[S_COUNT:])
s_axi_bid = Signal(intbv(0)[S_COUNT*S_ID_WIDTH:])
s_axi_bresp = Signal(intbv(0)[S_COUNT*2:])
s_axi_buser = Signal(intbv(0)[S_COUNT*BUSER_WIDTH:])
s_axi_bvalid = Signal(intbv(0)[S_COUNT:])
s_axi_arready = Signal(intbv(0)[S_COUNT:])
s_axi_rid = Signal(intbv(0)[S_COUNT*S_ID_WIDTH:])
s_axi_rdata = Signal(intbv(0)[S_COUNT*DATA_WIDTH:])
s_axi_rresp = Signal(intbv(0)[S_COUNT*2:])
s_axi_rlast = Signal(intbv(0)[S_COUNT:])
s_axi_ruser = Signal(intbv(0)[S_COUNT*RUSER_WIDTH:])
s_axi_rvalid = Signal(intbv(0)[S_COUNT:])
m_axi_awid = Signal(intbv(0)[M_COUNT*M_ID_WIDTH:])
m_axi_awaddr = Signal(intbv(0)[M_COUNT*ADDR_WIDTH:])
m_axi_awlen = Signal(intbv(0)[M_COUNT*8:])
m_axi_awsize = Signal(intbv(0)[M_COUNT*3:])
m_axi_awburst = Signal(intbv(0)[M_COUNT*2:])
m_axi_awlock = Signal(intbv(0)[M_COUNT:])
m_axi_awcache = Signal(intbv(0)[M_COUNT*4:])
m_axi_awprot = Signal(intbv(0)[M_COUNT*3:])
m_axi_awqos = Signal(intbv(0)[M_COUNT*4:])
m_axi_awregion = Signal(intbv(0)[M_COUNT*4:])
m_axi_awuser = Signal(intbv(0)[M_COUNT*AWUSER_WIDTH:])
m_axi_awvalid = Signal(intbv(0)[M_COUNT:])
m_axi_wdata = Signal(intbv(0)[M_COUNT*DATA_WIDTH:])
m_axi_wstrb = Signal(intbv(0)[M_COUNT*STRB_WIDTH:])
m_axi_wlast = Signal(intbv(0)[M_COUNT:])
m_axi_wuser = Signal(intbv(0)[M_COUNT*WUSER_WIDTH:])
m_axi_wvalid = Signal(intbv(0)[M_COUNT:])
m_axi_bready = Signal(intbv(0)[M_COUNT:])
m_axi_arid = Signal(intbv(0)[M_COUNT*M_ID_WIDTH:])
m_axi_araddr = Signal(intbv(0)[M_COUNT*ADDR_WIDTH:])
m_axi_arlen = Signal(intbv(0)[M_COUNT*8:])
m_axi_arsize = Signal(intbv(0)[M_COUNT*3:])
m_axi_arburst = Signal(intbv(0)[M_COUNT*2:])
m_axi_arlock = Signal(intbv(0)[M_COUNT:])
m_axi_arcache = Signal(intbv(0)[M_COUNT*4:])
m_axi_arprot = Signal(intbv(0)[M_COUNT*3:])
m_axi_arqos = Signal(intbv(0)[M_COUNT*4:])
m_axi_arregion = Signal(intbv(0)[M_COUNT*4:])
m_axi_aruser = Signal(intbv(0)[M_COUNT*ARUSER_WIDTH:])
m_axi_arvalid = Signal(intbv(0)[M_COUNT:])
m_axi_rready = Signal(intbv(0)[M_COUNT:])
s_axi_awready_list = [s_axi_awready(i) for i in range(S_COUNT)]
s_axi_wready_list = [s_axi_wready(i) for i in range(S_COUNT)]
s_axi_bid_list = [s_axi_bid((i+1)*S_ID_WIDTH, i*S_ID_WIDTH) for i in range(S_COUNT)]
s_axi_bresp_list = [s_axi_bresp((i+1)*2, i*2) for i in range(S_COUNT)]
s_axi_buser_list = [s_axi_buser((i+1)*BUSER_WIDTH, i*BUSER_WIDTH) for i in range(S_COUNT)]
s_axi_bvalid_list = [s_axi_bvalid(i) for i in range(S_COUNT)]
s_axi_arready_list = [s_axi_arready(i) for i in range(S_COUNT)]
s_axi_rid_list = [s_axi_rid((i+1)*S_ID_WIDTH, i*S_ID_WIDTH) for i in range(S_COUNT)]
s_axi_rdata_list = [s_axi_rdata((i+1)*DATA_WIDTH, i*DATA_WIDTH) for i in range(S_COUNT)]
s_axi_rresp_list = [s_axi_rresp((i+1)*2, i*2) for i in range(S_COUNT)]
s_axi_rlast_list = [s_axi_rlast(i) for i in range(S_COUNT)]
s_axi_ruser_list = [s_axi_ruser((i+1)*RUSER_WIDTH, i*RUSER_WIDTH) for i in range(S_COUNT)]
s_axi_rvalid_list = [s_axi_rvalid(i) for i in range(S_COUNT)]
m_axi_awid_list = [m_axi_awid((i+1)*M_ID_WIDTH, i*M_ID_WIDTH) for i in range(M_COUNT)]
m_axi_awaddr_list = [m_axi_awaddr((i+1)*ADDR_WIDTH, i*ADDR_WIDTH) for i in range(M_COUNT)]
m_axi_awlen_list = [m_axi_awlen((i+1)*8, i*8) for i in range(M_COUNT)]
m_axi_awsize_list = [m_axi_awsize((i+1)*3, i*3) for i in range(M_COUNT)]
m_axi_awburst_list = [m_axi_awburst((i+1)*2, i*2) for i in range(M_COUNT)]
m_axi_awlock_list = [m_axi_awlock(i) for i in range(M_COUNT)]
m_axi_awcache_list = [m_axi_awcache((i+1)*4, i*4) for i in range(M_COUNT)]
m_axi_awprot_list = [m_axi_awprot((i+1)*3, i*3) for i in range(M_COUNT)]
m_axi_awqos_list = [m_axi_awqos((i+1)*4, i*4) for i in range(M_COUNT)]
m_axi_awregion_list = [m_axi_awregion((i+1)*4, i*4) for i in range(M_COUNT)]
m_axi_awuser_list = [m_axi_awuser((i+1)*AWUSER_WIDTH, i*AWUSER_WIDTH) for i in range(M_COUNT)]
m_axi_awvalid_list = [m_axi_awvalid(i) for i in range(M_COUNT)]
m_axi_wdata_list = [m_axi_wdata((i+1)*DATA_WIDTH, i*DATA_WIDTH) for i in range(M_COUNT)]
m_axi_wstrb_list = [m_axi_wstrb((i+1)*STRB_WIDTH, i*STRB_WIDTH) for i in range(M_COUNT)]
m_axi_wlast_list = [m_axi_wlast(i) for i in range(M_COUNT)]
m_axi_wuser_list = [m_axi_wuser((i+1)*WUSER_WIDTH, i*WUSER_WIDTH) for i in range(M_COUNT)]
m_axi_wvalid_list = [m_axi_wvalid(i) for i in range(M_COUNT)]
m_axi_bready_list = [m_axi_bready(i) for i in range(M_COUNT)]
m_axi_arid_list = [m_axi_arid((i+1)*M_ID_WIDTH, i*M_ID_WIDTH) for i in range(M_COUNT)]
m_axi_araddr_list = [m_axi_araddr((i+1)*ADDR_WIDTH, i*ADDR_WIDTH) for i in range(M_COUNT)]
m_axi_arlen_list = [m_axi_arlen((i+1)*8, i*8) for i in range(M_COUNT)]
m_axi_arsize_list = [m_axi_arsize((i+1)*3, i*3) for i in range(M_COUNT)]
m_axi_arburst_list = [m_axi_arburst((i+1)*2, i*2) for i in range(M_COUNT)]
m_axi_arlock_list = [m_axi_arlock(i) for i in range(M_COUNT)]
m_axi_arcache_list = [m_axi_arcache((i+1)*4, i*4) for i in range(M_COUNT)]
m_axi_arprot_list = [m_axi_arprot((i+1)*3, i*3) for i in range(M_COUNT)]
m_axi_arqos_list = [m_axi_arqos((i+1)*4, i*4) for i in range(M_COUNT)]
m_axi_arregion_list = [m_axi_arregion((i+1)*4, i*4) for i in range(M_COUNT)]
m_axi_aruser_list = [m_axi_aruser((i+1)*ARUSER_WIDTH, i*ARUSER_WIDTH) for i in range(M_COUNT)]
m_axi_arvalid_list = [m_axi_arvalid(i) for i in range(M_COUNT)]
m_axi_rready_list = [m_axi_rready(i) for i in range(M_COUNT)]
# AXI4 masters
axi_master_inst_list = []
axi_master_pause_list = []
axi_master_logic = []
for k in range(S_COUNT):
m = axi.AXIMaster()
p = Signal(bool(False))
axi_master_inst_list.append(m)
axi_master_pause_list.append(p)
axi_master_logic.append(m.create_logic(
clk,
rst,
m_axi_awid=s_axi_awid_list[k],
m_axi_awaddr=s_axi_awaddr_list[k],
m_axi_awlen=s_axi_awlen_list[k],
m_axi_awsize=s_axi_awsize_list[k],
m_axi_awburst=s_axi_awburst_list[k],
m_axi_awlock=s_axi_awlock_list[k],
m_axi_awcache=s_axi_awcache_list[k],
m_axi_awprot=s_axi_awprot_list[k],
m_axi_awqos=s_axi_awqos_list[k],
m_axi_awvalid=s_axi_awvalid_list[k],
m_axi_awready=s_axi_awready_list[k],
m_axi_wdata=s_axi_wdata_list[k],
m_axi_wstrb=s_axi_wstrb_list[k],
m_axi_wlast=s_axi_wlast_list[k],
m_axi_wvalid=s_axi_wvalid_list[k],
m_axi_wready=s_axi_wready_list[k],
m_axi_bid=s_axi_bid_list[k],
m_axi_bresp=s_axi_bresp_list[k],
m_axi_bvalid=s_axi_bvalid_list[k],
m_axi_bready=s_axi_bready_list[k],
m_axi_arid=s_axi_arid_list[k],
m_axi_araddr=s_axi_araddr_list[k],
m_axi_arlen=s_axi_arlen_list[k],
m_axi_arsize=s_axi_arsize_list[k],
m_axi_arburst=s_axi_arburst_list[k],
m_axi_arlock=s_axi_arlock_list[k],
m_axi_arcache=s_axi_arcache_list[k],
m_axi_arprot=s_axi_arprot_list[k],
m_axi_arqos=s_axi_arqos_list[k],
m_axi_arvalid=s_axi_arvalid_list[k],
m_axi_arready=s_axi_arready_list[k],
m_axi_rid=s_axi_rid_list[k],
m_axi_rdata=s_axi_rdata_list[k],
m_axi_rresp=s_axi_rresp_list[k],
m_axi_rlast=s_axi_rlast_list[k],
m_axi_rvalid=s_axi_rvalid_list[k],
m_axi_rready=s_axi_rready_list[k],
pause=p,
name='master_%d' % k
))
# AXI4 RAM models
axi_ram_inst_list = []
axi_ram_pause_list = []
axi_ram_logic = []
for k in range(M_COUNT):
r = axi.AXIRam(2**16)
p = Signal(bool(False))
axi_ram_inst_list.append(r)
axi_ram_pause_list.append(p)
axi_ram_logic.append(r.create_port(
clk,
s_axi_awid=m_axi_awid_list[k],
s_axi_awaddr=m_axi_awaddr_list[k],
s_axi_awlen=m_axi_awlen_list[k],
s_axi_awsize=m_axi_awsize_list[k],
s_axi_awburst=m_axi_awburst_list[k],
s_axi_awlock=m_axi_awlock_list[k],
s_axi_awcache=m_axi_awcache_list[k],
s_axi_awprot=m_axi_awprot_list[k],
s_axi_awvalid=m_axi_awvalid_list[k],
s_axi_awready=m_axi_awready_list[k],
s_axi_wdata=m_axi_wdata_list[k],
s_axi_wstrb=m_axi_wstrb_list[k],
s_axi_wlast=m_axi_wlast_list[k],
s_axi_wvalid=m_axi_wvalid_list[k],
s_axi_wready=m_axi_wready_list[k],
s_axi_bid=m_axi_bid_list[k],
s_axi_bresp=m_axi_bresp_list[k],
s_axi_bvalid=m_axi_bvalid_list[k],
s_axi_bready=m_axi_bready_list[k],
s_axi_arid=m_axi_arid_list[k],
s_axi_araddr=m_axi_araddr_list[k],
s_axi_arlen=m_axi_arlen_list[k],
s_axi_arsize=m_axi_arsize_list[k],
s_axi_arburst=m_axi_arburst_list[k],
s_axi_arlock=m_axi_arlock_list[k],
s_axi_arcache=m_axi_arcache_list[k],
s_axi_arprot=m_axi_arprot_list[k],
s_axi_arvalid=m_axi_arvalid_list[k],
s_axi_arready=m_axi_arready_list[k],
s_axi_rid=m_axi_rid_list[k],
s_axi_rdata=m_axi_rdata_list[k],
s_axi_rresp=m_axi_rresp_list[k],
s_axi_rlast=m_axi_rlast_list[k],
s_axi_rvalid=m_axi_rvalid_list[k],
s_axi_rready=m_axi_rready_list[k],
pause=p,
name='ram_%d' % k
))
# 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_awqos=s_axi_awqos,
s_axi_awuser=s_axi_awuser,
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_wuser=s_axi_wuser,
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_buser=s_axi_buser,
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_arqos=s_axi_arqos,
s_axi_aruser=s_axi_aruser,
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_ruser=s_axi_ruser,
s_axi_rvalid=s_axi_rvalid,
s_axi_rready=s_axi_rready,
m_axi_awid=m_axi_awid,
m_axi_awaddr=m_axi_awaddr,
m_axi_awlen=m_axi_awlen,
m_axi_awsize=m_axi_awsize,
m_axi_awburst=m_axi_awburst,
m_axi_awlock=m_axi_awlock,
m_axi_awcache=m_axi_awcache,
m_axi_awprot=m_axi_awprot,
m_axi_awqos=m_axi_awqos,
m_axi_awregion=m_axi_awregion,
m_axi_awuser=m_axi_awuser,
m_axi_awvalid=m_axi_awvalid,
m_axi_awready=m_axi_awready,
m_axi_wdata=m_axi_wdata,
m_axi_wstrb=m_axi_wstrb,
m_axi_wlast=m_axi_wlast,
m_axi_wuser=m_axi_wuser,
m_axi_wvalid=m_axi_wvalid,
m_axi_wready=m_axi_wready,
m_axi_bid=m_axi_bid,
m_axi_bresp=m_axi_bresp,
m_axi_buser=m_axi_buser,
m_axi_bvalid=m_axi_bvalid,
m_axi_bready=m_axi_bready,
m_axi_arid=m_axi_arid,
m_axi_araddr=m_axi_araddr,
m_axi_arlen=m_axi_arlen,
m_axi_arsize=m_axi_arsize,
m_axi_arburst=m_axi_arburst,
m_axi_arlock=m_axi_arlock,
m_axi_arcache=m_axi_arcache,
m_axi_arprot=m_axi_arprot,
m_axi_arqos=m_axi_arqos,
m_axi_arregion=m_axi_arregion,
m_axi_aruser=m_axi_aruser,
m_axi_arvalid=m_axi_arvalid,
m_axi_arready=m_axi_arready,
m_axi_rid=m_axi_rid,
m_axi_rdata=m_axi_rdata,
m_axi_rresp=m_axi_rresp,
m_axi_rlast=m_axi_rlast,
m_axi_ruser=m_axi_ruser,
m_axi_rvalid=m_axi_rvalid,
m_axi_rready=m_axi_rready
)
@always(delay(4))
def clkgen():
clk.next = not clk
def wait_normal():
while not all([axi_master_inst_list[k].idle() for k in range(S_COUNT)]):
yield clk.posedge
def wait_pause_master():
while not all([axi_master_inst_list[k].idle() for k in range(S_COUNT)]):
for k in range(S_COUNT):
axi_master_pause_list[k].next = True
yield clk.posedge
yield clk.posedge
yield clk.posedge
for k in range(S_COUNT):
axi_master_pause_list[k].next = False
yield clk.posedge
def wait_pause_slave():
while not all([axi_master_inst_list[k].idle() for k in range(S_COUNT)]):
for k in range(M_COUNT):
axi_ram_pause_list[k].next = True
yield clk.posedge
yield clk.posedge
yield clk.posedge
for k in range(M_COUNT):
axi_ram_pause_list[k].next = False
yield clk.posedge
@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: write")
current_test.next = 1
addr = 4
test_data = b'\x11\x22\x33\x44'
axi_master_inst_list[0].init_write(addr, test_data)
yield axi_master_inst_list[0].wait()
yield clk.posedge
data = axi_ram_inst_list[0].read_mem(addr&0xffffff80, 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_list[0].read_mem(addr, len(test_data)) == test_data
yield delay(100)
yield clk.posedge
print("test 2: read")
current_test.next = 2
addr = 4
test_data = b'\x11\x22\x33\x44'
axi_ram_inst_list[0].write_mem(addr, test_data)
axi_master_inst_list[0].init_read(addr, len(test_data))
yield axi_master_inst_list[0].wait()
yield clk.posedge
data = axi_master_inst_list[0].get_read_data()
assert data[0] == addr
assert data[1] == test_data
yield delay(100)
yield clk.posedge
print("test 3: one to many")
current_test.next = 3
addr = 4
test_data = b'\x11\x22\x33\x44'
for k in range(S_COUNT):
axi_master_inst_list[0].init_write(addr+M_BASE_ADDR[k], test_data)
yield axi_master_inst_list[0].wait()
yield clk.posedge
for k in range(S_COUNT):
data = axi_ram_inst_list[k].read_mem(addr&0xffffff80, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
for k in range(S_COUNT):
assert axi_ram_inst_list[k].read_mem(addr, len(test_data)) == test_data
for k in range(S_COUNT):
axi_master_inst_list[0].init_read(addr+M_BASE_ADDR[k], len(test_data))
yield axi_master_inst_list[0].wait()
yield clk.posedge
for k in range(S_COUNT):
data = axi_master_inst_list[0].get_read_data()
assert data[0] == addr+M_BASE_ADDR[k]
assert data[1] == test_data
yield delay(100)
yield clk.posedge
print("test 4: many to one")
current_test.next = 4
for k in range(M_COUNT):
axi_master_inst_list[k].init_write(k*4, bytearray([(k+1)*17]*4))
for k in range(M_COUNT):
yield axi_master_inst_list[k].wait()
yield clk.posedge
data = axi_ram_inst_list[0].read_mem(addr&0xffffff80, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
for k in range(M_COUNT):
assert axi_ram_inst_list[0].read_mem(k*4, 4) == bytearray([(k+1)*17]*4)
for k in range(M_COUNT):
axi_master_inst_list[k].init_read(k*4, 4)
for k in range(M_COUNT):
yield axi_master_inst_list[k].wait()
yield clk.posedge
for k in range(M_COUNT):
data = axi_master_inst_list[k].get_read_data()
assert data[0] == k*4
assert data[1] == bytearray([(k+1)*17]*4)
yield delay(100)
yield clk.posedge
print("test 10: transaction limit and ordering test")
current_test.next = 10
length = 256
test_data = bytearray([x%256 for x in range(length)])
for k in range(10):
axi_master_inst_list[0].init_write(length*k+M_BASE_ADDR[0], bytearray([k+1]*length))
yield axi_master_inst_list[0].wait()
yield clk.posedge
for k in range(10):
data = axi_ram_inst_list[0].read_mem((length*k)&0xffffff80, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))
for k in range(10):
assert axi_ram_inst_list[0].read_mem(length*k, length) == bytearray([k+1]*length)
for k in range(10):
axi_master_inst_list[0].init_read(length*k+M_BASE_ADDR[0], length)
yield axi_master_inst_list[0].wait()
yield clk.posedge
for k in range(10):
data = axi_master_inst_list[0].get_read_data()
assert data[0] == length*k+M_BASE_ADDR[0]
assert data[1] == bytearray([k+1]*length)
yield delay(100)
yield clk.posedge
print("test 5: various writes")
current_test.next = 5
for length in list(range(1,8))+[1024]:
for offset in list(range(4,8))+[4096-4]:
for wait in wait_normal, wait_pause_master, wait_pause_slave:
print("length %d, offset %d"% (length, offset))
#addr = 256*(16*offset+length)+offset
addr = offset
test_data = bytearray([x%256 for x in range(length)])
axi_ram_inst_list[0].write_mem(addr&0xffffff80, b'\xAA'*(length+256))
axi_master_inst_list[0].init_write(addr, test_data)
yield wait()
yield clk.posedge
data = axi_ram_inst_list[0].read_mem(addr&0xffffff80, 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_list[0].read_mem(addr, length) == test_data
assert axi_ram_inst_list[0].read_mem(addr-1, 1) == b'\xAA'
assert axi_ram_inst_list[0].read_mem(addr+length, 1) == b'\xAA'
yield delay(100)
yield clk.posedge
print("test 6: various reads")
current_test.next = 6
for length in list(range(1,8))+[1024]:
for offset in list(range(4,8))+[4096-4]:
for wait in wait_normal, wait_pause_master, wait_pause_slave:
print("length %d, offset %d"% (length, offset))
#addr = 256*(16*offset+length)+offset
addr = offset
test_data = bytearray([x%256 for x in range(length)])
axi_ram_inst_list[0].write_mem(addr, test_data)
axi_master_inst_list[0].init_read(addr, length)
yield wait()
yield clk.posedge
data = axi_master_inst_list[0].get_read_data()
assert data[0] == addr
assert data[1] == test_data
yield delay(100)
yield clk.posedge
print("test 7: concurrent operations")
current_test.next = 7
for count in [1, 2, 4, 8]:
for stride in [2, 3, 5, 7]:
for wait in wait_normal, wait_pause_master, wait_pause_slave:
print("count %d, stride %d"% (count, stride))
for k in range(S_COUNT):
for l in range(count):
ram = ((k*61+l)*stride)%M_COUNT
offset = k*256+l*4
axi_ram_inst_list[ram].write_mem(offset, b'\xAA'*4)
axi_master_inst_list[k].init_write(M_BASE_ADDR[ram]+offset, bytearray([0xaa, k, l, 0xaa]))
ram = ((k*61+l+67)*stride)%M_COUNT
offset = k*256+l*4
axi_ram_inst_list[ram].write_mem(offset+0x8000, bytearray([0xaa, k, l, 0xaa]))
axi_master_inst_list[k].init_read(M_BASE_ADDR[ram]+offset+0x8000, 4)
yield wait()
yield clk.posedge
for k in range(S_COUNT):
for l in range(count):
ram = ((k*61+l)*stride)%M_COUNT
offset = k*256+l*4
axi_ram_inst_list[ram].read_mem(offset, 4) == bytearray([0xaa, k, l, 0xaa])
ram = ((k*61+l+67)*stride)%M_COUNT
offset = k*256+l*4
data = axi_master_inst_list[k].get_read_data()
assert data[0] == M_BASE_ADDR[ram]+offset+0x8000
assert data[1] == bytearray([0xaa, k, l, 0xaa])
yield delay(100)
yield clk.posedge
print("test 8: bad write")
current_test.next = 8
axi_master_inst_list[0].init_write(0xff000000, b'\xDE\xAD\xBE\xEF')
yield axi_master_inst_list[0].wait()
yield clk.posedge
yield delay(100)
yield clk.posedge
print("test 9: bad read")
current_test.next = 9
axi_master_inst_list[0].init_read(0xff000000, 4)
yield axi_master_inst_list[0].wait()
yield clk.posedge
data = axi_master_inst_list[0].get_read_data()
assert data[0] == 0xff000000
yield delay(100)
raise StopSimulation
return instances()
def test_bench():
sim = Simulation(bench())
sim.run()
if __name__ == '__main__':
print("Running test...")
test_bench()

396
tb/test_axi_crossbar_4x4.v Normal file
View File

@ -0,0 +1,396 @@
/*
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_crossbar
*/
module test_axi_crossbar_4x4;
// Parameters
parameter S_COUNT = 4;
parameter M_COUNT = 4;
parameter DATA_WIDTH = 32;
parameter ADDR_WIDTH = 32;
parameter STRB_WIDTH = (DATA_WIDTH/8);
parameter S_ID_WIDTH = 8;
parameter M_ID_WIDTH = S_ID_WIDTH+$clog2(S_COUNT);
parameter AWUSER_ENABLE = 0;
parameter AWUSER_WIDTH = 1;
parameter WUSER_ENABLE = 0;
parameter WUSER_WIDTH = 1;
parameter BUSER_ENABLE = 0;
parameter BUSER_WIDTH = 1;
parameter ARUSER_ENABLE = 0;
parameter ARUSER_WIDTH = 1;
parameter RUSER_ENABLE = 0;
parameter RUSER_WIDTH = 1;
parameter S_THREADS = {S_COUNT{32'd2}};
parameter S_ACCEPT = {S_COUNT{32'd16}};
parameter M_REGIONS = 1;
parameter M_BASE_ADDR = {32'h03000000, 32'h02000000, 32'h01000000, 32'h00000000};
parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}};
parameter M_CONNECT_READ = {M_COUNT{{S_COUNT{1'b1}}}};
parameter M_CONNECT_WRITE = {M_COUNT{{S_COUNT{1'b1}}}};
parameter M_ISSUE = {M_COUNT{32'd4}};
parameter M_SECURE = {M_COUNT{1'b0}};
parameter S_AW_REG_TYPE = {S_COUNT{2'd0}};
parameter S_W_REG_TYPE = {S_COUNT{2'd0}};
parameter S_B_REG_TYPE = {S_COUNT{2'd1}};
parameter S_AR_REG_TYPE = {S_COUNT{2'd0}};
parameter S_R_REG_TYPE = {S_COUNT{2'd1}};
parameter M_AW_REG_TYPE = {M_COUNT{2'd1}};
parameter M_W_REG_TYPE = {M_COUNT{2'd2}};
parameter M_B_REG_TYPE = {M_COUNT{2'd0}};
parameter M_AR_REG_TYPE = {M_COUNT{2'd1}};
parameter M_R_REG_TYPE = {M_COUNT{2'd0}};
// Inputs
reg clk = 0;
reg rst = 0;
reg [7:0] current_test = 0;
reg [S_COUNT*S_ID_WIDTH-1:0] s_axi_awid = 0;
reg [S_COUNT*ADDR_WIDTH-1:0] s_axi_awaddr = 0;
reg [S_COUNT*8-1:0] s_axi_awlen = 0;
reg [S_COUNT*3-1:0] s_axi_awsize = 0;
reg [S_COUNT*2-1:0] s_axi_awburst = 0;
reg [S_COUNT-1:0] s_axi_awlock = 0;
reg [S_COUNT*4-1:0] s_axi_awcache = 0;
reg [S_COUNT*3-1:0] s_axi_awprot = 0;
reg [S_COUNT*4-1:0] s_axi_awqos = 0;
reg [S_COUNT*AWUSER_WIDTH-1:0] s_axi_awuser = 0;
reg [S_COUNT-1:0] s_axi_awvalid = 0;
reg [S_COUNT*DATA_WIDTH-1:0] s_axi_wdata = 0;
reg [S_COUNT*STRB_WIDTH-1:0] s_axi_wstrb = 0;
reg [S_COUNT-1:0] s_axi_wlast = 0;
reg [S_COUNT*WUSER_WIDTH-1:0] s_axi_wuser = 0;
reg [S_COUNT-1:0] s_axi_wvalid = 0;
reg [S_COUNT-1:0] s_axi_bready = 0;
reg [S_COUNT*S_ID_WIDTH-1:0] s_axi_arid = 0;
reg [S_COUNT*ADDR_WIDTH-1:0] s_axi_araddr = 0;
reg [S_COUNT*8-1:0] s_axi_arlen = 0;
reg [S_COUNT*3-1:0] s_axi_arsize = 0;
reg [S_COUNT*2-1:0] s_axi_arburst = 0;
reg [S_COUNT-1:0] s_axi_arlock = 0;
reg [S_COUNT*4-1:0] s_axi_arcache = 0;
reg [S_COUNT*3-1:0] s_axi_arprot = 0;
reg [S_COUNT*4-1:0] s_axi_arqos = 0;
reg [S_COUNT*ARUSER_WIDTH-1:0] s_axi_aruser = 0;
reg [S_COUNT-1:0] s_axi_arvalid = 0;
reg [S_COUNT-1:0] s_axi_rready = 0;
reg [M_COUNT-1:0] m_axi_awready = 0;
reg [M_COUNT-1:0] m_axi_wready = 0;
reg [M_COUNT*M_ID_WIDTH-1:0] m_axi_bid = 0;
reg [M_COUNT*2-1:0] m_axi_bresp = 0;
reg [M_COUNT*BUSER_WIDTH-1:0] m_axi_buser = 0;
reg [M_COUNT-1:0] m_axi_bvalid = 0;
reg [M_COUNT-1:0] m_axi_arready = 0;
reg [M_COUNT*M_ID_WIDTH-1:0] m_axi_rid = 0;
reg [M_COUNT*DATA_WIDTH-1:0] m_axi_rdata = 0;
reg [M_COUNT*2-1:0] m_axi_rresp = 0;
reg [M_COUNT-1:0] m_axi_rlast = 0;
reg [M_COUNT*RUSER_WIDTH-1:0] m_axi_ruser = 0;
reg [M_COUNT-1:0] m_axi_rvalid = 0;
// Outputs
wire [S_COUNT-1:0] s_axi_awready;
wire [S_COUNT-1:0] s_axi_wready;
wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_bid;
wire [S_COUNT*2-1:0] s_axi_bresp;
wire [S_COUNT*BUSER_WIDTH-1:0] s_axi_buser;
wire [S_COUNT-1:0] s_axi_bvalid;
wire [S_COUNT-1:0] s_axi_arready;
wire [S_COUNT*S_ID_WIDTH-1:0] s_axi_rid;
wire [S_COUNT*DATA_WIDTH-1:0] s_axi_rdata;
wire [S_COUNT*2-1:0] s_axi_rresp;
wire [S_COUNT-1:0] s_axi_rlast;
wire [S_COUNT*RUSER_WIDTH-1:0] s_axi_ruser;
wire [S_COUNT-1:0] s_axi_rvalid;
wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_awid;
wire [M_COUNT*ADDR_WIDTH-1:0] m_axi_awaddr;
wire [M_COUNT*8-1:0] m_axi_awlen;
wire [M_COUNT*3-1:0] m_axi_awsize;
wire [M_COUNT*2-1:0] m_axi_awburst;
wire [M_COUNT-1:0] m_axi_awlock;
wire [M_COUNT*4-1:0] m_axi_awcache;
wire [M_COUNT*3-1:0] m_axi_awprot;
wire [M_COUNT*4-1:0] m_axi_awqos;
wire [M_COUNT*4-1:0] m_axi_awregion;
wire [M_COUNT*AWUSER_WIDTH-1:0] m_axi_awuser;
wire [M_COUNT-1:0] m_axi_awvalid;
wire [M_COUNT*DATA_WIDTH-1:0] m_axi_wdata;
wire [M_COUNT*STRB_WIDTH-1:0] m_axi_wstrb;
wire [M_COUNT-1:0] m_axi_wlast;
wire [M_COUNT*WUSER_WIDTH-1:0] m_axi_wuser;
wire [M_COUNT-1:0] m_axi_wvalid;
wire [M_COUNT-1:0] m_axi_bready;
wire [M_COUNT*M_ID_WIDTH-1:0] m_axi_arid;
wire [M_COUNT*ADDR_WIDTH-1:0] m_axi_araddr;
wire [M_COUNT*8-1:0] m_axi_arlen;
wire [M_COUNT*3-1:0] m_axi_arsize;
wire [M_COUNT*2-1:0] m_axi_arburst;
wire [M_COUNT-1:0] m_axi_arlock;
wire [M_COUNT*4-1:0] m_axi_arcache;
wire [M_COUNT*3-1:0] m_axi_arprot;
wire [M_COUNT*4-1:0] m_axi_arqos;
wire [M_COUNT*4-1:0] m_axi_arregion;
wire [M_COUNT*ARUSER_WIDTH-1:0] m_axi_aruser;
wire [M_COUNT-1:0] m_axi_arvalid;
wire [M_COUNT-1:0] m_axi_rready;
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_awqos,
s_axi_awuser,
s_axi_awvalid,
s_axi_wdata,
s_axi_wstrb,
s_axi_wlast,
s_axi_wuser,
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_arqos,
s_axi_aruser,
s_axi_arvalid,
s_axi_rready,
m_axi_awready,
m_axi_wready,
m_axi_bid,
m_axi_bresp,
m_axi_buser,
m_axi_bvalid,
m_axi_arready,
m_axi_rid,
m_axi_rdata,
m_axi_rresp,
m_axi_rlast,
m_axi_ruser,
m_axi_rvalid
);
$to_myhdl(
s_axi_awready,
s_axi_wready,
s_axi_bid,
s_axi_bresp,
s_axi_buser,
s_axi_bvalid,
s_axi_arready,
s_axi_rid,
s_axi_rdata,
s_axi_rresp,
s_axi_rlast,
s_axi_ruser,
s_axi_rvalid,
m_axi_awid,
m_axi_awaddr,
m_axi_awlen,
m_axi_awsize,
m_axi_awburst,
m_axi_awlock,
m_axi_awcache,
m_axi_awprot,
m_axi_awqos,
m_axi_awregion,
m_axi_awuser,
m_axi_awvalid,
m_axi_wdata,
m_axi_wstrb,
m_axi_wlast,
m_axi_wuser,
m_axi_wvalid,
m_axi_bready,
m_axi_arid,
m_axi_araddr,
m_axi_arlen,
m_axi_arsize,
m_axi_arburst,
m_axi_arlock,
m_axi_arcache,
m_axi_arprot,
m_axi_arqos,
m_axi_arregion,
m_axi_aruser,
m_axi_arvalid,
m_axi_rready
);
// dump file
$dumpfile("test_axi_crossbar_4x4.lxt");
$dumpvars(0, test_axi_crossbar_4x4);
end
axi_crossbar #(
.S_COUNT(S_COUNT),
.M_COUNT(M_COUNT),
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.S_ID_WIDTH(S_ID_WIDTH),
.M_ID_WIDTH(M_ID_WIDTH),
.AWUSER_ENABLE(AWUSER_ENABLE),
.AWUSER_WIDTH(AWUSER_WIDTH),
.WUSER_ENABLE(WUSER_ENABLE),
.WUSER_WIDTH(WUSER_WIDTH),
.BUSER_ENABLE(BUSER_ENABLE),
.BUSER_WIDTH(BUSER_WIDTH),
.ARUSER_ENABLE(ARUSER_ENABLE),
.ARUSER_WIDTH(ARUSER_WIDTH),
.RUSER_ENABLE(RUSER_ENABLE),
.RUSER_WIDTH(RUSER_WIDTH),
.S_THREADS(S_THREADS),
.S_ACCEPT(S_ACCEPT),
.M_REGIONS(M_REGIONS),
.M_BASE_ADDR(M_BASE_ADDR),
.M_ADDR_WIDTH(M_ADDR_WIDTH),
.M_CONNECT_READ(M_CONNECT_READ),
.M_CONNECT_WRITE(M_CONNECT_WRITE),
.M_ISSUE(M_ISSUE),
.M_SECURE(M_SECURE),
.S_AW_REG_TYPE(S_AW_REG_TYPE),
.S_W_REG_TYPE(S_W_REG_TYPE),
.S_B_REG_TYPE(S_B_REG_TYPE),
.S_AR_REG_TYPE(S_AR_REG_TYPE),
.S_R_REG_TYPE(S_R_REG_TYPE),
.M_AW_REG_TYPE(M_AW_REG_TYPE),
.M_W_REG_TYPE(M_W_REG_TYPE),
.M_B_REG_TYPE(M_B_REG_TYPE),
.M_AR_REG_TYPE(M_AR_REG_TYPE),
.M_R_REG_TYPE(M_R_REG_TYPE)
)
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_awqos(s_axi_awqos),
.s_axi_awuser(s_axi_awuser),
.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_wuser(s_axi_wuser),
.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_buser(s_axi_buser),
.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_arqos(s_axi_arqos),
.s_axi_aruser(s_axi_aruser),
.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_ruser(s_axi_ruser),
.s_axi_rvalid(s_axi_rvalid),
.s_axi_rready(s_axi_rready),
.m_axi_awid(m_axi_awid),
.m_axi_awaddr(m_axi_awaddr),
.m_axi_awlen(m_axi_awlen),
.m_axi_awsize(m_axi_awsize),
.m_axi_awburst(m_axi_awburst),
.m_axi_awlock(m_axi_awlock),
.m_axi_awcache(m_axi_awcache),
.m_axi_awprot(m_axi_awprot),
.m_axi_awqos(m_axi_awqos),
.m_axi_awregion(m_axi_awregion),
.m_axi_awuser(m_axi_awuser),
.m_axi_awvalid(m_axi_awvalid),
.m_axi_awready(m_axi_awready),
.m_axi_wdata(m_axi_wdata),
.m_axi_wstrb(m_axi_wstrb),
.m_axi_wlast(m_axi_wlast),
.m_axi_wuser(m_axi_wuser),
.m_axi_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_buser(m_axi_buser),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
.m_axi_arid(m_axi_arid),
.m_axi_araddr(m_axi_araddr),
.m_axi_arlen(m_axi_arlen),
.m_axi_arsize(m_axi_arsize),
.m_axi_arburst(m_axi_arburst),
.m_axi_arlock(m_axi_arlock),
.m_axi_arcache(m_axi_arcache),
.m_axi_arprot(m_axi_arprot),
.m_axi_arqos(m_axi_arqos),
.m_axi_arregion(m_axi_arregion),
.m_axi_aruser(m_axi_aruser),
.m_axi_arvalid(m_axi_arvalid),
.m_axi_arready(m_axi_arready),
.m_axi_rid(m_axi_rid),
.m_axi_rdata(m_axi_rdata),
.m_axi_rresp(m_axi_rresp),
.m_axi_rlast(m_axi_rlast),
.m_axi_ruser(m_axi_ruser),
.m_axi_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready)
);
endmodule