Commit 738c1fef authored by Antoine Kaufmann's avatar Antoine Kaufmann
Browse files

add corundum and verilator build files

parent 7f925101
/*
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 #
(
// Number of AXI inputs (slave interfaces)
parameter S_COUNT = 4,
// Number of AXI outputs (master interfaces)
parameter M_COUNT = 4,
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Input ID field width (from AXI masters)
parameter S_ID_WIDTH = 8,
// Output ID field width (towards AXI slaves)
// Additional bits required for response routing
parameter M_ID_WIDTH = S_ID_WIDTH+$clog2(S_COUNT),
// Propagate awuser signal
parameter AWUSER_ENABLE = 0,
// Width of awuser signal
parameter AWUSER_WIDTH = 1,
// Propagate wuser signal
parameter WUSER_ENABLE = 0,
// Width of wuser signal
parameter WUSER_WIDTH = 1,
// Propagate buser signal
parameter BUSER_ENABLE = 0,
// Width of buser signal
parameter BUSER_WIDTH = 1,
// Number of concurrent unique IDs for each slave interface
// S_COUNT concatenated fields of 32 bits
parameter S_THREADS = {S_COUNT{32'd2}},
// Number of concurrent operations for each slave interface
// S_COUNT concatenated fields of 32 bits
parameter S_ACCEPT = {S_COUNT{32'd16}},
// Number of regions per master interface
parameter M_REGIONS = 1,
// Master interface base addresses
// M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits
// set to zero for default addressing based on M_ADDR_WIDTH
parameter M_BASE_ADDR = 0,
// Master interface address widths
// M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits
parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}},
// Write connections between interfaces
// M_COUNT concatenated fields of S_COUNT bits
parameter M_CONNECT = {M_COUNT{{S_COUNT{1'b1}}}},
// Number of concurrent operations for each master interface
// M_COUNT concatenated fields of 32 bits
parameter M_ISSUE = {M_COUNT{32'd4}},
// Secure master (fail operations based on awprot/arprot)
// M_COUNT bits
parameter M_SECURE = {M_COUNT{1'b0}},
// Slave interface AW channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S_AW_REG_TYPE = {S_COUNT{2'd0}},
// Slave interface W channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S_W_REG_TYPE = {S_COUNT{2'd0}},
// Slave interface B channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S_B_REG_TYPE = {S_COUNT{2'd1}},
// Master interface AW channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M_AW_REG_TYPE = {M_COUNT{2'd1}},
// Master interface W channel register type (output)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M_W_REG_TYPE = {M_COUNT{2'd2}},
// Master interface B channel register type (input)
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
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 (instance %m)");
$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 (instance %m)");
$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 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 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 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
/*
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 DMA
*/
module axi_dma #
(
// Width of AXI data bus in bits
parameter AXI_DATA_WIDTH = 32,
// Width of AXI address bus in bits
parameter AXI_ADDR_WIDTH = 16,
// Width of AXI wstrb (width of data bus in words)
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8),
// Width of AXI ID signal
parameter AXI_ID_WIDTH = 8,
// Maximum AXI burst length to generate
parameter AXI_MAX_BURST_LEN = 16,
// Width of AXI stream interfaces in bits
parameter AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
// Use AXI stream tkeep signal
parameter AXIS_KEEP_ENABLE = (AXIS_DATA_WIDTH>8),
// AXI stream tkeep signal width (words per cycle)
parameter AXIS_KEEP_WIDTH = (AXIS_DATA_WIDTH/8),
// Use AXI stream tlast signal
parameter AXIS_LAST_ENABLE = 1,
// Propagate AXI stream tid signal
parameter AXIS_ID_ENABLE = 0,
// AXI stream tid signal width
parameter AXIS_ID_WIDTH = 8,
// Propagate AXI stream tdest signal
parameter AXIS_DEST_ENABLE = 0,
// AXI stream tdest signal width
parameter AXIS_DEST_WIDTH = 8,
// Propagate AXI stream tuser signal
parameter AXIS_USER_ENABLE = 1,
// AXI stream tuser signal width
parameter AXIS_USER_WIDTH = 1,
// Width of length field
parameter LEN_WIDTH = 20,
// Width of tag field
parameter TAG_WIDTH = 8,
// Enable support for scatter/gather DMA
// (multiple descriptors per AXI stream frame)
parameter ENABLE_SG = 0,
// Enable support for unaligned transfers
parameter ENABLE_UNALIGNED = 0
)
(
input wire clk,
input wire rst,
/*
* AXI read descriptor input
*/
input wire [AXI_ADDR_WIDTH-1:0] s_axis_read_desc_addr,
input wire [LEN_WIDTH-1:0] s_axis_read_desc_len,
input wire [TAG_WIDTH-1:0] s_axis_read_desc_tag,
input wire [AXIS_ID_WIDTH-1:0] s_axis_read_desc_id,
input wire [AXIS_DEST_WIDTH-1:0] s_axis_read_desc_dest,
input wire [AXIS_USER_WIDTH-1:0] s_axis_read_desc_user,
input wire s_axis_read_desc_valid,
output wire s_axis_read_desc_ready,
/*
* AXI read descriptor status output
*/
output wire [TAG_WIDTH-1:0] m_axis_read_desc_status_tag,
output wire m_axis_read_desc_status_valid,
/*
* AXI stream read data output
*/
output wire [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata,
output wire [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep,
output wire m_axis_read_data_tvalid,
input wire m_axis_read_data_tready,
output wire m_axis_read_data_tlast,
output wire [AXIS_ID_WIDTH-1:0] m_axis_read_data_tid,
output wire [AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest,
output wire [AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser,
/*
* AXI write descriptor input
*/
input wire [AXI_ADDR_WIDTH-1:0] s_axis_write_desc_addr,
input wire [LEN_WIDTH-1:0] s_axis_write_desc_len,
input wire [TAG_WIDTH-1:0] s_axis_write_desc_tag,
input wire s_axis_write_desc_valid,
output wire s_axis_write_desc_ready,
/*
* AXI write descriptor status output
*/
output wire [LEN_WIDTH-1:0] m_axis_write_desc_status_len,
output wire [TAG_WIDTH-1:0] m_axis_write_desc_status_tag,
output wire [AXIS_ID_WIDTH-1:0] m_axis_write_desc_status_id,
output wire [AXIS_DEST_WIDTH-1:0] m_axis_write_desc_status_dest,
output wire [AXIS_USER_WIDTH-1:0] m_axis_write_desc_status_user,
output wire m_axis_write_desc_status_valid,
/*
* AXI stream write data input
*/
input wire [AXIS_DATA_WIDTH-1:0] s_axis_write_data_tdata,
input wire [AXIS_KEEP_WIDTH-1:0] s_axis_write_data_tkeep,
input wire s_axis_write_data_tvalid,
output wire s_axis_write_data_tready,
input wire s_axis_write_data_tlast,
input wire [AXIS_ID_WIDTH-1:0] s_axis_write_data_tid,
input wire [AXIS_DEST_WIDTH-1:0] s_axis_write_data_tdest,
input wire [AXIS_USER_WIDTH-1:0] s_axis_write_data_tuser,
/*
* AXI master interface
*/
output wire [AXI_ID_WIDTH-1:0] m_axi_awid,
output wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr,
output wire [7:0] m_axi_awlen,
output wire [2:0] m_axi_awsize,
output wire [1:0] m_axi_awburst,
output wire m_axi_awlock,
output wire [3:0] m_axi_awcache,
output wire [2:0] m_axi_awprot,
output wire m_axi_awvalid,
input wire m_axi_awready,
output wire [AXI_DATA_WIDTH-1:0] m_axi_wdata,
output wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb,
output wire m_axi_wlast,
output wire m_axi_wvalid,
input wire m_axi_wready,
input wire [AXI_ID_WIDTH-1:0] m_axi_bid,
input wire [1:0] m_axi_bresp,
input wire m_axi_bvalid,
output wire m_axi_bready,
output wire [AXI_ID_WIDTH-1:0] m_axi_arid,
output wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr,
output wire [7:0] m_axi_arlen,
output wire [2:0] m_axi_arsize,
output wire [1:0] m_axi_arburst,
output wire m_axi_arlock,
output wire [3:0] m_axi_arcache,
output wire [2:0] m_axi_arprot,
output wire m_axi_arvalid,
input wire m_axi_arready,
input wire [AXI_ID_WIDTH-1:0] m_axi_rid,
input wire [AXI_DATA_WIDTH-1:0] m_axi_rdata,
input wire [1:0] m_axi_rresp,
input wire m_axi_rlast,
input wire m_axi_rvalid,
output wire m_axi_rready,
/*
* Configuration
*/
input wire read_enable,
input wire write_enable,
input wire write_abort
);
axi_dma_rd #(
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
.AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
.AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE),
.AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
.AXIS_ID_WIDTH(AXIS_ID_WIDTH),
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
.AXIS_DEST_WIDTH(AXIS_DEST_WIDTH),
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
.AXIS_USER_WIDTH(AXIS_USER_WIDTH),
.LEN_WIDTH(LEN_WIDTH),
.TAG_WIDTH(TAG_WIDTH),
.ENABLE_SG(ENABLE_SG),
.ENABLE_UNALIGNED(ENABLE_UNALIGNED)
)
axi_dma_rd_inst (
.clk(clk),
.rst(rst),
/*
* AXI read descriptor input
*/
.s_axis_read_desc_addr(s_axis_read_desc_addr),
.s_axis_read_desc_len(s_axis_read_desc_len),
.s_axis_read_desc_tag(s_axis_read_desc_tag),
.s_axis_read_desc_id(s_axis_read_desc_id),
.s_axis_read_desc_dest(s_axis_read_desc_dest),
.s_axis_read_desc_user(s_axis_read_desc_user),
.s_axis_read_desc_valid(s_axis_read_desc_valid),
.s_axis_read_desc_ready(s_axis_read_desc_ready),
/*
* AXI read descriptor status output
*/
.m_axis_read_desc_status_tag(m_axis_read_desc_status_tag),
.m_axis_read_desc_status_valid(m_axis_read_desc_status_valid),
/*
* AXI stream read data output
*/
.m_axis_read_data_tdata(m_axis_read_data_tdata),
.m_axis_read_data_tkeep(m_axis_read_data_tkeep),
.m_axis_read_data_tvalid(m_axis_read_data_tvalid),
.m_axis_read_data_tready(m_axis_read_data_tready),
.m_axis_read_data_tlast(m_axis_read_data_tlast),
.m_axis_read_data_tid(m_axis_read_data_tid),
.m_axis_read_data_tdest(m_axis_read_data_tdest),
.m_axis_read_data_tuser(m_axis_read_data_tuser),
/*
* AXI master interface
*/
.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_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_rvalid(m_axi_rvalid),
.m_axi_rready(m_axi_rready),
/*
* Configuration
*/
.enable(read_enable)
);
axi_dma_wr #(
.AXI_DATA_WIDTH(AXI_DATA_WIDTH),
.AXI_ADDR_WIDTH(AXI_ADDR_WIDTH),
.AXI_STRB_WIDTH(AXI_STRB_WIDTH),
.AXI_ID_WIDTH(AXI_ID_WIDTH),
.AXI_MAX_BURST_LEN(AXI_MAX_BURST_LEN),
.AXIS_DATA_WIDTH(AXIS_DATA_WIDTH),
.AXIS_KEEP_ENABLE(AXIS_KEEP_ENABLE),
.AXIS_KEEP_WIDTH(AXIS_KEEP_WIDTH),
.AXIS_LAST_ENABLE(AXIS_LAST_ENABLE),
.AXIS_ID_ENABLE(AXIS_ID_ENABLE),
.AXIS_ID_WIDTH(AXIS_ID_WIDTH),
.AXIS_DEST_ENABLE(AXIS_DEST_ENABLE),
.AXIS_DEST_WIDTH(AXIS_DEST_WIDTH),
.AXIS_USER_ENABLE(AXIS_USER_ENABLE),
.AXIS_USER_WIDTH(AXIS_USER_WIDTH),
.LEN_WIDTH(LEN_WIDTH),
.TAG_WIDTH(TAG_WIDTH),
.ENABLE_SG(ENABLE_SG),
.ENABLE_UNALIGNED(ENABLE_UNALIGNED)
)
axi_dma_wr_inst (
.clk(clk),
.rst(rst),
/*
* AXI write descriptor input
*/
.s_axis_write_desc_addr(s_axis_write_desc_addr),
.s_axis_write_desc_len(s_axis_write_desc_len),
.s_axis_write_desc_tag(s_axis_write_desc_tag),
.s_axis_write_desc_valid(s_axis_write_desc_valid),
.s_axis_write_desc_ready(s_axis_write_desc_ready),
/*
* AXI write descriptor status output
*/
.m_axis_write_desc_status_len(m_axis_write_desc_status_len),
.m_axis_write_desc_status_tag(m_axis_write_desc_status_tag),
.m_axis_write_desc_status_id(m_axis_write_desc_status_id),
.m_axis_write_desc_status_dest(m_axis_write_desc_status_dest),
.m_axis_write_desc_status_user(m_axis_write_desc_status_user),
.m_axis_write_desc_status_valid(m_axis_write_desc_status_valid),
/*
* AXI stream write data input
*/
.s_axis_write_data_tdata(s_axis_write_data_tdata),
.s_axis_write_data_tkeep(s_axis_write_data_tkeep),
.s_axis_write_data_tvalid(s_axis_write_data_tvalid),
.s_axis_write_data_tready(s_axis_write_data_tready),
.s_axis_write_data_tlast(s_axis_write_data_tlast),
.s_axis_write_data_tid(s_axis_write_data_tid),
.s_axis_write_data_tdest(s_axis_write_data_tdest),
.s_axis_write_data_tuser(s_axis_write_data_tuser),
/*
* AXI master interface
*/
.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_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_wvalid(m_axi_wvalid),
.m_axi_wready(m_axi_wready),
.m_axi_bid(m_axi_bid),
.m_axi_bresp(m_axi_bresp),
.m_axi_bvalid(m_axi_bvalid),
.m_axi_bready(m_axi_bready),
/*
* Configuration
*/
.enable(write_enable),
.abort(write_abort)
);
endmodule
/*
Copyright (c) 2019 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
/*
* AXI DMA descriptor mux
*/
module axi_dma_desc_mux #
(
// Number of ports
parameter PORTS = 2,
// AXI address width
parameter AXI_ADDR_WIDTH = 16,
// Propagate AXI stream tid signal
parameter AXIS_ID_ENABLE = 0,
// AXI stream tid signal width
parameter AXIS_ID_WIDTH = 8,
// Propagate AXI stream tdest signal
parameter AXIS_DEST_ENABLE = 0,
// AXI stream tdest signal width
parameter AXIS_DEST_WIDTH = 8,
// Propagate AXI stream tuser signal
parameter AXIS_USER_ENABLE = 1,
// AXI stream tuser signal width
parameter AXIS_USER_WIDTH = 1,
// Length field width
parameter LEN_WIDTH = 20,
// Input tag field width
parameter S_TAG_WIDTH = 8,
// Output tag field width (towards CDMA module)
// Additional bits required for response routing
parameter M_TAG_WIDTH = S_TAG_WIDTH+$clog2(PORTS),
// arbitration type: "PRIORITY" or "ROUND_ROBIN"
parameter ARB_TYPE = "PRIORITY",
// LSB priority: "LOW", "HIGH"
parameter LSB_PRIORITY = "HIGH"
)
(
input wire clk,
input wire rst,
/*
* Descriptor output (to AXI DMA core)
*/
output wire [AXI_ADDR_WIDTH-1:0] m_axis_desc_addr,
output wire [LEN_WIDTH-1:0] m_axis_desc_len,
output wire [M_TAG_WIDTH-1:0] m_axis_desc_tag,
output wire [AXIS_ID_WIDTH-1:0] m_axis_desc_id,
output wire [AXIS_DEST_WIDTH-1:0] m_axis_desc_dest,
output wire [AXIS_USER_WIDTH-1:0] m_axis_desc_user,
output wire m_axis_desc_valid,
input wire m_axis_desc_ready,
/*
* Descriptor status input (from AXI DMA core)
*/
input wire [LEN_WIDTH-1:0] s_axis_desc_status_len,
input wire [M_TAG_WIDTH-1:0] s_axis_desc_status_tag,
input wire [AXIS_ID_WIDTH-1:0] s_axis_desc_status_id,
input wire [AXIS_DEST_WIDTH-1:0] s_axis_desc_status_dest,
input wire [AXIS_USER_WIDTH-1:0] s_axis_desc_status_user,
input wire s_axis_desc_status_valid,
/*
* Descriptor input
*/
input wire [PORTS*AXI_ADDR_WIDTH-1:0] s_axis_desc_addr,
input wire [PORTS*LEN_WIDTH-1:0] s_axis_desc_len,
input wire [PORTS*S_TAG_WIDTH-1:0] s_axis_desc_tag,
input wire [PORTS*AXIS_ID_WIDTH-1:0] s_axis_desc_id,
input wire [PORTS*AXIS_DEST_WIDTH-1:0] s_axis_desc_dest,
input wire [PORTS*AXIS_USER_WIDTH-1:0] s_axis_desc_user,
input wire [PORTS-1:0] s_axis_desc_valid,
output wire [PORTS-1:0] s_axis_desc_ready,
/*
* Descriptor status output
*/
output wire [PORTS*LEN_WIDTH-1:0] m_axis_desc_status_len,
output wire [PORTS*S_TAG_WIDTH-1:0] m_axis_desc_status_tag,
output wire [PORTS*AXIS_ID_WIDTH-1:0] m_axis_desc_status_id,
output wire [PORTS*AXIS_DEST_WIDTH-1:0] m_axis_desc_status_dest,
output wire [PORTS*AXIS_USER_WIDTH-1:0] m_axis_desc_status_user,
output wire [PORTS-1:0] m_axis_desc_status_valid
);
parameter CL_PORTS = $clog2(PORTS);
// check configuration
initial begin
if (M_TAG_WIDTH < S_TAG_WIDTH+$clog2(PORTS)) begin
$error("Error: M_TAG_WIDTH must be at least $clog2(PORTS) larger than S_TAG_WIDTH (instance %m)");
$finish;
end
end
// descriptor mux
wire [PORTS-1:0] request;
wire [PORTS-1:0] acknowledge;
wire [PORTS-1:0] grant;
wire grant_valid;
wire [CL_PORTS-1:0] grant_encoded;
// internal datapath
reg [AXI_ADDR_WIDTH-1:0] m_axis_desc_addr_int;
reg [LEN_WIDTH-1:0] m_axis_desc_len_int;
reg [M_TAG_WIDTH-1:0] m_axis_desc_tag_int;
reg [AXIS_ID_WIDTH-1:0] m_axis_desc_id_int;
reg [AXIS_DEST_WIDTH-1:0] m_axis_desc_dest_int;
reg [AXIS_USER_WIDTH-1:0] m_axis_desc_user_int;
reg m_axis_desc_valid_int;
reg m_axis_desc_ready_int_reg = 1'b0;
wire m_axis_desc_ready_int_early;
assign s_axis_desc_ready = (m_axis_desc_ready_int_reg && grant_valid) << grant_encoded;
// mux for incoming packet
wire [AXI_ADDR_WIDTH-1:0] current_s_desc_addr = s_axis_desc_addr[grant_encoded*AXI_ADDR_WIDTH +: AXI_ADDR_WIDTH];
wire [LEN_WIDTH-1:0] current_s_desc_len = s_axis_desc_len[grant_encoded*LEN_WIDTH +: LEN_WIDTH];
wire [S_TAG_WIDTH-1:0] current_s_desc_tag = s_axis_desc_tag[grant_encoded*S_TAG_WIDTH +: S_TAG_WIDTH];
wire [AXIS_ID_WIDTH-1:0] current_s_desc_id = s_axis_desc_id[grant_encoded*AXIS_ID_WIDTH +: AXIS_ID_WIDTH];
wire [AXIS_DEST_WIDTH-1:0] current_s_desc_dest = s_axis_desc_dest[grant_encoded*AXIS_DEST_WIDTH +: AXIS_DEST_WIDTH];
wire [AXIS_USER_WIDTH-1:0] current_s_desc_user = s_axis_desc_user[grant_encoded*AXIS_USER_WIDTH +: AXIS_USER_WIDTH];
wire current_s_desc_valid = s_axis_desc_valid[grant_encoded];
wire current_s_desc_ready = s_axis_desc_ready[grant_encoded];
// arbiter instance
arbiter #(
.PORTS(PORTS),
.TYPE(ARB_TYPE),
.BLOCK("ACKNOWLEDGE"),
.LSB_PRIORITY(LSB_PRIORITY)
)
arb_inst (
.clk(clk),
.rst(rst),
.request(request),
.acknowledge(acknowledge),
.grant(grant),
.grant_valid(grant_valid),
.grant_encoded(grant_encoded)
);
assign request = s_axis_desc_valid & ~grant;
assign acknowledge = grant & s_axis_desc_valid & s_axis_desc_ready;
always @* begin
m_axis_desc_addr_int = current_s_desc_addr;
m_axis_desc_len_int = current_s_desc_len;
m_axis_desc_tag_int = {grant_encoded, current_s_desc_tag};
m_axis_desc_id_int = current_s_desc_id;
m_axis_desc_dest_int = current_s_desc_dest;
m_axis_desc_user_int = current_s_desc_user;
m_axis_desc_valid_int = current_s_desc_valid && m_axis_desc_ready_int_reg && grant_valid;
end
// output datapath logic
reg [AXI_ADDR_WIDTH-1:0] m_axis_desc_addr_reg = {AXI_ADDR_WIDTH{1'b0}};
reg [LEN_WIDTH-1:0] m_axis_desc_len_reg = {LEN_WIDTH{1'b0}};
reg [M_TAG_WIDTH-1:0] m_axis_desc_tag_reg = {M_TAG_WIDTH{1'b0}};
reg [AXIS_ID_WIDTH-1:0] m_axis_desc_id_reg = {AXIS_ID_WIDTH{1'b0}};
reg [AXIS_DEST_WIDTH-1:0] m_axis_desc_dest_reg = {AXIS_DEST_WIDTH{1'b0}};
reg [AXIS_USER_WIDTH-1:0] m_axis_desc_user_reg = {AXIS_USER_WIDTH{1'b0}};
reg m_axis_desc_valid_reg = 1'b0, m_axis_desc_valid_next;
reg [AXI_ADDR_WIDTH-1:0] temp_m_axis_desc_addr_reg = {AXI_ADDR_WIDTH{1'b0}};
reg [LEN_WIDTH-1:0] temp_m_axis_desc_len_reg = {LEN_WIDTH{1'b0}};
reg [M_TAG_WIDTH-1:0] temp_m_axis_desc_tag_reg = {M_TAG_WIDTH{1'b0}};
reg [AXIS_ID_WIDTH-1:0] temp_m_axis_desc_id_reg = {AXIS_ID_WIDTH{1'b0}};
reg [AXIS_DEST_WIDTH-1:0] temp_m_axis_desc_dest_reg = {AXIS_DEST_WIDTH{1'b0}};
reg [AXIS_USER_WIDTH-1:0] temp_m_axis_desc_user_reg = {AXIS_USER_WIDTH{1'b0}};
reg temp_m_axis_desc_valid_reg = 1'b0, temp_m_axis_desc_valid_next;
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_axis_temp_to_output;
assign m_axis_desc_addr = m_axis_desc_addr_reg;
assign m_axis_desc_len = m_axis_desc_len_reg;
assign m_axis_desc_tag = m_axis_desc_tag_reg;
assign m_axis_desc_id = AXIS_ID_ENABLE ? m_axis_desc_id_reg : {AXIS_ID_WIDTH{1'b0}};
assign m_axis_desc_dest = AXIS_DEST_ENABLE ? m_axis_desc_dest_reg : {AXIS_DEST_WIDTH{1'b0}};
assign m_axis_desc_user = AXIS_USER_ENABLE ? m_axis_desc_user_reg : {AXIS_USER_WIDTH{1'b0}};
assign m_axis_desc_valid = m_axis_desc_valid_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_axis_desc_ready_int_early = m_axis_desc_ready || (!temp_m_axis_desc_valid_reg && (!m_axis_desc_valid_reg || !m_axis_desc_valid_int));
always @* begin
// transfer sink ready state to source
m_axis_desc_valid_next = m_axis_desc_valid_reg;
temp_m_axis_desc_valid_next = temp_m_axis_desc_valid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (m_axis_desc_ready_int_reg) begin
// input is ready
if (m_axis_desc_ready || !m_axis_desc_valid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axis_desc_valid_next = m_axis_desc_valid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axis_desc_valid_next = m_axis_desc_valid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (m_axis_desc_ready) begin
// input is not ready, but output is ready
m_axis_desc_valid_next = temp_m_axis_desc_valid_reg;
temp_m_axis_desc_valid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_axis_desc_valid_reg <= 1'b0;
m_axis_desc_ready_int_reg <= 1'b0;
temp_m_axis_desc_valid_reg <= 1'b0;
end else begin
m_axis_desc_valid_reg <= m_axis_desc_valid_next;
m_axis_desc_ready_int_reg <= m_axis_desc_ready_int_early;
temp_m_axis_desc_valid_reg <= temp_m_axis_desc_valid_next;
end
// datapath
if (store_axis_int_to_output) begin
m_axis_desc_addr_reg <= m_axis_desc_addr_int;
m_axis_desc_len_reg <= m_axis_desc_len_int;
m_axis_desc_tag_reg <= m_axis_desc_tag_int;
m_axis_desc_id_reg <= m_axis_desc_id_int;
m_axis_desc_dest_reg <= m_axis_desc_dest_int;
m_axis_desc_user_reg <= m_axis_desc_user_int;
end else if (store_axis_temp_to_output) begin
m_axis_desc_addr_reg <= temp_m_axis_desc_addr_reg;
m_axis_desc_len_reg <= temp_m_axis_desc_len_reg;
m_axis_desc_tag_reg <= temp_m_axis_desc_tag_reg;
m_axis_desc_id_reg <= temp_m_axis_desc_id_reg;
m_axis_desc_dest_reg <= temp_m_axis_desc_dest_reg;
m_axis_desc_user_reg <= temp_m_axis_desc_user_reg;
end
if (store_axis_int_to_temp) begin
temp_m_axis_desc_addr_reg <= m_axis_desc_addr_int;
temp_m_axis_desc_len_reg <= m_axis_desc_len_int;
temp_m_axis_desc_tag_reg <= m_axis_desc_tag_int;
temp_m_axis_desc_id_reg <= m_axis_desc_id_int;
temp_m_axis_desc_dest_reg <= m_axis_desc_dest_int;
temp_m_axis_desc_user_reg <= m_axis_desc_user_int;
end
end
// descriptor status demux
reg [LEN_WIDTH-1:0] m_axis_desc_status_len_reg = {LEN_WIDTH{1'b0}};
reg [S_TAG_WIDTH-1:0] m_axis_desc_status_tag_reg = {S_TAG_WIDTH{1'b0}};
reg [AXIS_ID_WIDTH-1:0] m_axis_desc_status_id_reg = {AXIS_ID_WIDTH{1'b0}};
reg [AXIS_DEST_WIDTH-1:0] m_axis_desc_status_dest_reg = {AXIS_DEST_WIDTH{1'b0}};
reg [AXIS_USER_WIDTH-1:0] m_axis_desc_status_user_reg = {AXIS_USER_WIDTH{1'b0}};
reg [PORTS-1:0] m_axis_desc_status_valid_reg = {PORTS{1'b0}};
assign m_axis_desc_status_len = {PORTS{m_axis_desc_status_len_reg}};
assign m_axis_desc_status_tag = {PORTS{m_axis_desc_status_tag_reg}};
assign m_axis_desc_status_id = AXIS_ID_ENABLE ? {PORTS{m_axis_desc_status_id_reg}} : {AXIS_ID_WIDTH*PORTS{1'b0}};
assign m_axis_desc_status_dest = AXIS_DEST_ENABLE ? {PORTS{m_axis_desc_status_dest_reg}} : {AXIS_DEST_WIDTH*PORTS{1'b0}};
assign m_axis_desc_status_user = AXIS_USER_ENABLE ? {PORTS{m_axis_desc_status_user_reg}} : {AXIS_USER_WIDTH*PORTS{1'b0}};
assign m_axis_desc_status_valid = m_axis_desc_status_valid_reg;
always @(posedge clk) begin
if (rst) begin
m_axis_desc_status_valid_reg <= {PORTS{1'b0}};
end else begin
m_axis_desc_status_valid_reg <= s_axis_desc_status_valid << (PORTS > 1 ? s_axis_desc_status_tag[S_TAG_WIDTH+CL_PORTS-1:S_TAG_WIDTH] : 0);
end
m_axis_desc_status_len_reg <= s_axis_desc_status_len;
m_axis_desc_status_tag_reg <= s_axis_desc_status_tag;
m_axis_desc_status_id_reg <= s_axis_desc_status_id;
m_axis_desc_status_dest_reg <= s_axis_desc_status_dest;
m_axis_desc_status_user_reg <= s_axis_desc_status_user;
end
endmodule
/*
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 DMA
*/
module axi_dma_rd #
(
// Width of AXI data bus in bits
parameter AXI_DATA_WIDTH = 32,
// Width of AXI address bus in bits
parameter AXI_ADDR_WIDTH = 16,
// Width of AXI wstrb (width of data bus in words)
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8),
// Width of AXI ID signal
parameter AXI_ID_WIDTH = 8,
// Maximum AXI burst length to generate
parameter AXI_MAX_BURST_LEN = 16,
// Width of AXI stream interfaces in bits
parameter AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
// Use AXI stream tkeep signal
parameter AXIS_KEEP_ENABLE = (AXIS_DATA_WIDTH>8),
// AXI stream tkeep signal width (words per cycle)
parameter AXIS_KEEP_WIDTH = (AXIS_DATA_WIDTH/8),
// Use AXI stream tlast signal
parameter AXIS_LAST_ENABLE = 1,
// Propagate AXI stream tid signal
parameter AXIS_ID_ENABLE = 0,
// AXI stream tid signal width
parameter AXIS_ID_WIDTH = 8,
// Propagate AXI stream tdest signal
parameter AXIS_DEST_ENABLE = 0,
// AXI stream tdest signal width
parameter AXIS_DEST_WIDTH = 8,
// Propagate AXI stream tuser signal
parameter AXIS_USER_ENABLE = 1,
// AXI stream tuser signal width
parameter AXIS_USER_WIDTH = 1,
// Width of length field
parameter LEN_WIDTH = 20,
// Width of tag field
parameter TAG_WIDTH = 8,
// Enable support for scatter/gather DMA
// (multiple descriptors per AXI stream frame)
parameter ENABLE_SG = 0,
// Enable support for unaligned transfers
parameter ENABLE_UNALIGNED = 0
)
(
input wire clk,
input wire rst,
/*
* AXI read descriptor input
*/
input wire [AXI_ADDR_WIDTH-1:0] s_axis_read_desc_addr,
input wire [LEN_WIDTH-1:0] s_axis_read_desc_len,
input wire [TAG_WIDTH-1:0] s_axis_read_desc_tag,
input wire [AXIS_ID_WIDTH-1:0] s_axis_read_desc_id,
input wire [AXIS_DEST_WIDTH-1:0] s_axis_read_desc_dest,
input wire [AXIS_USER_WIDTH-1:0] s_axis_read_desc_user,
input wire s_axis_read_desc_valid,
output wire s_axis_read_desc_ready,
/*
* AXI read descriptor status output
*/
output wire [TAG_WIDTH-1:0] m_axis_read_desc_status_tag,
output wire m_axis_read_desc_status_valid,
/*
* AXI stream read data output
*/
output wire [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata,
output wire [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep,
output wire m_axis_read_data_tvalid,
input wire m_axis_read_data_tready,
output wire m_axis_read_data_tlast,
output wire [AXIS_ID_WIDTH-1:0] m_axis_read_data_tid,
output wire [AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest,
output wire [AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser,
/*
* AXI master interface
*/
output wire [AXI_ID_WIDTH-1:0] m_axi_arid,
output wire [AXI_ADDR_WIDTH-1:0] m_axi_araddr,
output wire [7:0] m_axi_arlen,
output wire [2:0] m_axi_arsize,
output wire [1:0] m_axi_arburst,
output wire m_axi_arlock,
output wire [3:0] m_axi_arcache,
output wire [2:0] m_axi_arprot,
output wire m_axi_arvalid,
input wire m_axi_arready,
input wire [AXI_ID_WIDTH-1:0] m_axi_rid,
input wire [AXI_DATA_WIDTH-1:0] m_axi_rdata,
input wire [1:0] m_axi_rresp,
input wire m_axi_rlast,
input wire m_axi_rvalid,
output wire m_axi_rready,
/*
* Configuration
*/
input wire enable
);
parameter AXI_WORD_WIDTH = AXI_STRB_WIDTH;
parameter AXI_WORD_SIZE = AXI_DATA_WIDTH/AXI_WORD_WIDTH;
parameter AXI_BURST_SIZE = $clog2(AXI_STRB_WIDTH);
parameter AXI_MAX_BURST_SIZE = AXI_MAX_BURST_LEN << AXI_BURST_SIZE;
parameter AXIS_KEEP_WIDTH_INT = AXIS_KEEP_ENABLE ? AXIS_KEEP_WIDTH : 1;
parameter AXIS_WORD_WIDTH = AXIS_KEEP_WIDTH_INT;
parameter AXIS_WORD_SIZE = AXIS_DATA_WIDTH/AXIS_WORD_WIDTH;
parameter OFFSET_WIDTH = AXI_STRB_WIDTH > 1 ? $clog2(AXI_STRB_WIDTH) : 1;
parameter OFFSET_MASK = AXI_STRB_WIDTH > 1 ? {OFFSET_WIDTH{1'b1}} : 0;
parameter ADDR_MASK = {AXI_ADDR_WIDTH{1'b1}} << $clog2(AXI_STRB_WIDTH);
parameter CYCLE_COUNT_WIDTH = LEN_WIDTH - AXI_BURST_SIZE + 1;
// bus width assertions
initial begin
if (AXI_WORD_SIZE * AXI_STRB_WIDTH != AXI_DATA_WIDTH) begin
$error("Error: AXI data width not evenly divisble (instance %m)");
$finish;
end
if (AXIS_WORD_SIZE * AXIS_KEEP_WIDTH_INT != AXIS_DATA_WIDTH) begin
$error("Error: AXI stream data width not evenly divisble (instance %m)");
$finish;
end
if (AXI_WORD_SIZE != AXIS_WORD_SIZE) begin
$error("Error: word size mismatch (instance %m)");
$finish;
end
if (2**$clog2(AXI_WORD_WIDTH) != AXI_WORD_WIDTH) begin
$error("Error: AXI word width must be even power of two (instance %m)");
$finish;
end
if (AXI_DATA_WIDTH != AXIS_DATA_WIDTH) begin
$error("Error: AXI interface width must match AXI stream interface width (instance %m)");
$finish;
end
if (AXI_MAX_BURST_LEN < 1 || AXI_MAX_BURST_LEN > 256) begin
$error("Error: AXI_MAX_BURST_LEN must be between 1 and 256 (instance %m)");
$finish;
end
if (ENABLE_SG) begin
$error("Error: scatter/gather is not yet implemented (instance %m)");
$finish;
end
end
localparam [0:0]
AXI_STATE_IDLE = 1'd0,
AXI_STATE_START = 1'd1;
reg [0:0] axi_state_reg = AXI_STATE_IDLE, axi_state_next;
localparam [0:0]
AXIS_STATE_IDLE = 1'd0,
AXIS_STATE_READ = 1'd1;
reg [0:0] axis_state_reg = AXIS_STATE_IDLE, axis_state_next;
// datapath control signals
reg transfer_in_save;
reg axis_cmd_ready;
reg [AXI_ADDR_WIDTH-1:0] addr_reg = {AXI_ADDR_WIDTH{1'b0}}, addr_next;
reg [LEN_WIDTH-1:0] op_word_count_reg = {LEN_WIDTH{1'b0}}, op_word_count_next;
reg [LEN_WIDTH-1:0] tr_word_count_reg = {LEN_WIDTH{1'b0}}, tr_word_count_next;
reg [OFFSET_WIDTH-1:0] axis_cmd_offset_reg = {OFFSET_WIDTH{1'b0}}, axis_cmd_offset_next;
reg [OFFSET_WIDTH-1:0] axis_cmd_last_cycle_offset_reg = {OFFSET_WIDTH{1'b0}}, axis_cmd_last_cycle_offset_next;
reg [CYCLE_COUNT_WIDTH-1:0] axis_cmd_input_cycle_count_reg = {CYCLE_COUNT_WIDTH{1'b0}}, axis_cmd_input_cycle_count_next;
reg [CYCLE_COUNT_WIDTH-1:0] axis_cmd_output_cycle_count_reg = {CYCLE_COUNT_WIDTH{1'b0}}, axis_cmd_output_cycle_count_next;
reg axis_cmd_bubble_cycle_reg = 1'b0, axis_cmd_bubble_cycle_next;
reg [TAG_WIDTH-1:0] axis_cmd_tag_reg = {TAG_WIDTH{1'b0}}, axis_cmd_tag_next;
reg [AXIS_ID_WIDTH-1:0] axis_cmd_axis_id_reg = {AXIS_ID_WIDTH{1'b0}}, axis_cmd_axis_id_next;
reg [AXIS_DEST_WIDTH-1:0] axis_cmd_axis_dest_reg = {AXIS_DEST_WIDTH{1'b0}}, axis_cmd_axis_dest_next;
reg [AXIS_USER_WIDTH-1:0] axis_cmd_axis_user_reg = {AXIS_USER_WIDTH{1'b0}}, axis_cmd_axis_user_next;
reg axis_cmd_valid_reg = 1'b0, axis_cmd_valid_next;
reg [OFFSET_WIDTH-1:0] offset_reg = {OFFSET_WIDTH{1'b0}}, offset_next;
reg [OFFSET_WIDTH-1:0] last_cycle_offset_reg = {OFFSET_WIDTH{1'b0}}, last_cycle_offset_next;
reg [CYCLE_COUNT_WIDTH-1:0] input_cycle_count_reg = {CYCLE_COUNT_WIDTH{1'b0}}, input_cycle_count_next;
reg [CYCLE_COUNT_WIDTH-1:0] output_cycle_count_reg = {CYCLE_COUNT_WIDTH{1'b0}}, output_cycle_count_next;
reg input_active_reg = 1'b0, input_active_next;
reg output_active_reg = 1'b0, output_active_next;
reg bubble_cycle_reg = 1'b0, bubble_cycle_next;
reg first_cycle_reg = 1'b0, first_cycle_next;
reg output_last_cycle_reg = 1'b0, output_last_cycle_next;
reg [TAG_WIDTH-1:0] tag_reg = {TAG_WIDTH{1'b0}}, tag_next;
reg [AXIS_ID_WIDTH-1:0] axis_id_reg = {AXIS_ID_WIDTH{1'b0}}, axis_id_next;
reg [AXIS_DEST_WIDTH-1:0] axis_dest_reg = {AXIS_DEST_WIDTH{1'b0}}, axis_dest_next;
reg [AXIS_USER_WIDTH-1:0] axis_user_reg = {AXIS_USER_WIDTH{1'b0}}, axis_user_next;
reg s_axis_read_desc_ready_reg = 1'b0, s_axis_read_desc_ready_next;
reg [TAG_WIDTH-1:0] m_axis_read_desc_status_tag_reg = {TAG_WIDTH{1'b0}}, m_axis_read_desc_status_tag_next;
reg m_axis_read_desc_status_valid_reg = 1'b0, m_axis_read_desc_status_valid_next;
reg [AXI_ADDR_WIDTH-1:0] m_axi_araddr_reg = {AXI_ADDR_WIDTH{1'b0}}, m_axi_araddr_next;
reg [7:0] m_axi_arlen_reg = 8'd0, m_axi_arlen_next;
reg m_axi_arvalid_reg = 1'b0, m_axi_arvalid_next;
reg m_axi_rready_reg = 1'b0, m_axi_rready_next;
reg [AXI_DATA_WIDTH-1:0] save_axi_rdata_reg = {AXI_DATA_WIDTH{1'b0}};
wire [AXI_DATA_WIDTH-1:0] shift_axi_rdata = {m_axi_rdata, save_axi_rdata_reg} >> ((AXI_STRB_WIDTH-offset_reg)*AXI_WORD_SIZE);
// internal datapath
reg [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata_int;
reg [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep_int;
reg m_axis_read_data_tvalid_int;
reg m_axis_read_data_tready_int_reg = 1'b0;
reg m_axis_read_data_tlast_int;
reg [AXIS_ID_WIDTH-1:0] m_axis_read_data_tid_int;
reg [AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest_int;
reg [AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser_int;
wire m_axis_read_data_tready_int_early;
assign s_axis_read_desc_ready = s_axis_read_desc_ready_reg;
assign m_axis_read_desc_status_tag = m_axis_read_desc_status_tag_reg;
assign m_axis_read_desc_status_valid = m_axis_read_desc_status_valid_reg;
assign m_axi_arid = {AXI_ID_WIDTH{1'b0}};
assign m_axi_araddr = m_axi_araddr_reg;
assign m_axi_arlen = m_axi_arlen_reg;
assign m_axi_arsize = AXI_BURST_SIZE;
assign m_axi_arburst = 2'b01;
assign m_axi_arlock = 1'b0;
assign m_axi_arcache = 4'b0011;
assign m_axi_arprot = 3'b010;
assign m_axi_arvalid = m_axi_arvalid_reg;
assign m_axi_rready = m_axi_rready_reg;
wire [AXI_ADDR_WIDTH-1:0] addr_plus_max_burst = addr_reg + AXI_MAX_BURST_SIZE;
wire [AXI_ADDR_WIDTH-1:0] addr_plus_count = addr_reg + op_word_count_reg;
always @* begin
axi_state_next = AXI_STATE_IDLE;
s_axis_read_desc_ready_next = 1'b0;
m_axi_araddr_next = m_axi_araddr_reg;
m_axi_arlen_next = m_axi_arlen_reg;
m_axi_arvalid_next = m_axi_arvalid_reg && !m_axi_arready;
addr_next = addr_reg;
op_word_count_next = op_word_count_reg;
tr_word_count_next = tr_word_count_reg;
axis_cmd_offset_next = axis_cmd_offset_reg;
axis_cmd_last_cycle_offset_next = axis_cmd_last_cycle_offset_reg;
axis_cmd_input_cycle_count_next = axis_cmd_input_cycle_count_reg;
axis_cmd_output_cycle_count_next = axis_cmd_output_cycle_count_reg;
axis_cmd_bubble_cycle_next = axis_cmd_bubble_cycle_reg;
axis_cmd_tag_next = axis_cmd_tag_reg;
axis_cmd_axis_id_next = axis_cmd_axis_id_reg;
axis_cmd_axis_dest_next = axis_cmd_axis_dest_reg;
axis_cmd_axis_user_next = axis_cmd_axis_user_reg;
axis_cmd_valid_next = axis_cmd_valid_reg && !axis_cmd_ready;
case (axi_state_reg)
AXI_STATE_IDLE: begin
// idle state - load new descriptor to start operation
s_axis_read_desc_ready_next = !axis_cmd_valid_reg && enable;
if (s_axis_read_desc_ready && s_axis_read_desc_valid) begin
if (ENABLE_UNALIGNED) begin
addr_next = s_axis_read_desc_addr;
axis_cmd_offset_next = AXI_STRB_WIDTH > 1 ? AXI_STRB_WIDTH - (s_axis_read_desc_addr & OFFSET_MASK) : 0;
axis_cmd_bubble_cycle_next = axis_cmd_offset_next > 0;
axis_cmd_last_cycle_offset_next = s_axis_read_desc_len & OFFSET_MASK;
end else begin
addr_next = s_axis_read_desc_addr & ADDR_MASK;
axis_cmd_offset_next = 0;
axis_cmd_bubble_cycle_next = 1'b0;
axis_cmd_last_cycle_offset_next = s_axis_read_desc_len & OFFSET_MASK;
end
axis_cmd_tag_next = s_axis_read_desc_tag;
op_word_count_next = s_axis_read_desc_len;
axis_cmd_axis_id_next = s_axis_read_desc_id;
axis_cmd_axis_dest_next = s_axis_read_desc_dest;
axis_cmd_axis_user_next = s_axis_read_desc_user;
if (ENABLE_UNALIGNED) begin
axis_cmd_input_cycle_count_next = (op_word_count_next + (s_axis_read_desc_addr & OFFSET_MASK) - 1) >> AXI_BURST_SIZE;
end else begin
axis_cmd_input_cycle_count_next = (op_word_count_next - 1) >> AXI_BURST_SIZE;
end
axis_cmd_output_cycle_count_next = (op_word_count_next - 1) >> AXI_BURST_SIZE;
axis_cmd_valid_next = 1'b1;
s_axis_read_desc_ready_next = 1'b0;
axi_state_next = AXI_STATE_START;
end else begin
axi_state_next = AXI_STATE_IDLE;
end
end
AXI_STATE_START: begin
// start state - initiate new AXI transfer
if (!m_axi_arvalid) begin
if (op_word_count_reg <= AXI_MAX_BURST_SIZE - (addr_reg & OFFSET_MASK) || AXI_MAX_BURST_SIZE >= 4096) begin
// packet smaller than max burst size
if (addr_reg[12] != addr_plus_count[12]) begin
// crosses 4k boundary
tr_word_count_next = 13'h1000 - addr_reg[11:0];
end else begin
// does not cross 4k boundary
tr_word_count_next = op_word_count_reg;
end
end else begin
// packet larger than max burst size
if (addr_reg[12] != addr_plus_max_burst[12]) begin
// crosses 4k boundary
tr_word_count_next = 13'h1000 - addr_reg[11:0];
end else begin
// does not cross 4k boundary
tr_word_count_next = AXI_MAX_BURST_SIZE - (addr_reg & OFFSET_MASK);
end
end
m_axi_araddr_next = addr_reg;
if (ENABLE_UNALIGNED) begin
m_axi_arlen_next = (tr_word_count_next + (addr_reg & OFFSET_MASK) - 1) >> AXI_BURST_SIZE;
end else begin
m_axi_arlen_next = (tr_word_count_next - 1) >> AXI_BURST_SIZE;
end
m_axi_arvalid_next = 1'b1;
addr_next = addr_reg + tr_word_count_next;
op_word_count_next = op_word_count_reg - tr_word_count_next;
if (op_word_count_next > 0) begin
axi_state_next = AXI_STATE_START;
end else begin
s_axis_read_desc_ready_next = !axis_cmd_valid_reg && enable;
axi_state_next = AXI_STATE_IDLE;
end
end else begin
axi_state_next = AXI_STATE_START;
end
end
endcase
end
always @* begin
axis_state_next = AXIS_STATE_IDLE;
m_axis_read_desc_status_tag_next = m_axis_read_desc_status_tag_reg;
m_axis_read_desc_status_valid_next = 1'b0;
m_axis_read_data_tdata_int = shift_axi_rdata;
m_axis_read_data_tkeep_int = {AXIS_KEEP_WIDTH{1'b1}};
m_axis_read_data_tlast_int = 1'b0;
m_axis_read_data_tvalid_int = 1'b0;
m_axis_read_data_tid_int = axis_id_reg;
m_axis_read_data_tdest_int = axis_dest_reg;
m_axis_read_data_tuser_int = axis_user_reg;
m_axi_rready_next = 1'b0;
transfer_in_save = 1'b0;
axis_cmd_ready = 1'b0;
offset_next = offset_reg;
last_cycle_offset_next = last_cycle_offset_reg;
input_cycle_count_next = input_cycle_count_reg;
output_cycle_count_next = output_cycle_count_reg;
input_active_next = input_active_reg;
output_active_next = output_active_reg;
bubble_cycle_next = bubble_cycle_reg;
first_cycle_next = first_cycle_reg;
output_last_cycle_next = output_last_cycle_reg;
tag_next = tag_reg;
axis_id_next = axis_id_reg;
axis_dest_next = axis_dest_reg;
axis_user_next = axis_user_reg;
case (axis_state_reg)
AXIS_STATE_IDLE: begin
// idle state - load new descriptor to start operation
m_axi_rready_next = 1'b0;
// store transfer parameters
if (ENABLE_UNALIGNED) begin
offset_next = axis_cmd_offset_reg;
end else begin
offset_next = 0;
end
last_cycle_offset_next = axis_cmd_last_cycle_offset_reg;
input_cycle_count_next = axis_cmd_input_cycle_count_reg;
output_cycle_count_next = axis_cmd_output_cycle_count_reg;
bubble_cycle_next = axis_cmd_bubble_cycle_reg;
tag_next = axis_cmd_tag_reg;
axis_id_next = axis_cmd_axis_id_reg;
axis_dest_next = axis_cmd_axis_dest_reg;
axis_user_next = axis_cmd_axis_user_reg;
output_last_cycle_next = output_cycle_count_next == 0;
input_active_next = 1'b1;
output_active_next = 1'b1;
first_cycle_next = 1'b1;
if (axis_cmd_valid_reg) begin
axis_cmd_ready = 1'b1;
m_axi_rready_next = m_axis_read_data_tready_int_early;
axis_state_next = AXIS_STATE_READ;
end
end
AXIS_STATE_READ: begin
// handle AXI read data
m_axi_rready_next = m_axis_read_data_tready_int_early && input_active_reg;
if (m_axis_read_data_tready_int_reg && ((m_axi_rready && m_axi_rvalid) || !input_active_reg)) begin
// transfer in AXI read data
transfer_in_save = m_axi_rready && m_axi_rvalid;
if (ENABLE_UNALIGNED && first_cycle_reg && bubble_cycle_reg) begin
if (input_active_reg) begin
input_cycle_count_next = input_cycle_count_reg - 1;
input_active_next = input_cycle_count_reg > 0;
end
bubble_cycle_next = 1'b0;
first_cycle_next = 1'b0;
m_axi_rready_next = m_axis_read_data_tready_int_early && input_active_next;
axis_state_next = AXIS_STATE_READ;
end else begin
// update counters
if (input_active_reg) begin
input_cycle_count_next = input_cycle_count_reg - 1;
input_active_next = input_cycle_count_reg > 0;
end
if (output_active_reg) begin
output_cycle_count_next = output_cycle_count_reg - 1;
output_active_next = output_cycle_count_reg > 0;
end
output_last_cycle_next = output_cycle_count_next == 0;
bubble_cycle_next = 1'b0;
first_cycle_next = 1'b0;
// pass through read data
m_axis_read_data_tdata_int = shift_axi_rdata;
m_axis_read_data_tkeep_int = {AXIS_KEEP_WIDTH_INT{1'b1}};
m_axis_read_data_tvalid_int = 1'b1;
if (output_last_cycle_reg) begin
// no more data to transfer, finish operation
if (last_cycle_offset_reg > 0) begin
m_axis_read_data_tkeep_int = {AXIS_KEEP_WIDTH_INT{1'b1}} >> (AXIS_KEEP_WIDTH_INT - last_cycle_offset_reg);
end
m_axis_read_data_tlast_int = 1'b1;
m_axis_read_desc_status_tag_next = tag_reg;
m_axis_read_desc_status_valid_next = 1'b1;
m_axi_rready_next = 1'b0;
axis_state_next = AXIS_STATE_IDLE;
end else begin
// more cycles in AXI transfer
m_axi_rready_next = m_axis_read_data_tready_int_early && input_active_next;
axis_state_next = AXIS_STATE_READ;
end
end
end else begin
axis_state_next = AXIS_STATE_READ;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
axi_state_reg <= AXI_STATE_IDLE;
axis_state_reg <= AXIS_STATE_IDLE;
axis_cmd_valid_reg <= 1'b0;
s_axis_read_desc_ready_reg <= 1'b0;
m_axis_read_desc_status_valid_reg <= 1'b0;
m_axi_arvalid_reg <= 1'b0;
m_axi_rready_reg <= 1'b0;
end else begin
axi_state_reg <= axi_state_next;
axis_state_reg <= axis_state_next;
axis_cmd_valid_reg <= axis_cmd_valid_next;
s_axis_read_desc_ready_reg <= s_axis_read_desc_ready_next;
m_axis_read_desc_status_valid_reg <= m_axis_read_desc_status_valid_next;
m_axi_arvalid_reg <= m_axi_arvalid_next;
m_axi_rready_reg <= m_axi_rready_next;
end
m_axis_read_desc_status_tag_reg <= m_axis_read_desc_status_tag_next;
m_axi_araddr_reg <= m_axi_araddr_next;
m_axi_arlen_reg <= m_axi_arlen_next;
addr_reg <= addr_next;
op_word_count_reg <= op_word_count_next;
tr_word_count_reg <= tr_word_count_next;
axis_cmd_offset_reg <= axis_cmd_offset_next;
axis_cmd_last_cycle_offset_reg <= axis_cmd_last_cycle_offset_next;
axis_cmd_input_cycle_count_reg <= axis_cmd_input_cycle_count_next;
axis_cmd_output_cycle_count_reg <= axis_cmd_output_cycle_count_next;
axis_cmd_bubble_cycle_reg <= axis_cmd_bubble_cycle_next;
axis_cmd_tag_reg <= axis_cmd_tag_next;
axis_cmd_axis_id_reg <= axis_cmd_axis_id_next;
axis_cmd_axis_dest_reg <= axis_cmd_axis_dest_next;
axis_cmd_axis_user_reg <= axis_cmd_axis_user_next;
axis_cmd_valid_reg <= axis_cmd_valid_next;
offset_reg <= offset_next;
last_cycle_offset_reg <= last_cycle_offset_next;
input_cycle_count_reg <= input_cycle_count_next;
output_cycle_count_reg <= output_cycle_count_next;
input_active_reg <= input_active_next;
output_active_reg <= output_active_next;
bubble_cycle_reg <= bubble_cycle_next;
first_cycle_reg <= first_cycle_next;
output_last_cycle_reg <= output_last_cycle_next;
tag_reg <= tag_next;
axis_id_reg <= axis_id_next;
axis_dest_reg <= axis_dest_next;
axis_user_reg <= axis_user_next;
if (transfer_in_save) begin
save_axi_rdata_reg <= m_axi_rdata;
end
end
// output datapath logic
reg [AXIS_DATA_WIDTH-1:0] m_axis_read_data_tdata_reg = {AXIS_DATA_WIDTH{1'b0}};
reg [AXIS_KEEP_WIDTH-1:0] m_axis_read_data_tkeep_reg = {AXIS_KEEP_WIDTH{1'b0}};
reg m_axis_read_data_tvalid_reg = 1'b0, m_axis_read_data_tvalid_next;
reg m_axis_read_data_tlast_reg = 1'b0;
reg [AXIS_ID_WIDTH-1:0] m_axis_read_data_tid_reg = {AXIS_ID_WIDTH{1'b0}};
reg [AXIS_DEST_WIDTH-1:0] m_axis_read_data_tdest_reg = {AXIS_DEST_WIDTH{1'b0}};
reg [AXIS_USER_WIDTH-1:0] m_axis_read_data_tuser_reg = {AXIS_USER_WIDTH{1'b0}};
reg [AXIS_DATA_WIDTH-1:0] temp_m_axis_read_data_tdata_reg = {AXIS_DATA_WIDTH{1'b0}};
reg [AXIS_KEEP_WIDTH-1:0] temp_m_axis_read_data_tkeep_reg = {AXIS_KEEP_WIDTH{1'b0}};
reg temp_m_axis_read_data_tvalid_reg = 1'b0, temp_m_axis_read_data_tvalid_next;
reg temp_m_axis_read_data_tlast_reg = 1'b0;
reg [AXIS_ID_WIDTH-1:0] temp_m_axis_read_data_tid_reg = {AXIS_ID_WIDTH{1'b0}};
reg [AXIS_DEST_WIDTH-1:0] temp_m_axis_read_data_tdest_reg = {AXIS_DEST_WIDTH{1'b0}};
reg [AXIS_USER_WIDTH-1:0] temp_m_axis_read_data_tuser_reg = {AXIS_USER_WIDTH{1'b0}};
// datapath control
reg store_axis_int_to_output;
reg store_axis_int_to_temp;
reg store_axis_temp_to_output;
assign m_axis_read_data_tdata = m_axis_read_data_tdata_reg;
assign m_axis_read_data_tkeep = AXIS_KEEP_ENABLE ? m_axis_read_data_tkeep_reg : {AXIS_KEEP_WIDTH{1'b1}};
assign m_axis_read_data_tvalid = m_axis_read_data_tvalid_reg;
assign m_axis_read_data_tlast = AXIS_LAST_ENABLE ? m_axis_read_data_tlast_reg : 1'b1;
assign m_axis_read_data_tid = AXIS_ID_ENABLE ? m_axis_read_data_tid_reg : {AXIS_ID_WIDTH{1'b0}};
assign m_axis_read_data_tdest = AXIS_DEST_ENABLE ? m_axis_read_data_tdest_reg : {AXIS_DEST_WIDTH{1'b0}};
assign m_axis_read_data_tuser = AXIS_USER_ENABLE ? m_axis_read_data_tuser_reg : {AXIS_USER_WIDTH{1'b0}};
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_axis_read_data_tready_int_early = m_axis_read_data_tready || (!temp_m_axis_read_data_tvalid_reg && (!m_axis_read_data_tvalid_reg || !m_axis_read_data_tvalid_int));
always @* begin
// transfer sink ready state to source
m_axis_read_data_tvalid_next = m_axis_read_data_tvalid_reg;
temp_m_axis_read_data_tvalid_next = temp_m_axis_read_data_tvalid_reg;
store_axis_int_to_output = 1'b0;
store_axis_int_to_temp = 1'b0;
store_axis_temp_to_output = 1'b0;
if (m_axis_read_data_tready_int_reg) begin
// input is ready
if (m_axis_read_data_tready || !m_axis_read_data_tvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axis_read_data_tvalid_next = m_axis_read_data_tvalid_int;
store_axis_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axis_read_data_tvalid_next = m_axis_read_data_tvalid_int;
store_axis_int_to_temp = 1'b1;
end
end else if (m_axis_read_data_tready) begin
// input is not ready, but output is ready
m_axis_read_data_tvalid_next = temp_m_axis_read_data_tvalid_reg;
temp_m_axis_read_data_tvalid_next = 1'b0;
store_axis_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_axis_read_data_tvalid_reg <= 1'b0;
m_axis_read_data_tready_int_reg <= 1'b0;
temp_m_axis_read_data_tvalid_reg <= 1'b0;
end else begin
m_axis_read_data_tvalid_reg <= m_axis_read_data_tvalid_next;
m_axis_read_data_tready_int_reg <= m_axis_read_data_tready_int_early;
temp_m_axis_read_data_tvalid_reg <= temp_m_axis_read_data_tvalid_next;
end
// datapath
if (store_axis_int_to_output) begin
m_axis_read_data_tdata_reg <= m_axis_read_data_tdata_int;
m_axis_read_data_tkeep_reg <= m_axis_read_data_tkeep_int;
m_axis_read_data_tlast_reg <= m_axis_read_data_tlast_int;
m_axis_read_data_tid_reg <= m_axis_read_data_tid_int;
m_axis_read_data_tdest_reg <= m_axis_read_data_tdest_int;
m_axis_read_data_tuser_reg <= m_axis_read_data_tuser_int;
end else if (store_axis_temp_to_output) begin
m_axis_read_data_tdata_reg <= temp_m_axis_read_data_tdata_reg;
m_axis_read_data_tkeep_reg <= temp_m_axis_read_data_tkeep_reg;
m_axis_read_data_tlast_reg <= temp_m_axis_read_data_tlast_reg;
m_axis_read_data_tid_reg <= temp_m_axis_read_data_tid_reg;
m_axis_read_data_tdest_reg <= temp_m_axis_read_data_tdest_reg;
m_axis_read_data_tuser_reg <= temp_m_axis_read_data_tuser_reg;
end
if (store_axis_int_to_temp) begin
temp_m_axis_read_data_tdata_reg <= m_axis_read_data_tdata_int;
temp_m_axis_read_data_tkeep_reg <= m_axis_read_data_tkeep_int;
temp_m_axis_read_data_tlast_reg <= m_axis_read_data_tlast_int;
temp_m_axis_read_data_tid_reg <= m_axis_read_data_tid_int;
temp_m_axis_read_data_tdest_reg <= m_axis_read_data_tdest_int;
temp_m_axis_read_data_tuser_reg <= m_axis_read_data_tuser_int;
end
end
endmodule
/*
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 DMA
*/
module axi_dma_wr #
(
// Width of AXI data bus in bits
parameter AXI_DATA_WIDTH = 32,
// Width of AXI address bus in bits
parameter AXI_ADDR_WIDTH = 16,
// Width of AXI wstrb (width of data bus in words)
parameter AXI_STRB_WIDTH = (AXI_DATA_WIDTH/8),
// Width of AXI ID signal
parameter AXI_ID_WIDTH = 8,
// Maximum AXI burst length to generate
parameter AXI_MAX_BURST_LEN = 16,
// Width of AXI stream interfaces in bits
parameter AXIS_DATA_WIDTH = AXI_DATA_WIDTH,
// Use AXI stream tkeep signal
parameter AXIS_KEEP_ENABLE = (AXIS_DATA_WIDTH>8),
// AXI stream tkeep signal width (words per cycle)
parameter AXIS_KEEP_WIDTH = (AXIS_DATA_WIDTH/8),
// Use AXI stream tlast signal
parameter AXIS_LAST_ENABLE = 1,
// Propagate AXI stream tid signal
parameter AXIS_ID_ENABLE = 0,
// AXI stream tid signal width
parameter AXIS_ID_WIDTH = 8,
// Propagate AXI stream tdest signal
parameter AXIS_DEST_ENABLE = 0,
// AXI stream tdest signal width
parameter AXIS_DEST_WIDTH = 8,
// Propagate AXI stream tuser signal
parameter AXIS_USER_ENABLE = 1,
// AXI stream tuser signal width
parameter AXIS_USER_WIDTH = 1,
// Width of length field
parameter LEN_WIDTH = 20,
// Width of tag field
parameter TAG_WIDTH = 8,
// Enable support for scatter/gather DMA
// (multiple descriptors per AXI stream frame)
parameter ENABLE_SG = 0,
// Enable support for unaligned transfers
parameter ENABLE_UNALIGNED = 0
)
(
input wire clk,
input wire rst,
/*
* AXI write descriptor input
*/
input wire [AXI_ADDR_WIDTH-1:0] s_axis_write_desc_addr,
input wire [LEN_WIDTH-1:0] s_axis_write_desc_len,
input wire [TAG_WIDTH-1:0] s_axis_write_desc_tag,
input wire s_axis_write_desc_valid,
output wire s_axis_write_desc_ready,
/*
* AXI write descriptor status output
*/
output wire [LEN_WIDTH-1:0] m_axis_write_desc_status_len,
output wire [TAG_WIDTH-1:0] m_axis_write_desc_status_tag,
output wire [AXIS_ID_WIDTH-1:0] m_axis_write_desc_status_id,
output wire [AXIS_DEST_WIDTH-1:0] m_axis_write_desc_status_dest,
output wire [AXIS_USER_WIDTH-1:0] m_axis_write_desc_status_user,
output wire m_axis_write_desc_status_valid,
/*
* AXI stream write data input
*/
input wire [AXIS_DATA_WIDTH-1:0] s_axis_write_data_tdata,
input wire [AXIS_KEEP_WIDTH-1:0] s_axis_write_data_tkeep,
input wire s_axis_write_data_tvalid,
output wire s_axis_write_data_tready,
input wire s_axis_write_data_tlast,
input wire [AXIS_ID_WIDTH-1:0] s_axis_write_data_tid,
input wire [AXIS_DEST_WIDTH-1:0] s_axis_write_data_tdest,
input wire [AXIS_USER_WIDTH-1:0] s_axis_write_data_tuser,
/*
* AXI master interface
*/
output wire [AXI_ID_WIDTH-1:0] m_axi_awid,
output wire [AXI_ADDR_WIDTH-1:0] m_axi_awaddr,
output wire [7:0] m_axi_awlen,
output wire [2:0] m_axi_awsize,
output wire [1:0] m_axi_awburst,
output wire m_axi_awlock,
output wire [3:0] m_axi_awcache,
output wire [2:0] m_axi_awprot,
output wire m_axi_awvalid,
input wire m_axi_awready,
output wire [AXI_DATA_WIDTH-1:0] m_axi_wdata,
output wire [AXI_STRB_WIDTH-1:0] m_axi_wstrb,
output wire m_axi_wlast,
output wire m_axi_wvalid,
input wire m_axi_wready,
input wire [AXI_ID_WIDTH-1:0] m_axi_bid,
input wire [1:0] m_axi_bresp,
input wire m_axi_bvalid,
output wire m_axi_bready,
/*
* Configuration
*/
input wire enable,
input wire abort
);
parameter AXI_WORD_WIDTH = AXI_STRB_WIDTH;
parameter AXI_WORD_SIZE = AXI_DATA_WIDTH/AXI_WORD_WIDTH;
parameter AXI_BURST_SIZE = $clog2(AXI_STRB_WIDTH);
parameter AXI_MAX_BURST_SIZE = AXI_MAX_BURST_LEN << AXI_BURST_SIZE;
parameter AXIS_KEEP_WIDTH_INT = AXIS_KEEP_ENABLE ? AXIS_KEEP_WIDTH : 1;
parameter AXIS_WORD_WIDTH = AXIS_KEEP_WIDTH_INT;
parameter AXIS_WORD_SIZE = AXIS_DATA_WIDTH/AXIS_WORD_WIDTH;
parameter OFFSET_WIDTH = AXI_STRB_WIDTH > 1 ? $clog2(AXI_STRB_WIDTH) : 1;
parameter OFFSET_MASK = AXI_STRB_WIDTH > 1 ? {OFFSET_WIDTH{1'b1}} : 0;
parameter ADDR_MASK = {AXI_ADDR_WIDTH{1'b1}} << $clog2(AXI_STRB_WIDTH);
parameter CYCLE_COUNT_WIDTH = LEN_WIDTH - AXI_BURST_SIZE + 1;
parameter STATUS_FIFO_ADDR_WIDTH = 5;
// bus width assertions
initial begin
if (AXI_WORD_SIZE * AXI_STRB_WIDTH != AXI_DATA_WIDTH) begin
$error("Error: AXI data width not evenly divisble (instance %m)");
$finish;
end
if (AXIS_WORD_SIZE * AXIS_KEEP_WIDTH_INT != AXIS_DATA_WIDTH) begin
$error("Error: AXI stream data width not evenly divisble (instance %m)");
$finish;
end
if (AXI_WORD_SIZE != AXIS_WORD_SIZE) begin
$error("Error: word size mismatch (instance %m)");
$finish;
end
if (2**$clog2(AXI_WORD_WIDTH) != AXI_WORD_WIDTH) begin
$error("Error: AXI word width must be even power of two (instance %m)");
$finish;
end
if (AXI_DATA_WIDTH != AXIS_DATA_WIDTH) begin
$error("Error: AXI interface width must match AXI stream interface width (instance %m)");
$finish;
end
if (AXI_MAX_BURST_LEN < 1 || AXI_MAX_BURST_LEN > 256) begin
$error("Error: AXI_MAX_BURST_LEN must be between 1 and 256 (instance %m)");
$finish;
end
if (ENABLE_SG) begin
$error("Error: scatter/gather is not yet implemented (instance %m)");
$finish;
end
end
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_START = 3'd1,
STATE_WRITE = 3'd2,
STATE_FINISH_BURST = 3'd3,
STATE_DROP_DATA = 3'd4;
reg [2:0] state_reg = STATE_IDLE, state_next;
// datapath control signals
reg transfer_in_save;
reg flush_save;
reg status_fifo_we;
integer i;
reg [OFFSET_WIDTH:0] cycle_size;
reg [AXI_ADDR_WIDTH-1:0] addr_reg = {AXI_ADDR_WIDTH{1'b0}}, addr_next;
reg [LEN_WIDTH-1:0] op_word_count_reg = {LEN_WIDTH{1'b0}}, op_word_count_next;
reg [LEN_WIDTH-1:0] tr_word_count_reg = {LEN_WIDTH{1'b0}}, tr_word_count_next;
reg [OFFSET_WIDTH-1:0] offset_reg = {OFFSET_WIDTH{1'b0}}, offset_next;
reg [AXI_STRB_WIDTH-1:0] strb_offset_mask_reg = {AXI_STRB_WIDTH{1'b1}}, strb_offset_mask_next;
reg zero_offset_reg = 1'b1, zero_offset_next;
reg [OFFSET_WIDTH-1:0] last_cycle_offset_reg = {OFFSET_WIDTH{1'b0}}, last_cycle_offset_next;
reg [LEN_WIDTH-1:0] length_reg = {LEN_WIDTH{1'b0}}, length_next;
reg [CYCLE_COUNT_WIDTH-1:0] input_cycle_count_reg = {CYCLE_COUNT_WIDTH{1'b0}}, input_cycle_count_next;
reg [CYCLE_COUNT_WIDTH-1:0] output_cycle_count_reg = {CYCLE_COUNT_WIDTH{1'b0}}, output_cycle_count_next;
reg input_active_reg = 1'b0, input_active_next;
reg first_cycle_reg = 1'b0, first_cycle_next;
reg input_last_cycle_reg = 1'b0, input_last_cycle_next;
reg output_last_cycle_reg = 1'b0, output_last_cycle_next;
reg last_transfer_reg = 1'b0, last_transfer_next;
reg [TAG_WIDTH-1:0] tag_reg = {TAG_WIDTH{1'b0}}, tag_next;
reg [AXIS_ID_WIDTH-1:0] axis_id_reg = {AXIS_ID_WIDTH{1'b0}}, axis_id_next;
reg [AXIS_DEST_WIDTH-1:0] axis_dest_reg = {AXIS_DEST_WIDTH{1'b0}}, axis_dest_next;
reg [AXIS_USER_WIDTH-1:0] axis_user_reg = {AXIS_USER_WIDTH{1'b0}}, axis_user_next;
reg [STATUS_FIFO_ADDR_WIDTH+1-1:0] status_fifo_wr_ptr_reg = 0, status_fifo_wr_ptr_next;
reg [STATUS_FIFO_ADDR_WIDTH+1-1:0] status_fifo_rd_ptr_reg = 0, status_fifo_rd_ptr_next;
reg [LEN_WIDTH-1:0] status_fifo_len[(2**STATUS_FIFO_ADDR_WIDTH)-1:0];
reg [TAG_WIDTH-1:0] status_fifo_tag[(2**STATUS_FIFO_ADDR_WIDTH)-1:0];
reg [AXIS_ID_WIDTH-1:0] status_fifo_id[(2**STATUS_FIFO_ADDR_WIDTH)-1:0];
reg [AXIS_DEST_WIDTH-1:0] status_fifo_dest[(2**STATUS_FIFO_ADDR_WIDTH)-1:0];
reg [AXIS_USER_WIDTH-1:0] status_fifo_user[(2**STATUS_FIFO_ADDR_WIDTH)-1:0];
reg status_fifo_last[(2**STATUS_FIFO_ADDR_WIDTH)-1:0];
reg [LEN_WIDTH-1:0] status_fifo_wr_len;
reg [TAG_WIDTH-1:0] status_fifo_wr_tag;
reg [AXIS_ID_WIDTH-1:0] status_fifo_wr_id;
reg [AXIS_DEST_WIDTH-1:0] status_fifo_wr_dest;
reg [AXIS_USER_WIDTH-1:0] status_fifo_wr_user;
reg status_fifo_wr_last;
reg s_axis_write_desc_ready_reg = 1'b0, s_axis_write_desc_ready_next;
reg [LEN_WIDTH-1:0] m_axis_write_desc_status_len_reg = {LEN_WIDTH{1'b0}}, m_axis_write_desc_status_len_next;
reg [TAG_WIDTH-1:0] m_axis_write_desc_status_tag_reg = {TAG_WIDTH{1'b0}}, m_axis_write_desc_status_tag_next;
reg [AXIS_ID_WIDTH-1:0] m_axis_write_desc_status_id_reg = {AXIS_ID_WIDTH{1'b0}}, m_axis_write_desc_status_id_next;
reg [AXIS_DEST_WIDTH-1:0] m_axis_write_desc_status_dest_reg = {AXIS_DEST_WIDTH{1'b0}}, m_axis_write_desc_status_dest_next;
reg [AXIS_USER_WIDTH-1:0] m_axis_write_desc_status_user_reg = {AXIS_USER_WIDTH{1'b0}}, m_axis_write_desc_status_user_next;
reg m_axis_write_desc_status_valid_reg = 1'b0, m_axis_write_desc_status_valid_next;
reg [AXI_ADDR_WIDTH-1:0] m_axi_awaddr_reg = {AXI_ADDR_WIDTH{1'b0}}, m_axi_awaddr_next;
reg [7:0] m_axi_awlen_reg = 8'd0, m_axi_awlen_next;
reg m_axi_awvalid_reg = 1'b0, m_axi_awvalid_next;
reg m_axi_bready_reg = 1'b0, m_axi_bready_next;
reg s_axis_write_data_tready_reg = 1'b0, s_axis_write_data_tready_next;
reg [AXIS_DATA_WIDTH-1:0] save_axis_tdata_reg = {AXIS_DATA_WIDTH{1'b0}};
reg [AXIS_KEEP_WIDTH_INT-1:0] save_axis_tkeep_reg = {AXIS_KEEP_WIDTH_INT{1'b0}};
reg save_axis_tlast_reg = 1'b0;
reg [AXIS_DATA_WIDTH-1:0] shift_axis_tdata;
reg [AXIS_KEEP_WIDTH_INT-1:0] shift_axis_tkeep;
reg shift_axis_tvalid;
reg shift_axis_tlast;
reg shift_axis_input_tready;
reg shift_axis_extra_cycle_reg = 1'b0;
// internal datapath
reg [AXI_DATA_WIDTH-1:0] m_axi_wdata_int;
reg [AXI_STRB_WIDTH-1:0] m_axi_wstrb_int;
reg m_axi_wlast_int;
reg m_axi_wvalid_int;
reg m_axi_wready_int_reg = 1'b0;
wire m_axi_wready_int_early;
assign s_axis_write_desc_ready = s_axis_write_desc_ready_reg;
assign m_axis_write_desc_status_len = m_axis_write_desc_status_len_reg;
assign m_axis_write_desc_status_tag = m_axis_write_desc_status_tag_reg;
assign m_axis_write_desc_status_id = m_axis_write_desc_status_id_reg;
assign m_axis_write_desc_status_dest = m_axis_write_desc_status_dest_reg;
assign m_axis_write_desc_status_user = m_axis_write_desc_status_user_reg;
assign m_axis_write_desc_status_valid = m_axis_write_desc_status_valid_reg;
assign s_axis_write_data_tready = s_axis_write_data_tready_reg;
assign m_axi_awid = {AXI_ID_WIDTH{1'b0}};
assign m_axi_awaddr = m_axi_awaddr_reg;
assign m_axi_awlen = m_axi_awlen_reg;
assign m_axi_awsize = AXI_BURST_SIZE;
assign m_axi_awburst = 2'b01;
assign m_axi_awlock = 1'b0;
assign m_axi_awcache = 4'b0011;
assign m_axi_awprot = 3'b010;
assign m_axi_awvalid = m_axi_awvalid_reg;
assign m_axi_bready = m_axi_bready_reg;
wire [AXI_ADDR_WIDTH-1:0] addr_plus_max_burst = addr_reg + AXI_MAX_BURST_SIZE;
wire [AXI_ADDR_WIDTH-1:0] addr_plus_count = addr_reg + op_word_count_reg;
always @* begin
if (!ENABLE_UNALIGNED || zero_offset_reg) begin
// passthrough if no overlap
shift_axis_tdata = s_axis_write_data_tdata;
shift_axis_tkeep = s_axis_write_data_tkeep;
shift_axis_tvalid = s_axis_write_data_tvalid;
shift_axis_tlast = AXIS_LAST_ENABLE && s_axis_write_data_tlast;
shift_axis_input_tready = 1'b1;
end else if (!AXIS_LAST_ENABLE) begin
shift_axis_tdata = {s_axis_write_data_tdata, save_axis_tdata_reg} >> ((AXIS_KEEP_WIDTH_INT-offset_reg)*AXIS_WORD_SIZE);
shift_axis_tkeep = {s_axis_write_data_tkeep, save_axis_tkeep_reg} >> (AXIS_KEEP_WIDTH_INT-offset_reg);
shift_axis_tvalid = s_axis_write_data_tvalid;
shift_axis_tlast = 1'b0;
shift_axis_input_tready = 1'b1;
end else if (shift_axis_extra_cycle_reg) begin
shift_axis_tdata = {s_axis_write_data_tdata, save_axis_tdata_reg} >> ((AXIS_KEEP_WIDTH_INT-offset_reg)*AXIS_WORD_SIZE);
shift_axis_tkeep = {{AXIS_KEEP_WIDTH_INT{1'b0}}, save_axis_tkeep_reg} >> (AXIS_KEEP_WIDTH_INT-offset_reg);
shift_axis_tvalid = 1'b1;
shift_axis_tlast = save_axis_tlast_reg;
shift_axis_input_tready = flush_save;
end else begin
shift_axis_tdata = {s_axis_write_data_tdata, save_axis_tdata_reg} >> ((AXIS_KEEP_WIDTH_INT-offset_reg)*AXIS_WORD_SIZE);
shift_axis_tkeep = {s_axis_write_data_tkeep, save_axis_tkeep_reg} >> (AXIS_KEEP_WIDTH_INT-offset_reg);
shift_axis_tvalid = s_axis_write_data_tvalid;
shift_axis_tlast = (s_axis_write_data_tlast && ((s_axis_write_data_tkeep & ({AXIS_KEEP_WIDTH_INT{1'b1}} << (AXIS_KEEP_WIDTH_INT-offset_reg))) == 0));
shift_axis_input_tready = 1'b1;
end
end
always @* begin
state_next = STATE_IDLE;
s_axis_write_desc_ready_next = 1'b0;
m_axis_write_desc_status_len_next = m_axis_write_desc_status_len_reg;
m_axis_write_desc_status_tag_next = m_axis_write_desc_status_tag_reg;
m_axis_write_desc_status_id_next = m_axis_write_desc_status_id_reg;
m_axis_write_desc_status_dest_next = m_axis_write_desc_status_dest_reg;
m_axis_write_desc_status_user_next = m_axis_write_desc_status_user_reg;
m_axis_write_desc_status_valid_next = 1'b0;
s_axis_write_data_tready_next = 1'b0;
m_axi_awaddr_next = m_axi_awaddr_reg;
m_axi_awlen_next = m_axi_awlen_reg;
m_axi_awvalid_next = m_axi_awvalid_reg && !m_axi_awready;
m_axi_wdata_int = shift_axis_tdata;
m_axi_wstrb_int = shift_axis_tkeep;
m_axi_wlast_int = 1'b0;
m_axi_wvalid_int = 1'b0;
m_axi_bready_next = 1'b0;
transfer_in_save = 1'b0;
flush_save = 1'b0;
status_fifo_we = 1'b0;
cycle_size = AXIS_KEEP_WIDTH_INT;
addr_next = addr_reg;
offset_next = offset_reg;
strb_offset_mask_next = strb_offset_mask_reg;
zero_offset_next = zero_offset_reg;
last_cycle_offset_next = last_cycle_offset_reg;
length_next = length_reg;
op_word_count_next = op_word_count_reg;
tr_word_count_next = tr_word_count_reg;
input_cycle_count_next = input_cycle_count_reg;
output_cycle_count_next = output_cycle_count_reg;
input_active_next = input_active_reg;
first_cycle_next = first_cycle_reg;
input_last_cycle_next = input_last_cycle_reg;
output_last_cycle_next = output_last_cycle_reg;
last_transfer_next = last_transfer_reg;
status_fifo_rd_ptr_next = status_fifo_rd_ptr_reg;
tag_next = tag_reg;
axis_id_next = axis_id_reg;
axis_dest_next = axis_dest_reg;
axis_user_next = axis_user_reg;
status_fifo_wr_len = length_reg;
status_fifo_wr_tag = tag_reg;
status_fifo_wr_id = axis_id_reg;
status_fifo_wr_dest = axis_dest_reg;
status_fifo_wr_user = axis_user_reg;
status_fifo_wr_last = 1'b0;
case (state_reg)
STATE_IDLE: begin
// idle state - load new descriptor to start operation
flush_save = 1'b1;
s_axis_write_desc_ready_next = enable;
if (ENABLE_UNALIGNED) begin
addr_next = s_axis_write_desc_addr;
offset_next = s_axis_write_desc_addr & OFFSET_MASK;
strb_offset_mask_next = {AXI_STRB_WIDTH{1'b1}} << (s_axis_write_desc_addr & OFFSET_MASK);
zero_offset_next = (s_axis_write_desc_addr & OFFSET_MASK) == 0;
last_cycle_offset_next = offset_next + (s_axis_write_desc_len & OFFSET_MASK);
end else begin
addr_next = s_axis_write_desc_addr & ADDR_MASK;
offset_next = 0;
strb_offset_mask_next = {AXI_STRB_WIDTH{1'b1}};
zero_offset_next = 1'b1;
last_cycle_offset_next = offset_next + (s_axis_write_desc_len & OFFSET_MASK);
end
tag_next = s_axis_write_desc_tag;
op_word_count_next = s_axis_write_desc_len;
first_cycle_next = 1'b1;
length_next = 0;
if (s_axis_write_desc_ready && s_axis_write_desc_valid) begin
s_axis_write_desc_ready_next = 1'b0;
state_next = STATE_START;
end else begin
state_next = STATE_IDLE;
end
end
STATE_START: begin
// start state - initiate new AXI transfer
if (op_word_count_reg <= AXI_MAX_BURST_SIZE - (addr_reg & OFFSET_MASK) || AXI_MAX_BURST_SIZE >= 4096) begin
// packet smaller than max burst size
if (addr_reg[12] != addr_plus_count[12]) begin
// crosses 4k boundary
tr_word_count_next = 13'h1000 - addr_reg[11:0];
end else begin
// does not cross 4k boundary
tr_word_count_next = op_word_count_reg;
end
end else begin
// packet larger than max burst size
if (addr_reg[12] != addr_plus_max_burst[12]) begin
// crosses 4k boundary
tr_word_count_next = 13'h1000 - addr_reg[11:0];
end else begin
// does not cross 4k boundary
tr_word_count_next = AXI_MAX_BURST_SIZE - (addr_reg & OFFSET_MASK);
end
end
input_cycle_count_next = (tr_word_count_next - 1) >> $clog2(AXIS_KEEP_WIDTH_INT);
input_last_cycle_next = input_cycle_count_next == 0;
if (ENABLE_UNALIGNED) begin
output_cycle_count_next = (tr_word_count_next + (addr_reg & OFFSET_MASK) - 1) >> AXI_BURST_SIZE;
end else begin
output_cycle_count_next = (tr_word_count_next - 1) >> AXI_BURST_SIZE;
end
output_last_cycle_next = output_cycle_count_next == 0;
last_transfer_next = tr_word_count_next == op_word_count_reg;
input_active_next = 1'b1;
if (ENABLE_UNALIGNED) begin
if (!first_cycle_reg && last_transfer_next) begin
if (offset_reg >= last_cycle_offset_reg && last_cycle_offset_reg > 0) begin
// last cycle will be served by stored partial cycle
input_active_next = input_cycle_count_next > 0;
input_cycle_count_next = input_cycle_count_next - 1;
end
end
end
if (!m_axi_awvalid_reg) begin
m_axi_awaddr_next = addr_reg;
m_axi_awlen_next = output_cycle_count_next;
m_axi_awvalid_next = s_axis_write_data_tvalid || !first_cycle_reg;
if (m_axi_awvalid_next) begin
addr_next = addr_reg + tr_word_count_next;
op_word_count_next = op_word_count_reg - tr_word_count_next;
s_axis_write_data_tready_next = m_axi_wready_int_early && input_active_next;
state_next = STATE_WRITE;
end else begin
state_next = STATE_START;
end
end else begin
state_next = STATE_START;
end
end
STATE_WRITE: begin
s_axis_write_data_tready_next = m_axi_wready_int_early && (last_transfer_reg || input_active_reg) && shift_axis_input_tready;
if (m_axi_wready_int_reg && ((s_axis_write_data_tready && shift_axis_tvalid) || (!input_active_reg && !last_transfer_reg) || !shift_axis_input_tready)) begin
if (s_axis_write_data_tready && s_axis_write_data_tvalid) begin
transfer_in_save = 1'b1;
axis_id_next = s_axis_write_data_tid;
axis_dest_next = s_axis_write_data_tdest;
axis_user_next = s_axis_write_data_tuser;
end
// update counters
if (first_cycle_reg) begin
length_next = length_reg + (AXIS_KEEP_WIDTH_INT - offset_reg);
end else begin
length_next = length_reg + AXIS_KEEP_WIDTH_INT;
end
if (input_active_reg) begin
input_cycle_count_next = input_cycle_count_reg - 1;
input_active_next = input_cycle_count_reg > 0;
end
input_last_cycle_next = input_cycle_count_next == 0;
output_cycle_count_next = output_cycle_count_reg - 1;
output_last_cycle_next = output_cycle_count_next == 0;
first_cycle_next = 1'b0;
strb_offset_mask_next = {AXI_STRB_WIDTH{1'b1}};
m_axi_wdata_int = shift_axis_tdata;
m_axi_wstrb_int = strb_offset_mask_reg;
m_axi_wvalid_int = 1'b1;
if (AXIS_LAST_ENABLE && s_axis_write_data_tlast) begin
// end of input frame
input_active_next = 1'b0;
s_axis_write_data_tready_next = 1'b0;
end
if (AXIS_LAST_ENABLE && shift_axis_tlast) begin
// end of data packet
if (AXIS_KEEP_ENABLE) begin
cycle_size = AXIS_KEEP_WIDTH_INT;
for (i = AXIS_KEEP_WIDTH_INT-1; i >= 0; i = i - 1) begin
if (~shift_axis_tkeep & strb_offset_mask_reg & (1 << i)) begin
cycle_size = i;
end
end
end else begin
cycle_size = AXIS_KEEP_WIDTH_INT;
end
if (output_last_cycle_reg) begin
m_axi_wlast_int = 1'b1;
// no more data to transfer, finish operation
if (last_transfer_reg && last_cycle_offset_reg > 0) begin
if (AXIS_KEEP_ENABLE && !(shift_axis_tkeep & ~({AXI_STRB_WIDTH{1'b1}} >> (AXI_STRB_WIDTH - last_cycle_offset_reg)))) begin
m_axi_wstrb_int = strb_offset_mask_reg & shift_axis_tkeep;
if (first_cycle_reg) begin
length_next = length_reg + (cycle_size - offset_reg);
end else begin
length_next = length_reg + cycle_size;
end
end else begin
m_axi_wstrb_int = strb_offset_mask_reg & {AXI_STRB_WIDTH{1'b1}} >> (AXI_STRB_WIDTH - last_cycle_offset_reg);
if (first_cycle_reg) begin
length_next = length_reg + (last_cycle_offset_reg - offset_reg);
end else begin
length_next = length_reg + last_cycle_offset_reg;
end
end
end else begin
if (AXIS_KEEP_ENABLE) begin
m_axi_wstrb_int = strb_offset_mask_reg & shift_axis_tkeep;
if (first_cycle_reg) begin
length_next = length_reg + (cycle_size - offset_reg);
end else begin
length_next = length_reg + cycle_size;
end
end
end
// enqueue status FIFO entry for write completion
status_fifo_we = 1'b1;
status_fifo_wr_len = length_next;
status_fifo_wr_tag = tag_reg;
status_fifo_wr_id = axis_id_next;
status_fifo_wr_dest = axis_dest_next;
status_fifo_wr_user = axis_user_next;
status_fifo_wr_last = 1'b1;
s_axis_write_data_tready_next = 1'b0;
s_axis_write_desc_ready_next = enable;
state_next = STATE_IDLE;
end else begin
// more cycles left in burst, finish burst
if (AXIS_KEEP_ENABLE) begin
m_axi_wstrb_int = strb_offset_mask_reg & shift_axis_tkeep;
if (first_cycle_reg) begin
length_next = length_reg + (cycle_size - offset_reg);
end else begin
length_next = length_reg + cycle_size;
end
end
// enqueue status FIFO entry for write completion
status_fifo_we = 1'b1;
status_fifo_wr_len = length_next;
status_fifo_wr_tag = tag_reg;
status_fifo_wr_id = axis_id_next;
status_fifo_wr_dest = axis_dest_next;
status_fifo_wr_user = axis_user_next;
status_fifo_wr_last = 1'b1;
s_axis_write_data_tready_next = 1'b0;
state_next = STATE_FINISH_BURST;
end
end else if (output_last_cycle_reg) begin
m_axi_wlast_int = 1'b1;
if (op_word_count_reg > 0) begin
// current AXI transfer complete, but there is more data to transfer
// enqueue status FIFO entry for write completion
status_fifo_we = 1'b1;
status_fifo_wr_len = length_next;
status_fifo_wr_tag = tag_reg;
status_fifo_wr_id = axis_id_next;
status_fifo_wr_dest = axis_dest_next;
status_fifo_wr_user = axis_user_next;
status_fifo_wr_last = 1'b0;
s_axis_write_data_tready_next = 1'b0;
state_next = STATE_START;
end else begin
// no more data to transfer, finish operation
if (last_cycle_offset_reg > 0) begin
m_axi_wstrb_int = strb_offset_mask_reg & {AXI_STRB_WIDTH{1'b1}} >> (AXI_STRB_WIDTH - last_cycle_offset_reg);
if (first_cycle_reg) begin
length_next = length_reg + (last_cycle_offset_reg - offset_reg);
end else begin
length_next = length_reg + last_cycle_offset_reg;
end
end
// enqueue status FIFO entry for write completion
status_fifo_we = 1'b1;
status_fifo_wr_len = length_next;
status_fifo_wr_tag = tag_reg;
status_fifo_wr_id = axis_id_next;
status_fifo_wr_dest = axis_dest_next;
status_fifo_wr_user = axis_user_next;
status_fifo_wr_last = 1'b1;
if (AXIS_LAST_ENABLE) begin
// not at the end of packet; drop remainder
s_axis_write_data_tready_next = shift_axis_input_tready;
state_next = STATE_DROP_DATA;
end else begin
// no framing; return to idle
s_axis_write_data_tready_next = 1'b0;
s_axis_write_desc_ready_next = enable;
state_next = STATE_IDLE;
end
end
end else begin
s_axis_write_data_tready_next = m_axi_wready_int_early && (last_transfer_reg || input_active_next) && shift_axis_input_tready;
state_next = STATE_WRITE;
end
end else begin
state_next = STATE_WRITE;
end
end
STATE_FINISH_BURST: begin
// finish current AXI burst
if (m_axi_wready_int_reg) begin
// update counters
if (input_active_reg) begin
input_cycle_count_next = input_cycle_count_reg - 1;
input_active_next = input_cycle_count_reg > 0;
end
input_last_cycle_next = input_cycle_count_next == 0;
output_cycle_count_next = output_cycle_count_reg - 1;
output_last_cycle_next = output_cycle_count_next == 0;
m_axi_wdata_int = {AXI_DATA_WIDTH{1'b0}};
m_axi_wstrb_int = {AXI_STRB_WIDTH{1'b0}};
m_axi_wvalid_int = 1'b1;
if (output_last_cycle_reg) begin
// no more data to transfer, finish operation
m_axi_wlast_int = 1'b1;
s_axis_write_data_tready_next = 1'b0;
s_axis_write_desc_ready_next = enable;
state_next = STATE_IDLE;
end else begin
// more cycles in AXI transfer
state_next = STATE_FINISH_BURST;
end
end else begin
state_next = STATE_FINISH_BURST;
end
end
STATE_DROP_DATA: begin
// drop excess AXI stream data
s_axis_write_data_tready_next = shift_axis_input_tready;
if (shift_axis_tvalid) begin
if (s_axis_write_data_tready && s_axis_write_data_tvalid) begin
transfer_in_save = 1'b1;
end
if (shift_axis_tlast) begin
s_axis_write_data_tready_next = 1'b0;
s_axis_write_desc_ready_next = enable;
state_next = STATE_IDLE;
end else begin
state_next = STATE_DROP_DATA;
end
end else begin
state_next = STATE_DROP_DATA;
end
end
endcase
if (status_fifo_rd_ptr_reg != status_fifo_wr_ptr_reg) begin
// status FIFO not empty
if (m_axi_bready && m_axi_bvalid) begin
// got write completion, pop and return status
m_axis_write_desc_status_len_next = status_fifo_len[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
m_axis_write_desc_status_tag_next = status_fifo_tag[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
m_axis_write_desc_status_id_next = status_fifo_id[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
m_axis_write_desc_status_dest_next = status_fifo_dest[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
m_axis_write_desc_status_user_next = status_fifo_user[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
m_axis_write_desc_status_valid_next = status_fifo_last[status_fifo_rd_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]];
status_fifo_rd_ptr_next = status_fifo_rd_ptr_reg + 1;
m_axi_bready_next = 1'b0;
end else begin
// wait for write completion
m_axi_bready_next = 1'b1;
end
end
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
s_axis_write_desc_ready_reg <= 1'b0;
m_axis_write_desc_status_valid_reg <= 1'b0;
s_axis_write_data_tready_reg <= 1'b0;
m_axi_awvalid_reg <= 1'b0;
m_axi_bready_reg <= 1'b0;
save_axis_tlast_reg <= 1'b0;
shift_axis_extra_cycle_reg <= 1'b0;
status_fifo_wr_ptr_reg <= 0;
status_fifo_rd_ptr_reg <= 0;
end else begin
state_reg <= state_next;
s_axis_write_desc_ready_reg <= s_axis_write_desc_ready_next;
m_axis_write_desc_status_valid_reg <= m_axis_write_desc_status_valid_next;
s_axis_write_data_tready_reg <= s_axis_write_data_tready_next;
m_axi_awvalid_reg <= m_axi_awvalid_next;
m_axi_bready_reg <= m_axi_bready_next;
// datapath
if (flush_save) begin
save_axis_tlast_reg <= 1'b0;
shift_axis_extra_cycle_reg <= 1'b0;
end else if (transfer_in_save) begin
save_axis_tlast_reg <= s_axis_write_data_tlast;
shift_axis_extra_cycle_reg <= s_axis_write_data_tlast & ((s_axis_write_data_tkeep >> (AXIS_KEEP_WIDTH_INT-offset_reg)) != 0);
end
if (status_fifo_we) begin
status_fifo_wr_ptr_reg <= status_fifo_wr_ptr_reg + 1;
end
status_fifo_rd_ptr_reg <= status_fifo_rd_ptr_next;
end
m_axis_write_desc_status_len_reg <= m_axis_write_desc_status_len_next;
m_axis_write_desc_status_tag_reg <= m_axis_write_desc_status_tag_next;
m_axis_write_desc_status_id_reg <= m_axis_write_desc_status_id_next;
m_axis_write_desc_status_dest_reg <= m_axis_write_desc_status_dest_next;
m_axis_write_desc_status_user_reg <= m_axis_write_desc_status_user_next;
m_axi_awaddr_reg <= m_axi_awaddr_next;
m_axi_awlen_reg <= m_axi_awlen_next;
addr_reg <= addr_next;
offset_reg <= offset_next;
strb_offset_mask_reg <= strb_offset_mask_next;
zero_offset_reg <= zero_offset_next;
last_cycle_offset_reg <= last_cycle_offset_next;
length_reg <= length_next;
op_word_count_reg <= op_word_count_next;
tr_word_count_reg <= tr_word_count_next;
input_cycle_count_reg <= input_cycle_count_next;
output_cycle_count_reg <= output_cycle_count_next;
input_active_reg <= input_active_next;
first_cycle_reg <= first_cycle_next;
input_last_cycle_reg <= input_last_cycle_next;
output_last_cycle_reg <= output_last_cycle_next;
last_transfer_reg <= last_transfer_next;
tag_reg <= tag_next;
axis_id_reg <= axis_id_next;
axis_dest_reg <= axis_dest_next;
axis_user_reg <= axis_user_next;
if (flush_save) begin
save_axis_tkeep_reg <= {AXIS_KEEP_WIDTH_INT{1'b0}};
end else if (transfer_in_save) begin
save_axis_tdata_reg <= s_axis_write_data_tdata;
save_axis_tkeep_reg <= AXIS_KEEP_ENABLE ? s_axis_write_data_tkeep : {AXIS_KEEP_WIDTH_INT{1'b1}};
end
if (status_fifo_we) begin
status_fifo_len[status_fifo_wr_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]] <= status_fifo_wr_len;
status_fifo_tag[status_fifo_wr_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]] <= status_fifo_wr_tag;
status_fifo_id[status_fifo_wr_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]] <= status_fifo_wr_id;
status_fifo_dest[status_fifo_wr_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]] <= status_fifo_wr_dest;
status_fifo_user[status_fifo_wr_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]] <= status_fifo_wr_user;
status_fifo_last[status_fifo_wr_ptr_reg[STATUS_FIFO_ADDR_WIDTH-1:0]] <= status_fifo_wr_last;
status_fifo_wr_ptr_reg <= status_fifo_wr_ptr_reg + 1;
end
end
// output datapath logic
reg [AXI_DATA_WIDTH-1:0] m_axi_wdata_reg = {AXI_DATA_WIDTH{1'b0}};
reg [AXI_STRB_WIDTH-1:0] m_axi_wstrb_reg = {AXI_STRB_WIDTH{1'b0}};
reg m_axi_wlast_reg = 1'b0;
reg m_axi_wvalid_reg = 1'b0, m_axi_wvalid_next;
reg [AXI_DATA_WIDTH-1:0] temp_m_axi_wdata_reg = {AXI_DATA_WIDTH{1'b0}};
reg [AXI_STRB_WIDTH-1:0] temp_m_axi_wstrb_reg = {AXI_STRB_WIDTH{1'b0}};
reg temp_m_axi_wlast_reg = 1'b0;
reg temp_m_axi_wvalid_reg = 1'b0, temp_m_axi_wvalid_next;
// datapath control
reg store_axi_w_int_to_output;
reg store_axi_w_int_to_temp;
reg store_axi_w_temp_to_output;
assign m_axi_wdata = m_axi_wdata_reg;
assign m_axi_wstrb = m_axi_wstrb_reg;
assign m_axi_wvalid = m_axi_wvalid_reg;
assign m_axi_wlast = m_axi_wlast_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_axi_wready_int_early = m_axi_wready || (!temp_m_axi_wvalid_reg && (!m_axi_wvalid_reg || !m_axi_wvalid_int));
always @* begin
// transfer sink ready state to source
m_axi_wvalid_next = m_axi_wvalid_reg;
temp_m_axi_wvalid_next = temp_m_axi_wvalid_reg;
store_axi_w_int_to_output = 1'b0;
store_axi_w_int_to_temp = 1'b0;
store_axi_w_temp_to_output = 1'b0;
if (m_axi_wready_int_reg) begin
// input is ready
if (m_axi_wready || !m_axi_wvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axi_wvalid_next = m_axi_wvalid_int;
store_axi_w_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axi_wvalid_next = m_axi_wvalid_int;
store_axi_w_int_to_temp = 1'b1;
end
end else if (m_axi_wready) begin
// input is not ready, but output is ready
m_axi_wvalid_next = temp_m_axi_wvalid_reg;
temp_m_axi_wvalid_next = 1'b0;
store_axi_w_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_axi_wvalid_reg <= 1'b0;
m_axi_wready_int_reg <= 1'b0;
temp_m_axi_wvalid_reg <= 1'b0;
end else begin
m_axi_wvalid_reg <= m_axi_wvalid_next;
m_axi_wready_int_reg <= m_axi_wready_int_early;
temp_m_axi_wvalid_reg <= temp_m_axi_wvalid_next;
end
// datapath
if (store_axi_w_int_to_output) begin
m_axi_wdata_reg <= m_axi_wdata_int;
m_axi_wstrb_reg <= m_axi_wstrb_int;
m_axi_wlast_reg <= m_axi_wlast_int;
end else if (store_axi_w_temp_to_output) begin
m_axi_wdata_reg <= temp_m_axi_wdata_reg;
m_axi_wstrb_reg <= temp_m_axi_wstrb_reg;
m_axi_wlast_reg <= temp_m_axi_wlast_reg;
end
if (store_axi_w_int_to_temp) begin
temp_m_axi_wdata_reg <= m_axi_wdata_int;
temp_m_axi_wstrb_reg <= m_axi_wstrb_int;
temp_m_axi_wlast_reg <= m_axi_wlast_int;
end
end
endmodule
/*
Copyright (c) 2019 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 dual port RAM
*/
module axi_dp_ram #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 16,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Width of ID signal
parameter ID_WIDTH = 8,
// Extra pipeline register on output port A
parameter A_PIPELINE_OUTPUT = 0,
// Extra pipeline register on output port B
parameter B_PIPELINE_OUTPUT = 0,
// Interleave read and write burst cycles on port A
parameter A_INTERLEAVE = 0,
// Interleave read and write burst cycles on port B
parameter B_INTERLEAVE = 0
)
(
input wire a_clk,
input wire a_rst,
input wire b_clk,
input wire b_rst,
input wire [ID_WIDTH-1:0] s_axi_a_awid,
input wire [ADDR_WIDTH-1:0] s_axi_a_awaddr,
input wire [7:0] s_axi_a_awlen,
input wire [2:0] s_axi_a_awsize,
input wire [1:0] s_axi_a_awburst,
input wire s_axi_a_awlock,
input wire [3:0] s_axi_a_awcache,
input wire [2:0] s_axi_a_awprot,
input wire s_axi_a_awvalid,
output wire s_axi_a_awready,
input wire [DATA_WIDTH-1:0] s_axi_a_wdata,
input wire [STRB_WIDTH-1:0] s_axi_a_wstrb,
input wire s_axi_a_wlast,
input wire s_axi_a_wvalid,
output wire s_axi_a_wready,
output wire [ID_WIDTH-1:0] s_axi_a_bid,
output wire [1:0] s_axi_a_bresp,
output wire s_axi_a_bvalid,
input wire s_axi_a_bready,
input wire [ID_WIDTH-1:0] s_axi_a_arid,
input wire [ADDR_WIDTH-1:0] s_axi_a_araddr,
input wire [7:0] s_axi_a_arlen,
input wire [2:0] s_axi_a_arsize,
input wire [1:0] s_axi_a_arburst,
input wire s_axi_a_arlock,
input wire [3:0] s_axi_a_arcache,
input wire [2:0] s_axi_a_arprot,
input wire s_axi_a_arvalid,
output wire s_axi_a_arready,
output wire [ID_WIDTH-1:0] s_axi_a_rid,
output wire [DATA_WIDTH-1:0] s_axi_a_rdata,
output wire [1:0] s_axi_a_rresp,
output wire s_axi_a_rlast,
output wire s_axi_a_rvalid,
input wire s_axi_a_rready,
input wire [ID_WIDTH-1:0] s_axi_b_awid,
input wire [ADDR_WIDTH-1:0] s_axi_b_awaddr,
input wire [7:0] s_axi_b_awlen,
input wire [2:0] s_axi_b_awsize,
input wire [1:0] s_axi_b_awburst,
input wire s_axi_b_awlock,
input wire [3:0] s_axi_b_awcache,
input wire [2:0] s_axi_b_awprot,
input wire s_axi_b_awvalid,
output wire s_axi_b_awready,
input wire [DATA_WIDTH-1:0] s_axi_b_wdata,
input wire [STRB_WIDTH-1:0] s_axi_b_wstrb,
input wire s_axi_b_wlast,
input wire s_axi_b_wvalid,
output wire s_axi_b_wready,
output wire [ID_WIDTH-1:0] s_axi_b_bid,
output wire [1:0] s_axi_b_bresp,
output wire s_axi_b_bvalid,
input wire s_axi_b_bready,
input wire [ID_WIDTH-1:0] s_axi_b_arid,
input wire [ADDR_WIDTH-1:0] s_axi_b_araddr,
input wire [7:0] s_axi_b_arlen,
input wire [2:0] s_axi_b_arsize,
input wire [1:0] s_axi_b_arburst,
input wire s_axi_b_arlock,
input wire [3:0] s_axi_b_arcache,
input wire [2:0] s_axi_b_arprot,
input wire s_axi_b_arvalid,
output wire s_axi_b_arready,
output wire [ID_WIDTH-1:0] s_axi_b_rid,
output wire [DATA_WIDTH-1:0] s_axi_b_rdata,
output wire [1:0] s_axi_b_rresp,
output wire s_axi_b_rlast,
output wire s_axi_b_rvalid,
input wire s_axi_b_rready
);
parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(STRB_WIDTH);
parameter WORD_WIDTH = STRB_WIDTH;
parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH;
// bus width assertions
initial begin
if (WORD_SIZE * STRB_WIDTH != DATA_WIDTH) begin
$error("Error: AXI data width not evenly divisble (instance %m)");
$finish;
end
if (2**$clog2(WORD_WIDTH) != WORD_WIDTH) begin
$error("Error: AXI word width must be even power of two (instance %m)");
$finish;
end
end
wire [ID_WIDTH-1:0] ram_a_cmd_id;
wire [ADDR_WIDTH-1:0] ram_a_cmd_addr;
wire [DATA_WIDTH-1:0] ram_a_cmd_wr_data;
wire [STRB_WIDTH-1:0] ram_a_cmd_wr_strb;
wire ram_a_cmd_wr_en;
wire ram_a_cmd_rd_en;
wire ram_a_cmd_last;
reg ram_a_cmd_ready_reg = 1'b1;
reg [ID_WIDTH-1:0] ram_a_rd_resp_id_reg = {ID_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] ram_a_rd_resp_data_reg = {DATA_WIDTH{1'b0}};
reg ram_a_rd_resp_last_reg = 1'b0;
reg ram_a_rd_resp_valid_reg = 1'b0;
wire ram_a_rd_resp_ready;
wire [ID_WIDTH-1:0] ram_b_cmd_id;
wire [ADDR_WIDTH-1:0] ram_b_cmd_addr;
wire [DATA_WIDTH-1:0] ram_b_cmd_wr_data;
wire [STRB_WIDTH-1:0] ram_b_cmd_wr_strb;
wire ram_b_cmd_wr_en;
wire ram_b_cmd_rd_en;
wire ram_b_cmd_last;
reg ram_b_cmd_ready_reg = 1'b1;
reg [ID_WIDTH-1:0] ram_b_rd_resp_id_reg = {ID_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] ram_b_rd_resp_data_reg = {DATA_WIDTH{1'b0}};
reg ram_b_rd_resp_last_reg = 1'b0;
reg ram_b_rd_resp_valid_reg = 1'b0;
wire ram_b_rd_resp_ready;
axi_ram_wr_rd_if #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.ID_WIDTH(ID_WIDTH),
.AWUSER_ENABLE(0),
.WUSER_ENABLE(0),
.BUSER_ENABLE(0),
.ARUSER_ENABLE(0),
.RUSER_ENABLE(0),
.PIPELINE_OUTPUT(A_PIPELINE_OUTPUT),
.INTERLEAVE(A_INTERLEAVE)
)
a_if (
.clk(a_clk),
.rst(a_rst),
/*
* AXI slave interface
*/
.s_axi_awid(s_axi_a_awid),
.s_axi_awaddr(s_axi_a_awaddr),
.s_axi_awlen(s_axi_a_awlen),
.s_axi_awsize(s_axi_a_awsize),
.s_axi_awburst(s_axi_a_awburst),
.s_axi_awlock(s_axi_a_awlock),
.s_axi_awcache(s_axi_a_awcache),
.s_axi_awprot(s_axi_a_awprot),
.s_axi_awqos(4'd0),
.s_axi_awregion(4'd0),
.s_axi_awuser(0),
.s_axi_awvalid(s_axi_a_awvalid),
.s_axi_awready(s_axi_a_awready),
.s_axi_wdata(s_axi_a_wdata),
.s_axi_wstrb(s_axi_a_wstrb),
.s_axi_wlast(s_axi_a_wlast),
.s_axi_wuser(0),
.s_axi_wvalid(s_axi_a_wvalid),
.s_axi_wready(s_axi_a_wready),
.s_axi_bid(s_axi_a_bid),
.s_axi_bresp(s_axi_a_bresp),
.s_axi_buser(),
.s_axi_bvalid(s_axi_a_bvalid),
.s_axi_bready(s_axi_a_bready),
.s_axi_arid(s_axi_a_arid),
.s_axi_araddr(s_axi_a_araddr),
.s_axi_arlen(s_axi_a_arlen),
.s_axi_arsize(s_axi_a_arsize),
.s_axi_arburst(s_axi_a_arburst),
.s_axi_arlock(s_axi_a_arlock),
.s_axi_arcache(s_axi_a_arcache),
.s_axi_arprot(s_axi_a_arprot),
.s_axi_arqos(4'd0),
.s_axi_arregion(4'd0),
.s_axi_aruser(0),
.s_axi_arvalid(s_axi_a_arvalid),
.s_axi_arready(s_axi_a_arready),
.s_axi_rid(s_axi_a_rid),
.s_axi_rdata(s_axi_a_rdata),
.s_axi_rresp(s_axi_a_rresp),
.s_axi_rlast(s_axi_a_rlast),
.s_axi_ruser(),
.s_axi_rvalid(s_axi_a_rvalid),
.s_axi_rready(s_axi_a_rready),
/*
* RAM interface
*/
.ram_cmd_id(ram_a_cmd_id),
.ram_cmd_addr(ram_a_cmd_addr),
.ram_cmd_lock(),
.ram_cmd_cache(),
.ram_cmd_prot(),
.ram_cmd_qos(),
.ram_cmd_region(),
.ram_cmd_auser(),
.ram_cmd_wr_data(ram_a_cmd_wr_data),
.ram_cmd_wr_strb(ram_a_cmd_wr_strb),
.ram_cmd_wr_user(),
.ram_cmd_wr_en(ram_a_cmd_wr_en),
.ram_cmd_rd_en(ram_a_cmd_rd_en),
.ram_cmd_last(ram_a_cmd_last),
.ram_cmd_ready(ram_a_cmd_ready_reg),
.ram_rd_resp_id(ram_a_rd_resp_id_reg),
.ram_rd_resp_data(ram_a_rd_resp_data_reg),
.ram_rd_resp_last(ram_a_rd_resp_last_reg),
.ram_rd_resp_user(0),
.ram_rd_resp_valid(ram_a_rd_resp_valid_reg),
.ram_rd_resp_ready(ram_a_rd_resp_ready)
);
axi_ram_wr_rd_if #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.ID_WIDTH(ID_WIDTH),
.AWUSER_ENABLE(0),
.WUSER_ENABLE(0),
.BUSER_ENABLE(0),
.ARUSER_ENABLE(0),
.RUSER_ENABLE(0),
.PIPELINE_OUTPUT(B_PIPELINE_OUTPUT),
.INTERLEAVE(B_INTERLEAVE)
)
b_if (
.clk(b_clk),
.rst(b_rst),
/*
* AXI slave interface
*/
.s_axi_awid(s_axi_b_awid),
.s_axi_awaddr(s_axi_b_awaddr),
.s_axi_awlen(s_axi_b_awlen),
.s_axi_awsize(s_axi_b_awsize),
.s_axi_awburst(s_axi_b_awburst),
.s_axi_awlock(s_axi_b_awlock),
.s_axi_awcache(s_axi_b_awcache),
.s_axi_awprot(s_axi_b_awprot),
.s_axi_awqos(4'd0),
.s_axi_awregion(4'd0),
.s_axi_awuser(0),
.s_axi_awvalid(s_axi_b_awvalid),
.s_axi_awready(s_axi_b_awready),
.s_axi_wdata(s_axi_b_wdata),
.s_axi_wstrb(s_axi_b_wstrb),
.s_axi_wlast(s_axi_b_wlast),
.s_axi_wuser(0),
.s_axi_wvalid(s_axi_b_wvalid),
.s_axi_wready(s_axi_b_wready),
.s_axi_bid(s_axi_b_bid),
.s_axi_bresp(s_axi_b_bresp),
.s_axi_buser(),
.s_axi_bvalid(s_axi_b_bvalid),
.s_axi_bready(s_axi_b_bready),
.s_axi_arid(s_axi_b_arid),
.s_axi_araddr(s_axi_b_araddr),
.s_axi_arlen(s_axi_b_arlen),
.s_axi_arsize(s_axi_b_arsize),
.s_axi_arburst(s_axi_b_arburst),
.s_axi_arlock(s_axi_b_arlock),
.s_axi_arcache(s_axi_b_arcache),
.s_axi_arprot(s_axi_b_arprot),
.s_axi_arqos(4'd0),
.s_axi_arregion(4'd0),
.s_axi_aruser(0),
.s_axi_arvalid(s_axi_b_arvalid),
.s_axi_arready(s_axi_b_arready),
.s_axi_rid(s_axi_b_rid),
.s_axi_rdata(s_axi_b_rdata),
.s_axi_rresp(s_axi_b_rresp),
.s_axi_rlast(s_axi_b_rlast),
.s_axi_ruser(),
.s_axi_rvalid(s_axi_b_rvalid),
.s_axi_rready(s_axi_b_rready),
/*
* RAM interface
*/
.ram_cmd_id(ram_b_cmd_id),
.ram_cmd_addr(ram_b_cmd_addr),
.ram_cmd_lock(),
.ram_cmd_cache(),
.ram_cmd_prot(),
.ram_cmd_qos(),
.ram_cmd_region(),
.ram_cmd_auser(),
.ram_cmd_wr_data(ram_b_cmd_wr_data),
.ram_cmd_wr_strb(ram_b_cmd_wr_strb),
.ram_cmd_wr_user(),
.ram_cmd_wr_en(ram_b_cmd_wr_en),
.ram_cmd_rd_en(ram_b_cmd_rd_en),
.ram_cmd_last(ram_b_cmd_last),
.ram_cmd_ready(ram_b_cmd_ready_reg),
.ram_rd_resp_id(ram_b_rd_resp_id_reg),
.ram_rd_resp_data(ram_b_rd_resp_data_reg),
.ram_rd_resp_last(ram_b_rd_resp_last_reg),
.ram_rd_resp_user(0),
.ram_rd_resp_valid(ram_b_rd_resp_valid_reg),
.ram_rd_resp_ready(ram_b_rd_resp_ready)
);
// (* RAM_STYLE="BLOCK" *)
reg [DATA_WIDTH-1:0] mem[(2**VALID_ADDR_WIDTH)-1:0];
wire [VALID_ADDR_WIDTH-1:0] addr_a_valid = ram_a_cmd_addr >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
wire [VALID_ADDR_WIDTH-1:0] addr_b_valid = ram_b_cmd_addr >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
integer i, j;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (i = 0; i < 2**ADDR_WIDTH; i = i + 2**(ADDR_WIDTH/2)) begin
for (j = i; j < i + 2**(ADDR_WIDTH/2); j = j + 1) begin
mem[j] = 0;
end
end
end
always @(posedge a_clk) begin
ram_a_rd_resp_valid_reg <= ram_a_rd_resp_valid_reg && !ram_a_rd_resp_ready;
ram_a_cmd_ready_reg <= !ram_a_rd_resp_valid_reg || ram_a_rd_resp_ready;
if (ram_a_cmd_ready_reg && ram_a_cmd_rd_en) begin
ram_a_rd_resp_id_reg <= ram_a_cmd_id;
ram_a_rd_resp_data_reg <= mem[addr_a_valid];
ram_a_rd_resp_last_reg <= ram_a_cmd_last;
ram_a_rd_resp_valid_reg <= 1'b1;
ram_a_cmd_ready_reg <= ram_a_rd_resp_ready;
end else if (ram_a_cmd_ready_reg && ram_a_cmd_wr_en) begin
for (i = 0; i < WORD_WIDTH; i = i + 1) begin
if (ram_a_cmd_wr_strb[i]) begin
mem[addr_a_valid][WORD_SIZE*i +: WORD_SIZE] <= ram_a_cmd_wr_data[WORD_SIZE*i +: WORD_SIZE];
end
end
end
if (a_rst) begin
ram_a_cmd_ready_reg <= 1'b1;
ram_a_rd_resp_valid_reg <= 1'b0;
end
end
always @(posedge b_clk) begin
ram_b_rd_resp_valid_reg <= ram_b_rd_resp_valid_reg && !ram_b_rd_resp_ready;
ram_b_cmd_ready_reg <= !ram_b_rd_resp_valid_reg || ram_b_rd_resp_ready;
if (ram_b_cmd_ready_reg && ram_b_cmd_rd_en) begin
ram_b_rd_resp_id_reg <= ram_b_cmd_id;
ram_b_rd_resp_data_reg <= mem[addr_b_valid];
ram_b_rd_resp_last_reg <= ram_b_cmd_last;
ram_b_rd_resp_valid_reg <= 1'b1;
ram_b_cmd_ready_reg <= ram_b_rd_resp_ready;
end else if (ram_b_cmd_ready_reg && ram_b_cmd_wr_en) begin
for (i = 0; i < WORD_WIDTH; i = i + 1) begin
if (ram_b_cmd_wr_strb[i]) begin
mem[addr_b_valid][WORD_SIZE*i +: WORD_SIZE] <= ram_b_cmd_wr_data[WORD_SIZE*i +: WORD_SIZE];
end
end
end
if (b_rst) begin
ram_a_cmd_ready_reg <= 1'b1;
ram_b_rd_resp_valid_reg <= 1'b0;
end
end
endmodule
/*
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 FIFO
*/
module axi_fifo #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Width of ID signal
parameter ID_WIDTH = 8,
// Propagate awuser signal
parameter AWUSER_ENABLE = 0,
// Width of awuser signal
parameter AWUSER_WIDTH = 1,
// Propagate wuser signal
parameter WUSER_ENABLE = 0,
// Width of wuser signal
parameter WUSER_WIDTH = 1,
// Propagate buser signal
parameter BUSER_ENABLE = 0,
// Width of buser signal
parameter BUSER_WIDTH = 1,
// Propagate aruser signal
parameter ARUSER_ENABLE = 0,
// Width of aruser signal
parameter ARUSER_WIDTH = 1,
// Propagate ruser signal
parameter RUSER_ENABLE = 0,
// Width of ruser signal
parameter RUSER_WIDTH = 1,
// Write data FIFO depth (cycles)
parameter WRITE_FIFO_DEPTH = 32,
// Read data FIFO depth (cycles)
parameter READ_FIFO_DEPTH = 32,
// Hold write address until write data in FIFO, if possible
parameter WRITE_FIFO_DELAY = 0,
// Hold read address until space available in FIFO for data, if possible
parameter READ_FIFO_DELAY = 0
)
(
input wire clk,
input wire rst,
/*
* AXI slave interface
*/
input wire [ID_WIDTH-1:0] s_axi_awid,
input wire [ADDR_WIDTH-1:0] s_axi_awaddr,
input wire [7:0] s_axi_awlen,
input wire [2:0] s_axi_awsize,
input wire [1:0] s_axi_awburst,
input wire s_axi_awlock,
input wire [3:0] s_axi_awcache,
input wire [2:0] s_axi_awprot,
input wire [3:0] s_axi_awqos,
input wire [3:0] s_axi_awregion,
input wire [AWUSER_WIDTH-1:0] s_axi_awuser,
input wire s_axi_awvalid,
output wire s_axi_awready,
input wire [DATA_WIDTH-1:0] s_axi_wdata,
input wire [STRB_WIDTH-1:0] s_axi_wstrb,
input wire s_axi_wlast,
input wire [WUSER_WIDTH-1:0] s_axi_wuser,
input wire s_axi_wvalid,
output wire s_axi_wready,
output wire [ID_WIDTH-1:0] s_axi_bid,
output wire [1:0] s_axi_bresp,
output wire [BUSER_WIDTH-1:0] s_axi_buser,
output wire s_axi_bvalid,
input wire s_axi_bready,
input wire [ID_WIDTH-1:0] s_axi_arid,
input wire [ADDR_WIDTH-1:0] s_axi_araddr,
input wire [7:0] s_axi_arlen,
input wire [2:0] s_axi_arsize,
input wire [1:0] s_axi_arburst,
input wire s_axi_arlock,
input wire [3:0] s_axi_arcache,
input wire [2:0] s_axi_arprot,
input wire [3:0] s_axi_arqos,
input wire [3:0] s_axi_arregion,
input wire [ARUSER_WIDTH-1:0] s_axi_aruser,
input wire s_axi_arvalid,
output wire s_axi_arready,
output wire [ID_WIDTH-1:0] s_axi_rid,
output wire [DATA_WIDTH-1:0] s_axi_rdata,
output wire [1:0] s_axi_rresp,
output wire s_axi_rlast,
output wire [RUSER_WIDTH-1:0] s_axi_ruser,
output wire s_axi_rvalid,
input wire s_axi_rready,
/*
* AXI master interface
*/
output wire [ID_WIDTH-1:0] m_axi_awid,
output wire [ADDR_WIDTH-1:0] m_axi_awaddr,
output wire [7:0] m_axi_awlen,
output wire [2:0] m_axi_awsize,
output wire [1:0] m_axi_awburst,
output wire m_axi_awlock,
output wire [3:0] m_axi_awcache,
output wire [2:0] m_axi_awprot,
output wire [3:0] m_axi_awqos,
output wire [3:0] m_axi_awregion,
output wire [AWUSER_WIDTH-1:0] m_axi_awuser,
output wire m_axi_awvalid,
input wire m_axi_awready,
output wire [DATA_WIDTH-1:0] m_axi_wdata,
output wire [STRB_WIDTH-1:0] m_axi_wstrb,
output wire m_axi_wlast,
output wire [WUSER_WIDTH-1:0] m_axi_wuser,
output wire m_axi_wvalid,
input wire m_axi_wready,
input wire [ID_WIDTH-1:0] m_axi_bid,
input wire [1:0] m_axi_bresp,
input wire [BUSER_WIDTH-1:0] m_axi_buser,
input wire m_axi_bvalid,
output wire m_axi_bready,
output wire [ID_WIDTH-1:0] m_axi_arid,
output wire [ADDR_WIDTH-1:0] m_axi_araddr,
output wire [7:0] m_axi_arlen,
output wire [2:0] m_axi_arsize,
output wire [1:0] m_axi_arburst,
output wire m_axi_arlock,
output wire [3:0] m_axi_arcache,
output wire [2:0] m_axi_arprot,
output wire [3:0] m_axi_arqos,
output wire [3:0] m_axi_arregion,
output wire [ARUSER_WIDTH-1:0] m_axi_aruser,
output wire m_axi_arvalid,
input wire m_axi_arready,
input wire [ID_WIDTH-1:0] m_axi_rid,
input wire [DATA_WIDTH-1:0] m_axi_rdata,
input wire [1:0] m_axi_rresp,
input wire m_axi_rlast,
input wire [RUSER_WIDTH-1:0] m_axi_ruser,
input wire m_axi_rvalid,
output wire m_axi_rready
);
axi_fifo_wr #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.ID_WIDTH(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),
.FIFO_DEPTH(WRITE_FIFO_DEPTH),
.FIFO_DELAY(WRITE_FIFO_DELAY)
)
axi_fifo_wr_inst (
.clk(clk),
.rst(rst),
/*
* AXI slave interface
*/
.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_awregion(s_axi_awregion),
.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 interface
*/
.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_fifo_rd #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.ID_WIDTH(ID_WIDTH),
.ARUSER_ENABLE(ARUSER_ENABLE),
.ARUSER_WIDTH(ARUSER_WIDTH),
.RUSER_ENABLE(RUSER_ENABLE),
.RUSER_WIDTH(RUSER_WIDTH),
.FIFO_DEPTH(READ_FIFO_DEPTH),
.FIFO_DELAY(READ_FIFO_DELAY)
)
axi_fifo_rd_inst (
.clk(clk),
.rst(rst),
/*
* AXI slave interface
*/
.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_arregion(s_axi_arregion),
.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 interface
*/
.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
/*
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 FIFO (read)
*/
module axi_fifo_rd #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Width of ID signal
parameter ID_WIDTH = 8,
// Propagate aruser signal
parameter ARUSER_ENABLE = 0,
// Width of aruser signal
parameter ARUSER_WIDTH = 1,
// Propagate ruser signal
parameter RUSER_ENABLE = 0,
// Width of ruser signal
parameter RUSER_WIDTH = 1,
// Read data FIFO depth (cycles)
parameter FIFO_DEPTH = 32,
// Hold read address until space available in FIFO for data, if possible
parameter FIFO_DELAY = 0
)
(
input wire clk,
input wire rst,
/*
* AXI slave interface
*/
input wire [ID_WIDTH-1:0] s_axi_arid,
input wire [ADDR_WIDTH-1:0] s_axi_araddr,
input wire [7:0] s_axi_arlen,
input wire [2:0] s_axi_arsize,
input wire [1:0] s_axi_arburst,
input wire s_axi_arlock,
input wire [3:0] s_axi_arcache,
input wire [2:0] s_axi_arprot,
input wire [3:0] s_axi_arqos,
input wire [3:0] s_axi_arregion,
input wire [ARUSER_WIDTH-1:0] s_axi_aruser,
input wire s_axi_arvalid,
output wire s_axi_arready,
output wire [ID_WIDTH-1:0] s_axi_rid,
output wire [DATA_WIDTH-1:0] s_axi_rdata,
output wire [1:0] s_axi_rresp,
output wire s_axi_rlast,
output wire [RUSER_WIDTH-1:0] s_axi_ruser,
output wire s_axi_rvalid,
input wire s_axi_rready,
/*
* AXI master interface
*/
output wire [ID_WIDTH-1:0] m_axi_arid,
output wire [ADDR_WIDTH-1:0] m_axi_araddr,
output wire [7:0] m_axi_arlen,
output wire [2:0] m_axi_arsize,
output wire [1:0] m_axi_arburst,
output wire m_axi_arlock,
output wire [3:0] m_axi_arcache,
output wire [2:0] m_axi_arprot,
output wire [3:0] m_axi_arqos,
output wire [3:0] m_axi_arregion,
output wire [ARUSER_WIDTH-1:0] m_axi_aruser,
output wire m_axi_arvalid,
input wire m_axi_arready,
input wire [ID_WIDTH-1:0] m_axi_rid,
input wire [DATA_WIDTH-1:0] m_axi_rdata,
input wire [1:0] m_axi_rresp,
input wire m_axi_rlast,
input wire [RUSER_WIDTH-1:0] m_axi_ruser,
input wire m_axi_rvalid,
output wire m_axi_rready
);
parameter LAST_OFFSET = DATA_WIDTH;
parameter ID_OFFSET = LAST_OFFSET + 1;
parameter RESP_OFFSET = ID_OFFSET + ID_WIDTH;
parameter RUSER_OFFSET = RESP_OFFSET + 2;
parameter RWIDTH = RUSER_OFFSET + (RUSER_ENABLE ? RUSER_WIDTH : 0);
parameter FIFO_ADDR_WIDTH = $clog2(FIFO_DEPTH);
reg [FIFO_ADDR_WIDTH:0] wr_ptr_reg = {FIFO_ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
reg [FIFO_ADDR_WIDTH:0] wr_addr_reg = {FIFO_ADDR_WIDTH+1{1'b0}};
reg [FIFO_ADDR_WIDTH:0] rd_ptr_reg = {FIFO_ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg [FIFO_ADDR_WIDTH:0] rd_addr_reg = {FIFO_ADDR_WIDTH+1{1'b0}};
reg [RWIDTH-1:0] mem[(2**FIFO_ADDR_WIDTH)-1:0];
reg [RWIDTH-1:0] mem_read_data_reg;
reg mem_read_data_valid_reg = 1'b0, mem_read_data_valid_next;
wire [RWIDTH-1:0] m_axi_r;
reg [RWIDTH-1:0] s_axi_r_reg;
reg s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next;
// full when first MSB different but rest same
wire full = ((wr_ptr_reg[FIFO_ADDR_WIDTH] != rd_ptr_reg[FIFO_ADDR_WIDTH]) &&
(wr_ptr_reg[FIFO_ADDR_WIDTH-1:0] == rd_ptr_reg[FIFO_ADDR_WIDTH-1:0]));
// empty when pointers match exactly
wire empty = wr_ptr_reg == rd_ptr_reg;
// control signals
reg write;
reg read;
reg store_output;
assign m_axi_rready = !full;
generate
assign m_axi_r[DATA_WIDTH-1:0] = m_axi_rdata;
assign m_axi_r[LAST_OFFSET] = m_axi_rlast;
assign m_axi_r[ID_OFFSET +: ID_WIDTH] = m_axi_rid;
assign m_axi_r[RESP_OFFSET +: 2] = m_axi_rresp;
if (RUSER_ENABLE) assign m_axi_r[RUSER_OFFSET +: RUSER_WIDTH] = m_axi_ruser;
endgenerate
generate
if (FIFO_DELAY) begin
// store AR channel value until there is enough space to store R channel burst in FIFO or FIFO is empty
localparam COUNT_WIDTH = (FIFO_ADDR_WIDTH > 8 ? FIFO_ADDR_WIDTH : 8) + 1;
localparam [1:0]
STATE_IDLE = 1'd0,
STATE_WAIT = 1'd1;
reg [1:0] state_reg = STATE_IDLE, state_next;
reg [COUNT_WIDTH-1:0] count_reg = 0, count_next;
reg [ID_WIDTH-1:0] m_axi_arid_reg = {ID_WIDTH{1'b0}}, m_axi_arid_next;
reg [ADDR_WIDTH-1:0] m_axi_araddr_reg = {ADDR_WIDTH{1'b0}}, m_axi_araddr_next;
reg [7:0] m_axi_arlen_reg = 8'd0, m_axi_arlen_next;
reg [2:0] m_axi_arsize_reg = 3'd0, m_axi_arsize_next;
reg [1:0] m_axi_arburst_reg = 2'd0, m_axi_arburst_next;
reg m_axi_arlock_reg = 1'b0, m_axi_arlock_next;
reg [3:0] m_axi_arcache_reg = 4'd0, m_axi_arcache_next;
reg [2:0] m_axi_arprot_reg = 3'd0, m_axi_arprot_next;
reg [3:0] m_axi_arqos_reg = 4'd0, m_axi_arqos_next;
reg [3:0] m_axi_arregion_reg = 4'd0, m_axi_arregion_next;
reg [ARUSER_WIDTH-1:0] m_axi_aruser_reg = {ARUSER_WIDTH{1'b0}}, m_axi_aruser_next;
reg m_axi_arvalid_reg = 1'b0, m_axi_arvalid_next;
reg s_axi_arready_reg = 1'b0, s_axi_arready_next;
assign m_axi_arid = m_axi_arid_reg;
assign m_axi_araddr = m_axi_araddr_reg;
assign m_axi_arlen = m_axi_arlen_reg;
assign m_axi_arsize = m_axi_arsize_reg;
assign m_axi_arburst = m_axi_arburst_reg;
assign m_axi_arlock = m_axi_arlock_reg;
assign m_axi_arcache = m_axi_arcache_reg;
assign m_axi_arprot = m_axi_arprot_reg;
assign m_axi_arqos = m_axi_arqos_reg;
assign m_axi_arregion = m_axi_arregion_reg;
assign m_axi_aruser = ARUSER_ENABLE ? m_axi_aruser_reg : {ARUSER_WIDTH{1'b0}};
assign m_axi_arvalid = m_axi_arvalid_reg;
assign s_axi_arready = s_axi_arready_reg;
always @* begin
state_next = STATE_IDLE;
count_next = count_reg;
m_axi_arid_next = m_axi_arid_reg;
m_axi_araddr_next = m_axi_araddr_reg;
m_axi_arlen_next = m_axi_arlen_reg;
m_axi_arsize_next = m_axi_arsize_reg;
m_axi_arburst_next = m_axi_arburst_reg;
m_axi_arlock_next = m_axi_arlock_reg;
m_axi_arcache_next = m_axi_arcache_reg;
m_axi_arprot_next = m_axi_arprot_reg;
m_axi_arqos_next = m_axi_arqos_reg;
m_axi_arregion_next = m_axi_arregion_reg;
m_axi_aruser_next = m_axi_aruser_reg;
m_axi_arvalid_next = m_axi_arvalid_reg && !m_axi_arready;
s_axi_arready_next = s_axi_arready_reg;
case (state_reg)
STATE_IDLE: begin
s_axi_arready_next = !m_axi_arvalid;
if (s_axi_arready & s_axi_arvalid) begin
s_axi_arready_next = 1'b0;
m_axi_arid_next = s_axi_arid;
m_axi_araddr_next = s_axi_araddr;
m_axi_arlen_next = s_axi_arlen;
m_axi_arsize_next = s_axi_arsize;
m_axi_arburst_next = s_axi_arburst;
m_axi_arlock_next = s_axi_arlock;
m_axi_arcache_next = s_axi_arcache;
m_axi_arprot_next = s_axi_arprot;
m_axi_arqos_next = s_axi_arqos;
m_axi_arregion_next = s_axi_arregion;
m_axi_aruser_next = s_axi_aruser;
if (count_reg == 0 || count_reg + m_axi_arlen_next + 1 <= 2**FIFO_ADDR_WIDTH) begin
count_next = count_reg + m_axi_arlen_next + 1;
m_axi_arvalid_next = 1'b1;
s_axi_arready_next = 1'b0;
state_next = STATE_IDLE;
end else begin
s_axi_arready_next = 1'b0;
state_next = STATE_WAIT;
end
end else begin
state_next = STATE_IDLE;
end
end
STATE_WAIT: begin
s_axi_arready_next = 1'b0;
if (count_reg == 0 || count_reg + m_axi_arlen_reg + 1 <= 2**FIFO_ADDR_WIDTH) begin
count_next = count_reg + m_axi_arlen_reg + 1;
m_axi_arvalid_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_WAIT;
end
end
endcase
if (s_axi_rready && s_axi_rvalid) begin
count_next = count_next - 1;
end
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
m_axi_arvalid_reg <= 1'b0;
s_axi_arready_reg <= 1'b0;
end else begin
state_reg <= state_next;
m_axi_arvalid_reg <= m_axi_arvalid_next;
s_axi_arready_reg <= s_axi_arready_next;
end
count_reg <= count_next;
m_axi_arid_reg <= m_axi_arid_next;
m_axi_araddr_reg <= m_axi_araddr_next;
m_axi_arlen_reg <= m_axi_arlen_next;
m_axi_arsize_reg <= m_axi_arsize_next;
m_axi_arburst_reg <= m_axi_arburst_next;
m_axi_arlock_reg <= m_axi_arlock_next;
m_axi_arcache_reg <= m_axi_arcache_next;
m_axi_arprot_reg <= m_axi_arprot_next;
m_axi_arqos_reg <= m_axi_arqos_next;
m_axi_arregion_reg <= m_axi_arregion_next;
m_axi_aruser_reg <= m_axi_aruser_next;
end
end else begin
// bypass AR channel
assign m_axi_arid = s_axi_arid;
assign m_axi_araddr = s_axi_araddr;
assign m_axi_arlen = s_axi_arlen;
assign m_axi_arsize = s_axi_arsize;
assign m_axi_arburst = s_axi_arburst;
assign m_axi_arlock = s_axi_arlock;
assign m_axi_arcache = s_axi_arcache;
assign m_axi_arprot = s_axi_arprot;
assign m_axi_arqos = s_axi_arqos;
assign m_axi_arregion = s_axi_arregion;
assign m_axi_aruser = ARUSER_ENABLE ? s_axi_aruser : {ARUSER_WIDTH{1'b0}};
assign m_axi_arvalid = s_axi_arvalid;
assign s_axi_arready = m_axi_arready;
end
endgenerate
assign s_axi_rvalid = s_axi_rvalid_reg;
assign s_axi_rdata = s_axi_r_reg[DATA_WIDTH-1:0];
assign s_axi_rlast = s_axi_r_reg[LAST_OFFSET];
assign s_axi_rid = s_axi_r_reg[ID_OFFSET +: ID_WIDTH];
assign s_axi_rresp = s_axi_r_reg[RESP_OFFSET +: 2];
assign s_axi_ruser = RUSER_ENABLE ? s_axi_r_reg[RUSER_OFFSET +: RUSER_WIDTH] : {RUSER_WIDTH{1'b0}};
// Write logic
always @* begin
write = 1'b0;
wr_ptr_next = wr_ptr_reg;
if (m_axi_rvalid) begin
// input data valid
if (!full) begin
// not full, perform write
write = 1'b1;
wr_ptr_next = wr_ptr_reg + 1;
end
end
end
always @(posedge clk) begin
if (rst) begin
wr_ptr_reg <= {FIFO_ADDR_WIDTH+1{1'b0}};
end else begin
wr_ptr_reg <= wr_ptr_next;
end
wr_addr_reg <= wr_ptr_next;
if (write) begin
mem[wr_addr_reg[FIFO_ADDR_WIDTH-1:0]] <= m_axi_r;
end
end
// Read logic
always @* begin
read = 1'b0;
rd_ptr_next = rd_ptr_reg;
mem_read_data_valid_next = mem_read_data_valid_reg;
if (store_output || !mem_read_data_valid_reg) begin
// output data not valid OR currently being transferred
if (!empty) begin
// not empty, perform read
read = 1'b1;
mem_read_data_valid_next = 1'b1;
rd_ptr_next = rd_ptr_reg + 1;
end else begin
// empty, invalidate
mem_read_data_valid_next = 1'b0;
end
end
end
always @(posedge clk) begin
if (rst) begin
rd_ptr_reg <= {FIFO_ADDR_WIDTH+1{1'b0}};
mem_read_data_valid_reg <= 1'b0;
end else begin
rd_ptr_reg <= rd_ptr_next;
mem_read_data_valid_reg <= mem_read_data_valid_next;
end
rd_addr_reg <= rd_ptr_next;
if (read) begin
mem_read_data_reg <= mem[rd_addr_reg[FIFO_ADDR_WIDTH-1:0]];
end
end
// Output register
always @* begin
store_output = 1'b0;
s_axi_rvalid_next = s_axi_rvalid_reg;
if (s_axi_rready || !s_axi_rvalid) begin
store_output = 1'b1;
s_axi_rvalid_next = mem_read_data_valid_reg;
end
end
always @(posedge clk) begin
if (rst) begin
s_axi_rvalid_reg <= 1'b0;
end else begin
s_axi_rvalid_reg <= s_axi_rvalid_next;
end
if (store_output) begin
s_axi_r_reg <= mem_read_data_reg;
end
end
endmodule
/*
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 FIFO (write)
*/
module axi_fifo_wr #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Width of ID signal
parameter ID_WIDTH = 8,
// Propagate awuser signal
parameter AWUSER_ENABLE = 0,
// Width of awuser signal
parameter AWUSER_WIDTH = 1,
// Propagate wuser signal
parameter WUSER_ENABLE = 0,
// Width of wuser signal
parameter WUSER_WIDTH = 1,
// Propagate buser signal
parameter BUSER_ENABLE = 0,
// Width of buser signal
parameter BUSER_WIDTH = 1,
// Write data FIFO depth (cycles)
parameter FIFO_DEPTH = 32,
// Hold write address until write data in FIFO, if possible
parameter FIFO_DELAY = 0
)
(
input wire clk,
input wire rst,
/*
* AXI slave interface
*/
input wire [ID_WIDTH-1:0] s_axi_awid,
input wire [ADDR_WIDTH-1:0] s_axi_awaddr,
input wire [7:0] s_axi_awlen,
input wire [2:0] s_axi_awsize,
input wire [1:0] s_axi_awburst,
input wire s_axi_awlock,
input wire [3:0] s_axi_awcache,
input wire [2:0] s_axi_awprot,
input wire [3:0] s_axi_awqos,
input wire [3:0] s_axi_awregion,
input wire [AWUSER_WIDTH-1:0] s_axi_awuser,
input wire s_axi_awvalid,
output wire s_axi_awready,
input wire [DATA_WIDTH-1:0] s_axi_wdata,
input wire [STRB_WIDTH-1:0] s_axi_wstrb,
input wire s_axi_wlast,
input wire [WUSER_WIDTH-1:0] s_axi_wuser,
input wire s_axi_wvalid,
output wire s_axi_wready,
output wire [ID_WIDTH-1:0] s_axi_bid,
output wire [1:0] s_axi_bresp,
output wire [BUSER_WIDTH-1:0] s_axi_buser,
output wire s_axi_bvalid,
input wire s_axi_bready,
/*
* AXI master interface
*/
output wire [ID_WIDTH-1:0] m_axi_awid,
output wire [ADDR_WIDTH-1:0] m_axi_awaddr,
output wire [7:0] m_axi_awlen,
output wire [2:0] m_axi_awsize,
output wire [1:0] m_axi_awburst,
output wire m_axi_awlock,
output wire [3:0] m_axi_awcache,
output wire [2:0] m_axi_awprot,
output wire [3:0] m_axi_awqos,
output wire [3:0] m_axi_awregion,
output wire [AWUSER_WIDTH-1:0] m_axi_awuser,
output wire m_axi_awvalid,
input wire m_axi_awready,
output wire [DATA_WIDTH-1:0] m_axi_wdata,
output wire [STRB_WIDTH-1:0] m_axi_wstrb,
output wire m_axi_wlast,
output wire [WUSER_WIDTH-1:0] m_axi_wuser,
output wire m_axi_wvalid,
input wire m_axi_wready,
input wire [ID_WIDTH-1:0] m_axi_bid,
input wire [1:0] m_axi_bresp,
input wire [BUSER_WIDTH-1:0] m_axi_buser,
input wire m_axi_bvalid,
output wire m_axi_bready
);
parameter STRB_OFFSET = DATA_WIDTH;
parameter LAST_OFFSET = STRB_OFFSET + STRB_WIDTH;
parameter WUSER_OFFSET = LAST_OFFSET + 1;
parameter WWIDTH = WUSER_OFFSET + (WUSER_ENABLE ? WUSER_WIDTH : 0);
parameter FIFO_ADDR_WIDTH = $clog2(FIFO_DEPTH);
reg [FIFO_ADDR_WIDTH:0] wr_ptr_reg = {FIFO_ADDR_WIDTH+1{1'b0}}, wr_ptr_next;
reg [FIFO_ADDR_WIDTH:0] wr_addr_reg = {FIFO_ADDR_WIDTH+1{1'b0}};
reg [FIFO_ADDR_WIDTH:0] rd_ptr_reg = {FIFO_ADDR_WIDTH+1{1'b0}}, rd_ptr_next;
reg [FIFO_ADDR_WIDTH:0] rd_addr_reg = {FIFO_ADDR_WIDTH+1{1'b0}};
reg [WWIDTH-1:0] mem[(2**FIFO_ADDR_WIDTH)-1:0];
reg [WWIDTH-1:0] mem_read_data_reg;
reg mem_read_data_valid_reg = 1'b0, mem_read_data_valid_next;
wire [WWIDTH-1:0] s_axi_w;
reg [WWIDTH-1:0] m_axi_w_reg;
reg m_axi_wvalid_reg = 1'b0, m_axi_wvalid_next;
// full when first MSB different but rest same
wire full = ((wr_ptr_reg[FIFO_ADDR_WIDTH] != rd_ptr_reg[FIFO_ADDR_WIDTH]) &&
(wr_ptr_reg[FIFO_ADDR_WIDTH-1:0] == rd_ptr_reg[FIFO_ADDR_WIDTH-1:0]));
// empty when pointers match exactly
wire empty = wr_ptr_reg == rd_ptr_reg;
wire hold;
// control signals
reg write;
reg read;
reg store_output;
assign s_axi_wready = !full && !hold;
generate
assign s_axi_w[DATA_WIDTH-1:0] = s_axi_wdata;
assign s_axi_w[STRB_OFFSET +: STRB_WIDTH] = s_axi_wstrb;
assign s_axi_w[LAST_OFFSET] = s_axi_wlast;
if (WUSER_ENABLE) assign s_axi_w[WUSER_OFFSET +: WUSER_WIDTH] = s_axi_wuser;
endgenerate
generate
if (FIFO_DELAY) begin
// store AW channel value until W channel burst is stored in FIFO or FIFO is full
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_TRANSFER_IN = 2'd1,
STATE_TRANSFER_OUT = 2'd2;
reg [1:0] state_reg = STATE_IDLE, state_next;
reg hold_reg = 1'b1, hold_next;
reg [8:0] count_reg = 9'd0, count_next;
reg [ID_WIDTH-1:0] m_axi_awid_reg = {ID_WIDTH{1'b0}}, m_axi_awid_next;
reg [ADDR_WIDTH-1:0] m_axi_awaddr_reg = {ADDR_WIDTH{1'b0}}, m_axi_awaddr_next;
reg [7:0] m_axi_awlen_reg = 8'd0, m_axi_awlen_next;
reg [2:0] m_axi_awsize_reg = 3'd0, m_axi_awsize_next;
reg [1:0] m_axi_awburst_reg = 2'd0, m_axi_awburst_next;
reg m_axi_awlock_reg = 1'b0, m_axi_awlock_next;
reg [3:0] m_axi_awcache_reg = 4'd0, m_axi_awcache_next;
reg [2:0] m_axi_awprot_reg = 3'd0, m_axi_awprot_next;
reg [3:0] m_axi_awqos_reg = 4'd0, m_axi_awqos_next;
reg [3:0] m_axi_awregion_reg = 4'd0, m_axi_awregion_next;
reg [AWUSER_WIDTH-1:0] m_axi_awuser_reg = {AWUSER_WIDTH{1'b0}}, m_axi_awuser_next;
reg m_axi_awvalid_reg = 1'b0, m_axi_awvalid_next;
reg s_axi_awready_reg = 1'b0, s_axi_awready_next;
assign m_axi_awid = m_axi_awid_reg;
assign m_axi_awaddr = m_axi_awaddr_reg;
assign m_axi_awlen = m_axi_awlen_reg;
assign m_axi_awsize = m_axi_awsize_reg;
assign m_axi_awburst = m_axi_awburst_reg;
assign m_axi_awlock = m_axi_awlock_reg;
assign m_axi_awcache = m_axi_awcache_reg;
assign m_axi_awprot = m_axi_awprot_reg;
assign m_axi_awqos = m_axi_awqos_reg;
assign m_axi_awregion = m_axi_awregion_reg;
assign m_axi_awuser = AWUSER_ENABLE ? m_axi_awuser_reg : {AWUSER_WIDTH{1'b0}};
assign m_axi_awvalid = m_axi_awvalid_reg;
assign s_axi_awready = s_axi_awready_reg;
assign hold = hold_reg;
always @* begin
state_next = STATE_IDLE;
hold_next = hold_reg;
count_next = count_reg;
m_axi_awid_next = m_axi_awid_reg;
m_axi_awaddr_next = m_axi_awaddr_reg;
m_axi_awlen_next = m_axi_awlen_reg;
m_axi_awsize_next = m_axi_awsize_reg;
m_axi_awburst_next = m_axi_awburst_reg;
m_axi_awlock_next = m_axi_awlock_reg;
m_axi_awcache_next = m_axi_awcache_reg;
m_axi_awprot_next = m_axi_awprot_reg;
m_axi_awqos_next = m_axi_awqos_reg;
m_axi_awregion_next = m_axi_awregion_reg;
m_axi_awuser_next = m_axi_awuser_reg;
m_axi_awvalid_next = m_axi_awvalid_reg && !m_axi_awready;
s_axi_awready_next = s_axi_awready_reg;
case (state_reg)
STATE_IDLE: begin
s_axi_awready_next = !m_axi_awvalid;
hold_next = 1'b1;
if (s_axi_awready & s_axi_awvalid) begin
s_axi_awready_next = 1'b0;
m_axi_awid_next = s_axi_awid;
m_axi_awaddr_next = s_axi_awaddr;
m_axi_awlen_next = s_axi_awlen;
m_axi_awsize_next = s_axi_awsize;
m_axi_awburst_next = s_axi_awburst;
m_axi_awlock_next = s_axi_awlock;
m_axi_awcache_next = s_axi_awcache;
m_axi_awprot_next = s_axi_awprot;
m_axi_awqos_next = s_axi_awqos;
m_axi_awregion_next = s_axi_awregion;
m_axi_awuser_next = s_axi_awuser;
hold_next = 1'b0;
count_next = 0;
state_next = STATE_TRANSFER_IN;
end else begin
state_next = STATE_IDLE;
end
end
STATE_TRANSFER_IN: begin
s_axi_awready_next = 1'b0;
hold_next = 1'b0;
if (s_axi_wready & s_axi_wvalid) begin
count_next = count_reg + 1;
if (count_next == 2**FIFO_ADDR_WIDTH) begin
m_axi_awvalid_next = 1'b1;
state_next = STATE_TRANSFER_OUT;
end else if (count_reg == m_axi_awlen) begin
m_axi_awvalid_next = 1'b1;
hold_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_TRANSFER_IN;
end
end else begin
state_next = STATE_TRANSFER_IN;
end
end
STATE_TRANSFER_OUT: begin
s_axi_awready_next = 1'b0;
hold_next = 1'b0;
if (s_axi_wready & s_axi_wvalid) begin
count_next = count_reg + 1;
if (count_reg == m_axi_awlen) begin
hold_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_TRANSFER_OUT;
end
end else begin
state_next = STATE_TRANSFER_OUT;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
hold_reg <= 1'b1;
m_axi_awvalid_reg <= 1'b0;
s_axi_awready_reg <= 1'b0;
end else begin
state_reg <= state_next;
hold_reg <= hold_next;
m_axi_awvalid_reg <= m_axi_awvalid_next;
s_axi_awready_reg <= s_axi_awready_next;
end
count_reg <= count_next;
m_axi_awid_reg <= m_axi_awid_next;
m_axi_awaddr_reg <= m_axi_awaddr_next;
m_axi_awlen_reg <= m_axi_awlen_next;
m_axi_awsize_reg <= m_axi_awsize_next;
m_axi_awburst_reg <= m_axi_awburst_next;
m_axi_awlock_reg <= m_axi_awlock_next;
m_axi_awcache_reg <= m_axi_awcache_next;
m_axi_awprot_reg <= m_axi_awprot_next;
m_axi_awqos_reg <= m_axi_awqos_next;
m_axi_awregion_reg <= m_axi_awregion_next;
m_axi_awuser_reg <= m_axi_awuser_next;
end
end else begin
// bypass AW channel
assign m_axi_awid = s_axi_awid;
assign m_axi_awaddr = s_axi_awaddr;
assign m_axi_awlen = s_axi_awlen;
assign m_axi_awsize = s_axi_awsize;
assign m_axi_awburst = s_axi_awburst;
assign m_axi_awlock = s_axi_awlock;
assign m_axi_awcache = s_axi_awcache;
assign m_axi_awprot = s_axi_awprot;
assign m_axi_awqos = s_axi_awqos;
assign m_axi_awregion = s_axi_awregion;
assign m_axi_awuser = AWUSER_ENABLE ? s_axi_awuser : {AWUSER_WIDTH{1'b0}};
assign m_axi_awvalid = s_axi_awvalid;
assign s_axi_awready = m_axi_awready;
assign hold = 1'b0;
end
endgenerate
// bypass B channel
assign s_axi_bid = m_axi_bid;
assign s_axi_bresp = m_axi_bresp;
assign s_axi_buser = BUSER_ENABLE ? m_axi_buser : {BUSER_WIDTH{1'b0}};
assign s_axi_bvalid = m_axi_bvalid;
assign m_axi_bready = s_axi_bready;
assign m_axi_wvalid = m_axi_wvalid_reg;
assign m_axi_wdata = m_axi_w_reg[DATA_WIDTH-1:0];
assign m_axi_wstrb = m_axi_w_reg[STRB_OFFSET +: STRB_WIDTH];
assign m_axi_wlast = m_axi_w_reg[LAST_OFFSET];
assign m_axi_wuser = WUSER_ENABLE ? m_axi_w_reg[WUSER_OFFSET +: WUSER_WIDTH] : {WUSER_WIDTH{1'b0}};
// Write logic
always @* begin
write = 1'b0;
wr_ptr_next = wr_ptr_reg;
if (s_axi_wvalid) begin
// input data valid
if (!full && !hold) begin
// not full, perform write
write = 1'b1;
wr_ptr_next = wr_ptr_reg + 1;
end
end
end
always @(posedge clk) begin
if (rst) begin
wr_ptr_reg <= {FIFO_ADDR_WIDTH+1{1'b0}};
end else begin
wr_ptr_reg <= wr_ptr_next;
end
wr_addr_reg <= wr_ptr_next;
if (write) begin
mem[wr_addr_reg[FIFO_ADDR_WIDTH-1:0]] <= s_axi_w;
end
end
// Read logic
always @* begin
read = 1'b0;
rd_ptr_next = rd_ptr_reg;
mem_read_data_valid_next = mem_read_data_valid_reg;
if (store_output || !mem_read_data_valid_reg) begin
// output data not valid OR currently being transferred
if (!empty) begin
// not empty, perform read
read = 1'b1;
mem_read_data_valid_next = 1'b1;
rd_ptr_next = rd_ptr_reg + 1;
end else begin
// empty, invalidate
mem_read_data_valid_next = 1'b0;
end
end
end
always @(posedge clk) begin
if (rst) begin
rd_ptr_reg <= {FIFO_ADDR_WIDTH+1{1'b0}};
mem_read_data_valid_reg <= 1'b0;
end else begin
rd_ptr_reg <= rd_ptr_next;
mem_read_data_valid_reg <= mem_read_data_valid_next;
end
rd_addr_reg <= rd_ptr_next;
if (read) begin
mem_read_data_reg <= mem[rd_addr_reg[FIFO_ADDR_WIDTH-1:0]];
end
end
// Output register
always @* begin
store_output = 1'b0;
m_axi_wvalid_next = m_axi_wvalid_reg;
if (m_axi_wready || !m_axi_wvalid) begin
store_output = 1'b1;
m_axi_wvalid_next = mem_read_data_valid_reg;
end
end
always @(posedge clk) begin
if (rst) begin
m_axi_wvalid_reg <= 1'b0;
end else begin
m_axi_wvalid_reg <= m_axi_wvalid_next;
end
if (store_output) begin
m_axi_w_reg <= mem_read_data_reg;
end
end
endmodule
/*
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 interconnect
*/
module axi_interconnect #
(
// Number of AXI inputs (slave interfaces)
parameter S_COUNT = 4,
// Number of AXI outputs (master interfaces)
parameter M_COUNT = 4,
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Width of ID signal
parameter ID_WIDTH = 8,
// Propagate awuser signal
parameter AWUSER_ENABLE = 0,
// Width of awuser signal
parameter AWUSER_WIDTH = 1,
// Propagate wuser signal
parameter WUSER_ENABLE = 0,
// Width of wuser signal
parameter WUSER_WIDTH = 1,
// Propagate buser signal
parameter BUSER_ENABLE = 0,
// Width of buser signal
parameter BUSER_WIDTH = 1,
// Propagate aruser signal
parameter ARUSER_ENABLE = 0,
// Width of aruser signal
parameter ARUSER_WIDTH = 1,
// Propagate ruser signal
parameter RUSER_ENABLE = 0,
// Width of ruser signal
parameter RUSER_WIDTH = 1,
// Propagate ID field
parameter FORWARD_ID = 0,
// Number of regions per master interface
parameter M_REGIONS = 1,
// Master interface base addresses
// M_COUNT concatenated fields of M_REGIONS concatenated fields of ADDR_WIDTH bits
// set to zero for default addressing based on M_ADDR_WIDTH
parameter M_BASE_ADDR = 0,
// Master interface address widths
// M_COUNT concatenated fields of M_REGIONS concatenated fields of 32 bits
parameter M_ADDR_WIDTH = {M_COUNT{{M_REGIONS{32'd24}}}},
// Read connections between interfaces
// M_COUNT concatenated fields of S_COUNT bits
parameter M_CONNECT_READ = {M_COUNT{{S_COUNT{1'b1}}}},
// Write connections between interfaces
// M_COUNT concatenated fields of S_COUNT bits
parameter M_CONNECT_WRITE = {M_COUNT{{S_COUNT{1'b1}}}},
// Secure master (fail operations based on awprot/arprot)
// M_COUNT bits
parameter M_SECURE = {M_COUNT{1'b0}}
)
(
input wire clk,
input wire rst,
/*
* AXI slave interfaces
*/
input wire [S_COUNT*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*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*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*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*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*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*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*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 AUSER_WIDTH = AWUSER_WIDTH > ARUSER_WIDTH ? AWUSER_WIDTH : ARUSER_WIDTH;
// default address computation
function [M_COUNT*M_REGIONS*ADDR_WIDTH-1:0] calcBaseAddrs(input [31:0] dummy);
integer i;
reg [ADDR_WIDTH-1:0] base;
begin
calcBaseAddrs = {M_COUNT*M_REGIONS*ADDR_WIDTH{1'b0}};
base = 0;
for (i = 1; i < M_COUNT*M_REGIONS; i = i + 1) begin
if (M_ADDR_WIDTH[i*32 +: 32]) begin
base = base + 2**M_ADDR_WIDTH[(i-1)*32 +: 32]; // increment
base = base - (base % 2**M_ADDR_WIDTH[i*32 +: 32]); // align
calcBaseAddrs[i * ADDR_WIDTH +: ADDR_WIDTH] = base;
end
end
end
endfunction
parameter M_BASE_ADDR_INT = M_BASE_ADDR ? M_BASE_ADDR : calcBaseAddrs(0);
integer i, j;
// check configuration
initial begin
if (M_REGIONS < 1 || M_REGIONS > 16) begin
$error("Error: M_REGIONS must be between 1 and 16 (instance %m)");
$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 (instance %m)");
$finish;
end
end
$display("Addressing configuration for axi_interconnect instance %m");
for (i = 0; i < M_COUNT*M_REGIONS; i = i + 1) begin
if (M_ADDR_WIDTH[i*32 +: 32]) begin
$display("%2d (%2d): %x / %2d -- %x-%x", i/M_REGIONS, i%M_REGIONS, M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH], M_ADDR_WIDTH[i*32 +: 32], M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32]), M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32])));
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_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32])) <= (M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[j*32 +: 32])))) && ((M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[j*32 +: 32])) <= (M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32]))))) begin
$display("Overlapping regions:");
$display("%2d (%2d): %x / %2d -- %x-%x", i/M_REGIONS, i%M_REGIONS, M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH], M_ADDR_WIDTH[i*32 +: 32], M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[i*32 +: 32]), M_BASE_ADDR_INT[i*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[i*32 +: 32])));
$display("%2d (%2d): %x / %2d -- %x-%x", j/M_REGIONS, j%M_REGIONS, M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH], M_ADDR_WIDTH[j*32 +: 32], M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] & ({ADDR_WIDTH{1'b1}} << M_ADDR_WIDTH[j*32 +: 32]), M_BASE_ADDR_INT[j*ADDR_WIDTH +: ADDR_WIDTH] | ({ADDR_WIDTH{1'b1}} >> (ADDR_WIDTH - M_ADDR_WIDTH[j*32 +: 32])));
$error("Error: address ranges overlap (instance %m)");
$finish;
end
end
end
end
end
localparam [2:0]
STATE_IDLE = 3'd0,
STATE_DECODE = 3'd1,
STATE_WRITE = 3'd2,
STATE_WRITE_RESP = 3'd3,
STATE_WRITE_DROP = 3'd4,
STATE_READ = 3'd5,
STATE_READ_DROP = 3'd6,
STATE_WAIT_IDLE = 3'd7;
reg [2:0] state_reg = STATE_IDLE, state_next;
reg match;
reg [CL_M_COUNT-1:0] m_select_reg = 2'd0, m_select_next;
reg [ID_WIDTH-1:0] axi_id_reg = {ID_WIDTH{1'b0}}, axi_id_next;
reg [ADDR_WIDTH-1:0] axi_addr_reg = {ADDR_WIDTH{1'b0}}, axi_addr_next;
reg axi_addr_valid_reg = 1'b0, axi_addr_valid_next;
reg [7:0] axi_len_reg = 8'd0, axi_len_next;
reg [2:0] axi_size_reg = 3'd0, axi_size_next;
reg [1:0] axi_burst_reg = 2'd0, axi_burst_next;
reg axi_lock_reg = 1'b0, axi_lock_next;
reg [3:0] axi_cache_reg = 4'd0, axi_cache_next;
reg [2:0] axi_prot_reg = 3'b000, axi_prot_next;
reg [3:0] axi_qos_reg = 4'd0, axi_qos_next;
reg [3:0] axi_region_reg = 4'd0, axi_region_next;
reg [AUSER_WIDTH-1:0] axi_auser_reg = {AUSER_WIDTH{1'b0}}, axi_auser_next;
reg [1:0] axi_bresp_reg = 2'b00, axi_bresp_next;
reg [BUSER_WIDTH-1:0] axi_buser_reg = {BUSER_WIDTH{1'b0}}, axi_buser_next;
reg [S_COUNT-1:0] s_axi_awready_reg = 0, s_axi_awready_next;
reg [S_COUNT-1:0] s_axi_wready_reg = 0, s_axi_wready_next;
reg [S_COUNT-1:0] s_axi_bvalid_reg = 0, s_axi_bvalid_next;
reg [S_COUNT-1:0] s_axi_arready_reg = 0, s_axi_arready_next;
reg [M_COUNT-1:0] m_axi_awvalid_reg = 0, m_axi_awvalid_next;
reg [M_COUNT-1:0] m_axi_bready_reg = 0, m_axi_bready_next;
reg [M_COUNT-1:0] m_axi_arvalid_reg = 0, m_axi_arvalid_next;
reg [M_COUNT-1:0] m_axi_rready_reg = 0, m_axi_rready_next;
// internal datapath
reg [ID_WIDTH-1:0] s_axi_rid_int;
reg [DATA_WIDTH-1:0] s_axi_rdata_int;
reg [1:0] s_axi_rresp_int;
reg s_axi_rlast_int;
reg [RUSER_WIDTH-1:0] s_axi_ruser_int;
reg s_axi_rvalid_int;
reg s_axi_rready_int_reg = 1'b0;
wire s_axi_rready_int_early;
reg [DATA_WIDTH-1:0] m_axi_wdata_int;
reg [STRB_WIDTH-1:0] m_axi_wstrb_int;
reg m_axi_wlast_int;
reg [WUSER_WIDTH-1:0] m_axi_wuser_int;
reg m_axi_wvalid_int;
reg m_axi_wready_int_reg = 1'b0;
wire m_axi_wready_int_early;
assign s_axi_awready = s_axi_awready_reg;
assign s_axi_wready = s_axi_wready_reg;
assign s_axi_bid = {S_COUNT{axi_id_reg}};
assign s_axi_bresp = {S_COUNT{axi_bresp_reg}};
assign s_axi_buser = {S_COUNT{BUSER_ENABLE ? axi_buser_reg : {BUSER_WIDTH{1'b0}}}};
assign s_axi_bvalid = s_axi_bvalid_reg;
assign s_axi_arready = s_axi_arready_reg;
assign m_axi_awid = {M_COUNT{FORWARD_ID ? axi_id_reg : {ID_WIDTH{1'b0}}}};
assign m_axi_awaddr = {M_COUNT{axi_addr_reg}};
assign m_axi_awlen = {M_COUNT{axi_len_reg}};
assign m_axi_awsize = {M_COUNT{axi_size_reg}};
assign m_axi_awburst = {M_COUNT{axi_burst_reg}};
assign m_axi_awlock = {M_COUNT{axi_lock_reg}};
assign m_axi_awcache = {M_COUNT{axi_cache_reg}};
assign m_axi_awprot = {M_COUNT{axi_prot_reg}};
assign m_axi_awqos = {M_COUNT{axi_qos_reg}};
assign m_axi_awregion = {M_COUNT{axi_region_reg}};
assign m_axi_awuser = {M_COUNT{AWUSER_ENABLE ? axi_auser_reg[AWUSER_WIDTH-1:0] : {AWUSER_WIDTH{1'b0}}}};
assign m_axi_awvalid = m_axi_awvalid_reg;
assign m_axi_bready = m_axi_bready_reg;
assign m_axi_arid = {M_COUNT{FORWARD_ID ? axi_id_reg : {ID_WIDTH{1'b0}}}};
assign m_axi_araddr = {M_COUNT{axi_addr_reg}};
assign m_axi_arlen = {M_COUNT{axi_len_reg}};
assign m_axi_arsize = {M_COUNT{axi_size_reg}};
assign m_axi_arburst = {M_COUNT{axi_burst_reg}};
assign m_axi_arlock = {M_COUNT{axi_lock_reg}};
assign m_axi_arcache = {M_COUNT{axi_cache_reg}};
assign m_axi_arprot = {M_COUNT{axi_prot_reg}};
assign m_axi_arqos = {M_COUNT{axi_qos_reg}};
assign m_axi_arregion = {M_COUNT{axi_region_reg}};
assign m_axi_aruser = {M_COUNT{ARUSER_ENABLE ? axi_auser_reg[ARUSER_WIDTH-1:0] : {ARUSER_WIDTH{1'b0}}}};
assign m_axi_arvalid = m_axi_arvalid_reg;
assign m_axi_rready = m_axi_rready_reg;
// slave side mux
wire [(CL_S_COUNT > 0 ? CL_S_COUNT-1 : 0):0] s_select;
wire [ID_WIDTH-1:0] current_s_axi_awid = s_axi_awid[s_select*ID_WIDTH +: ID_WIDTH];
wire [ADDR_WIDTH-1:0] current_s_axi_awaddr = s_axi_awaddr[s_select*ADDR_WIDTH +: ADDR_WIDTH];
wire [7:0] current_s_axi_awlen = s_axi_awlen[s_select*8 +: 8];
wire [2:0] current_s_axi_awsize = s_axi_awsize[s_select*3 +: 3];
wire [1:0] current_s_axi_awburst = s_axi_awburst[s_select*2 +: 2];
wire current_s_axi_awlock = s_axi_awlock[s_select];
wire [3:0] current_s_axi_awcache = s_axi_awcache[s_select*4 +: 4];
wire [2:0] current_s_axi_awprot = s_axi_awprot[s_select*3 +: 3];
wire [3:0] current_s_axi_awqos = s_axi_awqos[s_select*4 +: 4];
wire [AWUSER_WIDTH-1:0] current_s_axi_awuser = s_axi_awuser[s_select*AWUSER_WIDTH +: AWUSER_WIDTH];
wire current_s_axi_awvalid = s_axi_awvalid[s_select];
wire current_s_axi_awready = s_axi_awready[s_select];
wire [DATA_WIDTH-1:0] current_s_axi_wdata = s_axi_wdata[s_select*DATA_WIDTH +: DATA_WIDTH];
wire [STRB_WIDTH-1:0] current_s_axi_wstrb = s_axi_wstrb[s_select*STRB_WIDTH +: STRB_WIDTH];
wire current_s_axi_wlast = s_axi_wlast[s_select];
wire [WUSER_WIDTH-1:0] current_s_axi_wuser = s_axi_wuser[s_select*WUSER_WIDTH +: WUSER_WIDTH];
wire current_s_axi_wvalid = s_axi_wvalid[s_select];
wire current_s_axi_wready = s_axi_wready[s_select];
wire [ID_WIDTH-1:0] current_s_axi_bid = s_axi_bid[s_select*ID_WIDTH +: ID_WIDTH];
wire [1:0] current_s_axi_bresp = s_axi_bresp[s_select*2 +: 2];
wire [BUSER_WIDTH-1:0] current_s_axi_buser = s_axi_buser[s_select*BUSER_WIDTH +: BUSER_WIDTH];
wire current_s_axi_bvalid = s_axi_bvalid[s_select];
wire current_s_axi_bready = s_axi_bready[s_select];
wire [ID_WIDTH-1:0] current_s_axi_arid = s_axi_arid[s_select*ID_WIDTH +: ID_WIDTH];
wire [ADDR_WIDTH-1:0] current_s_axi_araddr = s_axi_araddr[s_select*ADDR_WIDTH +: ADDR_WIDTH];
wire [7:0] current_s_axi_arlen = s_axi_arlen[s_select*8 +: 8];
wire [2:0] current_s_axi_arsize = s_axi_arsize[s_select*3 +: 3];
wire [1:0] current_s_axi_arburst = s_axi_arburst[s_select*2 +: 2];
wire current_s_axi_arlock = s_axi_arlock[s_select];
wire [3:0] current_s_axi_arcache = s_axi_arcache[s_select*4 +: 4];
wire [2:0] current_s_axi_arprot = s_axi_arprot[s_select*3 +: 3];
wire [3:0] current_s_axi_arqos = s_axi_arqos[s_select*4 +: 4];
wire [ARUSER_WIDTH-1:0] current_s_axi_aruser = s_axi_aruser[s_select*ARUSER_WIDTH +: ARUSER_WIDTH];
wire current_s_axi_arvalid = s_axi_arvalid[s_select];
wire current_s_axi_arready = s_axi_arready[s_select];
wire [ID_WIDTH-1:0] current_s_axi_rid = s_axi_rid[s_select*ID_WIDTH +: ID_WIDTH];
wire [DATA_WIDTH-1:0] current_s_axi_rdata = s_axi_rdata[s_select*DATA_WIDTH +: DATA_WIDTH];
wire [1:0] current_s_axi_rresp = s_axi_rresp[s_select*2 +: 2];
wire current_s_axi_rlast = s_axi_rlast[s_select];
wire [RUSER_WIDTH-1:0] current_s_axi_ruser = s_axi_ruser[s_select*RUSER_WIDTH +: RUSER_WIDTH];
wire current_s_axi_rvalid = s_axi_rvalid[s_select];
wire current_s_axi_rready = s_axi_rready[s_select];
// master side mux
wire [ID_WIDTH-1:0] current_m_axi_awid = m_axi_awid[m_select_reg*ID_WIDTH +: ID_WIDTH];
wire [ADDR_WIDTH-1:0] current_m_axi_awaddr = m_axi_awaddr[m_select_reg*ADDR_WIDTH +: ADDR_WIDTH];
wire [7:0] current_m_axi_awlen = m_axi_awlen[m_select_reg*8 +: 8];
wire [2:0] current_m_axi_awsize = m_axi_awsize[m_select_reg*3 +: 3];
wire [1:0] current_m_axi_awburst = m_axi_awburst[m_select_reg*2 +: 2];
wire current_m_axi_awlock = m_axi_awlock[m_select_reg];
wire [3:0] current_m_axi_awcache = m_axi_awcache[m_select_reg*4 +: 4];
wire [2:0] current_m_axi_awprot = m_axi_awprot[m_select_reg*3 +: 3];
wire [3:0] current_m_axi_awqos = m_axi_awqos[m_select_reg*4 +: 4];
wire [3:0] current_m_axi_awregion = m_axi_awregion[m_select_reg*4 +: 4];
wire [AWUSER_WIDTH-1:0] current_m_axi_awuser = m_axi_awuser[m_select_reg*AWUSER_WIDTH +: AWUSER_WIDTH];
wire current_m_axi_awvalid = m_axi_awvalid[m_select_reg];
wire current_m_axi_awready = m_axi_awready[m_select_reg];
wire [DATA_WIDTH-1:0] current_m_axi_wdata = m_axi_wdata[m_select_reg*DATA_WIDTH +: DATA_WIDTH];
wire [STRB_WIDTH-1:0] current_m_axi_wstrb = m_axi_wstrb[m_select_reg*STRB_WIDTH +: STRB_WIDTH];
wire current_m_axi_wlast = m_axi_wlast[m_select_reg];
wire [WUSER_WIDTH-1:0] current_m_axi_wuser = m_axi_wuser[m_select_reg*WUSER_WIDTH +: WUSER_WIDTH];
wire current_m_axi_wvalid = m_axi_wvalid[m_select_reg];
wire current_m_axi_wready = m_axi_wready[m_select_reg];
wire [ID_WIDTH-1:0] current_m_axi_bid = m_axi_bid[m_select_reg*ID_WIDTH +: ID_WIDTH];
wire [1:0] current_m_axi_bresp = m_axi_bresp[m_select_reg*2 +: 2];
wire [BUSER_WIDTH-1:0] current_m_axi_buser = m_axi_buser[m_select_reg*BUSER_WIDTH +: BUSER_WIDTH];
wire current_m_axi_bvalid = m_axi_bvalid[m_select_reg];
wire current_m_axi_bready = m_axi_bready[m_select_reg];
wire [ID_WIDTH-1:0] current_m_axi_arid = m_axi_arid[m_select_reg*ID_WIDTH +: ID_WIDTH];
wire [ADDR_WIDTH-1:0] current_m_axi_araddr = m_axi_araddr[m_select_reg*ADDR_WIDTH +: ADDR_WIDTH];
wire [7:0] current_m_axi_arlen = m_axi_arlen[m_select_reg*8 +: 8];
wire [2:0] current_m_axi_arsize = m_axi_arsize[m_select_reg*3 +: 3];
wire [1:0] current_m_axi_arburst = m_axi_arburst[m_select_reg*2 +: 2];
wire current_m_axi_arlock = m_axi_arlock[m_select_reg];
wire [3:0] current_m_axi_arcache = m_axi_arcache[m_select_reg*4 +: 4];
wire [2:0] current_m_axi_arprot = m_axi_arprot[m_select_reg*3 +: 3];
wire [3:0] current_m_axi_arqos = m_axi_arqos[m_select_reg*4 +: 4];
wire [3:0] current_m_axi_arregion = m_axi_arregion[m_select_reg*4 +: 4];
wire [ARUSER_WIDTH-1:0] current_m_axi_aruser = m_axi_aruser[m_select_reg*ARUSER_WIDTH +: ARUSER_WIDTH];
wire current_m_axi_arvalid = m_axi_arvalid[m_select_reg];
wire current_m_axi_arready = m_axi_arready[m_select_reg];
wire [ID_WIDTH-1:0] current_m_axi_rid = m_axi_rid[m_select_reg*ID_WIDTH +: ID_WIDTH];
wire [DATA_WIDTH-1:0] current_m_axi_rdata = m_axi_rdata[m_select_reg*DATA_WIDTH +: DATA_WIDTH];
wire [1:0] current_m_axi_rresp = m_axi_rresp[m_select_reg*2 +: 2];
wire current_m_axi_rlast = m_axi_rlast[m_select_reg];
wire [RUSER_WIDTH-1:0] current_m_axi_ruser = m_axi_ruser[m_select_reg*RUSER_WIDTH +: RUSER_WIDTH];
wire current_m_axi_rvalid = m_axi_rvalid[m_select_reg];
wire current_m_axi_rready = m_axi_rready[m_select_reg];
// arbiter instance
wire [S_COUNT*2-1:0] request;
wire [S_COUNT*2-1:0] acknowledge;
wire [S_COUNT*2-1:0] grant;
wire grant_valid;
wire [CL_S_COUNT:0] grant_encoded;
wire read = grant_encoded[0];
assign s_select = grant_encoded >> 1;
arbiter #(
.PORTS(S_COUNT*2),
.TYPE("ROUND_ROBIN"),
.BLOCK("ACKNOWLEDGE"),
.LSB_PRIORITY("HIGH")
)
arb_inst (
.clk(clk),
.rst(rst),
.request(request),
.acknowledge(acknowledge),
.grant(grant),
.grant_valid(grant_valid),
.grant_encoded(grant_encoded)
);
genvar n;
// request generation
generate
for (n = 0; n < S_COUNT; n = n + 1) begin
assign request[2*n] = s_axi_awvalid[n];
assign request[2*n+1] = s_axi_arvalid[n];
end
endgenerate
// acknowledge generation
generate
for (n = 0; n < S_COUNT; n = n + 1) begin
assign acknowledge[2*n] = grant[2*n] && s_axi_bvalid[n] && s_axi_bready[n];
assign acknowledge[2*n+1] = grant[2*n+1] && s_axi_rvalid[n] && s_axi_rready[n] && s_axi_rlast[n];
end
endgenerate
always @* begin
state_next = STATE_IDLE;
match = 1'b0;
m_select_next = m_select_reg;
axi_id_next = axi_id_reg;
axi_addr_next = axi_addr_reg;
axi_addr_valid_next = axi_addr_valid_reg;
axi_len_next = axi_len_reg;
axi_size_next = axi_size_reg;
axi_burst_next = axi_burst_reg;
axi_lock_next = axi_lock_reg;
axi_cache_next = axi_cache_reg;
axi_prot_next = axi_prot_reg;
axi_qos_next = axi_qos_reg;
axi_region_next = axi_region_reg;
axi_auser_next = axi_auser_reg;
axi_bresp_next = axi_bresp_reg;
axi_buser_next = axi_buser_reg;
s_axi_awready_next = 0;
s_axi_wready_next = 0;
s_axi_bvalid_next = s_axi_bvalid_reg & ~s_axi_bready;
s_axi_arready_next = 0;
m_axi_awvalid_next = m_axi_awvalid_reg & ~m_axi_awready;
m_axi_bready_next = 0;
m_axi_arvalid_next = m_axi_arvalid_reg & ~m_axi_arready;
m_axi_rready_next = 0;
s_axi_rid_int = axi_id_reg;
s_axi_rdata_int = current_m_axi_rdata;
s_axi_rresp_int = current_m_axi_rresp;
s_axi_rlast_int = current_m_axi_rlast;
s_axi_ruser_int = current_m_axi_ruser;
s_axi_rvalid_int = 1'b0;
m_axi_wdata_int = current_s_axi_wdata;
m_axi_wstrb_int = current_s_axi_wstrb;
m_axi_wlast_int = current_s_axi_wlast;
m_axi_wuser_int = current_s_axi_wuser;
m_axi_wvalid_int = 1'b0;
case (state_reg)
STATE_IDLE: begin
// idle state; wait for arbitration
if (grant_valid) begin
axi_addr_valid_next = 1'b1;
if (read) begin
// reading
axi_addr_next = current_s_axi_araddr;
axi_prot_next = current_s_axi_arprot;
axi_id_next = current_s_axi_arid;
axi_addr_next = current_s_axi_araddr;
axi_len_next = current_s_axi_arlen;
axi_size_next = current_s_axi_arsize;
axi_burst_next = current_s_axi_arburst;
axi_lock_next = current_s_axi_arlock;
axi_cache_next = current_s_axi_arcache;
axi_prot_next = current_s_axi_arprot;
axi_qos_next = current_s_axi_arqos;
axi_auser_next = current_s_axi_aruser;
s_axi_arready_next[s_select] = 1'b1;
end else begin
// writing
axi_addr_next = current_s_axi_awaddr;
axi_prot_next = current_s_axi_awprot;
axi_id_next = current_s_axi_awid;
axi_addr_next = current_s_axi_awaddr;
axi_len_next = current_s_axi_awlen;
axi_size_next = current_s_axi_awsize;
axi_burst_next = current_s_axi_awburst;
axi_lock_next = current_s_axi_awlock;
axi_cache_next = current_s_axi_awcache;
axi_prot_next = current_s_axi_awprot;
axi_qos_next = current_s_axi_awqos;
axi_auser_next = current_s_axi_awuser;
s_axi_awready_next[s_select] = 1'b1;
end
state_next = STATE_DECODE;
end else begin
state_next = STATE_IDLE;
end
end
STATE_DECODE: begin
// decode state; determine master interface
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] || !axi_prot_reg[1]) && ((read ? M_CONNECT_READ : M_CONNECT_WRITE) & (1 << (s_select+i*S_COUNT))) && (axi_addr_reg >> M_ADDR_WIDTH[(i*M_REGIONS+j)*32 +: 32]) == (M_BASE_ADDR_INT[(i*M_REGIONS+j)*ADDR_WIDTH +: ADDR_WIDTH] >> M_ADDR_WIDTH[(i*M_REGIONS+j)*32 +: 32])) begin
m_select_next = i;
axi_region_next = j;
match = 1'b1;
end
end
end
if (match) begin
if (read) begin
// reading
m_axi_rready_next[m_select_reg] = s_axi_rready_int_early;
state_next = STATE_READ;
end else begin
// writing
s_axi_wready_next[s_select] = m_axi_wready_int_early;
state_next = STATE_WRITE;
end
end else begin
// no match; return decode error
if (read) begin
// reading
state_next = STATE_READ_DROP;
end else begin
// writing
axi_bresp_next = 2'b11;
s_axi_wready_next[s_select] = 1'b1;
state_next = STATE_WRITE_DROP;
end
end
end
STATE_WRITE: begin
// write state; store and forward write data
s_axi_wready_next[s_select] = m_axi_wready_int_early;
if (axi_addr_valid_reg) begin
m_axi_awvalid_next[m_select_reg] = 1'b1;
end
axi_addr_valid_next = 1'b0;
if (current_s_axi_wready && current_s_axi_wvalid) begin
m_axi_wdata_int = current_s_axi_wdata;
m_axi_wstrb_int = current_s_axi_wstrb;
m_axi_wlast_int = current_s_axi_wlast;
m_axi_wuser_int = current_s_axi_wuser;
m_axi_wvalid_int = 1'b1;
if (current_s_axi_wlast) begin
s_axi_wready_next[s_select] = 1'b0;
m_axi_bready_next[m_select_reg] = 1'b1;
state_next = STATE_WRITE_RESP;
end else begin
state_next = STATE_WRITE;
end
end else begin
state_next = STATE_WRITE;
end
end
STATE_WRITE_RESP: begin
// write response state; store and forward write response
m_axi_bready_next[m_select_reg] = 1'b1;
if (current_m_axi_bready && current_m_axi_bvalid) begin
m_axi_bready_next[m_select_reg] = 1'b0;
axi_bresp_next = current_m_axi_bresp;
s_axi_bvalid_next[s_select] = 1'b1;
state_next = STATE_WAIT_IDLE;
end else begin
state_next = STATE_WRITE_RESP;
end
end
STATE_WRITE_DROP: begin
// write drop state; drop write data
s_axi_wready_next[s_select] = 1'b1;
axi_addr_valid_next = 1'b0;
if (current_s_axi_wready && current_s_axi_wvalid) begin
s_axi_wready_next[s_select] = 1'b0;
s_axi_bvalid_next[s_select] = 1'b1;
state_next = STATE_WAIT_IDLE;
end else begin
state_next = STATE_WRITE_DROP;
end
end
STATE_READ: begin
// read state; store and forward read response
m_axi_rready_next[m_select_reg] = s_axi_rready_int_early;
if (axi_addr_valid_reg) begin
m_axi_arvalid_next[m_select_reg] = 1'b1;
end
axi_addr_valid_next = 1'b0;
if (current_m_axi_rready && current_m_axi_rvalid) begin
s_axi_rid_int = axi_id_reg;
s_axi_rdata_int = current_m_axi_rdata;
s_axi_rresp_int = current_m_axi_rresp;
s_axi_rlast_int = current_m_axi_rlast;
s_axi_ruser_int = current_m_axi_ruser;
s_axi_rvalid_int = 1'b1;
if (current_m_axi_rlast) begin
m_axi_rready_next[m_select_reg] = 1'b0;
state_next = STATE_WAIT_IDLE;
end else begin
state_next = STATE_READ;
end
end else begin
state_next = STATE_READ;
end
end
STATE_READ_DROP: begin
// read drop state; generate decode error read response
s_axi_rid_int = axi_id_reg;
s_axi_rdata_int = {DATA_WIDTH{1'b0}};
s_axi_rresp_int = 2'b11;
s_axi_rlast_int = axi_len_reg == 0;
s_axi_ruser_int = {RUSER_WIDTH{1'b0}};
s_axi_rvalid_int = 1'b1;
if (s_axi_rready_int_reg) begin
axi_len_next = axi_len_reg - 1;
if (axi_len_reg == 0) begin
state_next = STATE_WAIT_IDLE;
end else begin
state_next = STATE_READ_DROP;
end
end else begin
state_next = STATE_READ_DROP;
end
end
STATE_WAIT_IDLE: begin
// wait for idle state; wait untl grant valid is deasserted
if (!grant_valid || acknowledge) begin
state_next = STATE_IDLE;
end else begin
state_next = STATE_WAIT_IDLE;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
s_axi_awready_reg <= 0;
s_axi_wready_reg <= 0;
s_axi_bvalid_reg <= 0;
s_axi_arready_reg <= 0;
m_axi_awvalid_reg <= 0;
m_axi_bready_reg <= 0;
m_axi_arvalid_reg <= 0;
m_axi_rready_reg <= 0;
end else begin
state_reg <= state_next;
s_axi_awready_reg <= s_axi_awready_next;
s_axi_wready_reg <= s_axi_wready_next;
s_axi_bvalid_reg <= s_axi_bvalid_next;
s_axi_arready_reg <= s_axi_arready_next;
m_axi_awvalid_reg <= m_axi_awvalid_next;
m_axi_bready_reg <= m_axi_bready_next;
m_axi_arvalid_reg <= m_axi_arvalid_next;
m_axi_rready_reg <= m_axi_rready_next;
end
m_select_reg <= m_select_next;
axi_id_reg <= axi_id_next;
axi_addr_reg <= axi_addr_next;
axi_addr_valid_reg <= axi_addr_valid_next;
axi_len_reg <= axi_len_next;
axi_size_reg <= axi_size_next;
axi_burst_reg <= axi_burst_next;
axi_lock_reg <= axi_lock_next;
axi_cache_reg <= axi_cache_next;
axi_prot_reg <= axi_prot_next;
axi_qos_reg <= axi_qos_next;
axi_region_reg <= axi_region_next;
axi_auser_reg <= axi_auser_next;
axi_bresp_reg <= axi_bresp_next;
axi_buser_reg <= axi_buser_next;
end
// output datapath logic (R channel)
reg [ID_WIDTH-1:0] s_axi_rid_reg = {ID_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] s_axi_rdata_reg = {DATA_WIDTH{1'b0}};
reg [1:0] s_axi_rresp_reg = 2'd0;
reg s_axi_rlast_reg = 1'b0;
reg [RUSER_WIDTH-1:0] s_axi_ruser_reg = 1'b0;
reg [S_COUNT-1:0] s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next;
reg [ID_WIDTH-1:0] temp_s_axi_rid_reg = {ID_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] temp_s_axi_rdata_reg = {DATA_WIDTH{1'b0}};
reg [1:0] temp_s_axi_rresp_reg = 2'd0;
reg temp_s_axi_rlast_reg = 1'b0;
reg [RUSER_WIDTH-1:0] temp_s_axi_ruser_reg = 1'b0;
reg temp_s_axi_rvalid_reg = 1'b0, temp_s_axi_rvalid_next;
// datapath control
reg store_axi_r_int_to_output;
reg store_axi_r_int_to_temp;
reg store_axi_r_temp_to_output;
assign s_axi_rid = {S_COUNT{s_axi_rid_reg}};
assign s_axi_rdata = {S_COUNT{s_axi_rdata_reg}};
assign s_axi_rresp = {S_COUNT{s_axi_rresp_reg}};
assign s_axi_rlast = {S_COUNT{s_axi_rlast_reg}};
assign s_axi_ruser = {S_COUNT{RUSER_ENABLE ? s_axi_ruser_reg : {RUSER_WIDTH{1'b0}}}};
assign s_axi_rvalid = s_axi_rvalid_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign s_axi_rready_int_early = current_s_axi_rready | (~temp_s_axi_rvalid_reg & (~current_s_axi_rvalid | ~s_axi_rvalid_int));
always @* begin
// transfer sink ready state to source
s_axi_rvalid_next = s_axi_rvalid_reg;
temp_s_axi_rvalid_next = temp_s_axi_rvalid_reg;
store_axi_r_int_to_output = 1'b0;
store_axi_r_int_to_temp = 1'b0;
store_axi_r_temp_to_output = 1'b0;
if (s_axi_rready_int_reg) begin
// input is ready
if (current_s_axi_rready | ~current_s_axi_rvalid) begin
// output is ready or currently not valid, transfer data to output
s_axi_rvalid_next[s_select] = s_axi_rvalid_int;
store_axi_r_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_s_axi_rvalid_next = s_axi_rvalid_int;
store_axi_r_int_to_temp = 1'b1;
end
end else if (current_s_axi_rready) begin
// input is not ready, but output is ready
s_axi_rvalid_next[s_select] = temp_s_axi_rvalid_reg;
temp_s_axi_rvalid_next = 1'b0;
store_axi_r_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
s_axi_rvalid_reg <= 1'b0;
s_axi_rready_int_reg <= 1'b0;
temp_s_axi_rvalid_reg <= 1'b0;
end else begin
s_axi_rvalid_reg <= s_axi_rvalid_next;
s_axi_rready_int_reg <= s_axi_rready_int_early;
temp_s_axi_rvalid_reg <= temp_s_axi_rvalid_next;
end
// datapath
if (store_axi_r_int_to_output) begin
s_axi_rid_reg <= s_axi_rid_int;
s_axi_rdata_reg <= s_axi_rdata_int;
s_axi_rresp_reg <= s_axi_rresp_int;
s_axi_rlast_reg <= s_axi_rlast_int;
s_axi_ruser_reg <= s_axi_ruser_int;
end else if (store_axi_r_temp_to_output) begin
s_axi_rid_reg <= temp_s_axi_rid_reg;
s_axi_rdata_reg <= temp_s_axi_rdata_reg;
s_axi_rresp_reg <= temp_s_axi_rresp_reg;
s_axi_rlast_reg <= temp_s_axi_rlast_reg;
s_axi_ruser_reg <= temp_s_axi_ruser_reg;
end
if (store_axi_r_int_to_temp) begin
temp_s_axi_rid_reg <= s_axi_rid_int;
temp_s_axi_rdata_reg <= s_axi_rdata_int;
temp_s_axi_rresp_reg <= s_axi_rresp_int;
temp_s_axi_rlast_reg <= s_axi_rlast_int;
temp_s_axi_ruser_reg <= s_axi_ruser_int;
end
end
// output datapath logic (W channel)
reg [DATA_WIDTH-1:0] m_axi_wdata_reg = {DATA_WIDTH{1'b0}};
reg [STRB_WIDTH-1:0] m_axi_wstrb_reg = {STRB_WIDTH{1'b0}};
reg m_axi_wlast_reg = 1'b0;
reg [WUSER_WIDTH-1:0] m_axi_wuser_reg = 1'b0;
reg [M_COUNT-1:0] m_axi_wvalid_reg = 1'b0, m_axi_wvalid_next;
reg [DATA_WIDTH-1:0] temp_m_axi_wdata_reg = {DATA_WIDTH{1'b0}};
reg [STRB_WIDTH-1:0] temp_m_axi_wstrb_reg = {STRB_WIDTH{1'b0}};
reg temp_m_axi_wlast_reg = 1'b0;
reg [WUSER_WIDTH-1:0] temp_m_axi_wuser_reg = 1'b0;
reg temp_m_axi_wvalid_reg = 1'b0, temp_m_axi_wvalid_next;
// datapath control
reg store_axi_w_int_to_output;
reg store_axi_w_int_to_temp;
reg store_axi_w_temp_to_output;
assign m_axi_wdata = {M_COUNT{m_axi_wdata_reg}};
assign m_axi_wstrb = {M_COUNT{m_axi_wstrb_reg}};
assign m_axi_wlast = {M_COUNT{m_axi_wlast_reg}};
assign m_axi_wuser = {M_COUNT{WUSER_ENABLE ? m_axi_wuser_reg : {WUSER_WIDTH{1'b0}}}};
assign m_axi_wvalid = m_axi_wvalid_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign m_axi_wready_int_early = current_m_axi_wready | (~temp_m_axi_wvalid_reg & (~current_m_axi_wvalid | ~m_axi_wvalid_int));
always @* begin
// transfer sink ready state to source
m_axi_wvalid_next = m_axi_wvalid_reg;
temp_m_axi_wvalid_next = temp_m_axi_wvalid_reg;
store_axi_w_int_to_output = 1'b0;
store_axi_w_int_to_temp = 1'b0;
store_axi_w_temp_to_output = 1'b0;
if (m_axi_wready_int_reg) begin
// input is ready
if (current_m_axi_wready | ~current_m_axi_wvalid) begin
// output is ready or currently not valid, transfer data to output
m_axi_wvalid_next[m_select_reg] = m_axi_wvalid_int;
store_axi_w_int_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axi_wvalid_next = m_axi_wvalid_int;
store_axi_w_int_to_temp = 1'b1;
end
end else if (current_m_axi_wready) begin
// input is not ready, but output is ready
m_axi_wvalid_next[m_select_reg] = temp_m_axi_wvalid_reg;
temp_m_axi_wvalid_next = 1'b0;
store_axi_w_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_axi_wvalid_reg <= 1'b0;
m_axi_wready_int_reg <= 1'b0;
temp_m_axi_wvalid_reg <= 1'b0;
end else begin
m_axi_wvalid_reg <= m_axi_wvalid_next;
m_axi_wready_int_reg <= m_axi_wready_int_early;
temp_m_axi_wvalid_reg <= temp_m_axi_wvalid_next;
end
// datapath
if (store_axi_w_int_to_output) begin
m_axi_wdata_reg <= m_axi_wdata_int;
m_axi_wstrb_reg <= m_axi_wstrb_int;
m_axi_wlast_reg <= m_axi_wlast_int;
m_axi_wuser_reg <= m_axi_wuser_int;
end else if (store_axi_w_temp_to_output) begin
m_axi_wdata_reg <= temp_m_axi_wdata_reg;
m_axi_wstrb_reg <= temp_m_axi_wstrb_reg;
m_axi_wlast_reg <= temp_m_axi_wlast_reg;
m_axi_wuser_reg <= temp_m_axi_wuser_reg;
end
if (store_axi_w_int_to_temp) begin
temp_m_axi_wdata_reg <= m_axi_wdata_int;
temp_m_axi_wstrb_reg <= m_axi_wstrb_int;
temp_m_axi_wlast_reg <= m_axi_wlast_int;
temp_m_axi_wuser_reg <= m_axi_wuser_int;
end
end
endmodule
/*
Copyright (c) 2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* AXI4 RAM
*/
module axi_ram #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 16,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Width of ID signal
parameter ID_WIDTH = 8,
// Extra pipeline register on output
parameter PIPELINE_OUTPUT = 0
)
(
input wire clk,
input wire rst,
input wire [ID_WIDTH-1:0] s_axi_awid,
input wire [ADDR_WIDTH-1:0] s_axi_awaddr,
input wire [7:0] s_axi_awlen,
input wire [2:0] s_axi_awsize,
input wire [1:0] s_axi_awburst,
input wire s_axi_awlock,
input wire [3:0] s_axi_awcache,
input wire [2:0] s_axi_awprot,
input wire s_axi_awvalid,
output wire s_axi_awready,
input wire [DATA_WIDTH-1:0] s_axi_wdata,
input wire [STRB_WIDTH-1:0] s_axi_wstrb,
input wire s_axi_wlast,
input wire s_axi_wvalid,
output wire s_axi_wready,
output wire [ID_WIDTH-1:0] s_axi_bid,
output wire [1:0] s_axi_bresp,
output wire s_axi_bvalid,
input wire s_axi_bready,
input wire [ID_WIDTH-1:0] s_axi_arid,
input wire [ADDR_WIDTH-1:0] s_axi_araddr,
input wire [7:0] s_axi_arlen,
input wire [2:0] s_axi_arsize,
input wire [1:0] s_axi_arburst,
input wire s_axi_arlock,
input wire [3:0] s_axi_arcache,
input wire [2:0] s_axi_arprot,
input wire s_axi_arvalid,
output wire s_axi_arready,
output wire [ID_WIDTH-1:0] s_axi_rid,
output wire [DATA_WIDTH-1:0] s_axi_rdata,
output wire [1:0] s_axi_rresp,
output wire s_axi_rlast,
output wire s_axi_rvalid,
input wire s_axi_rready
);
parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(STRB_WIDTH);
parameter WORD_WIDTH = STRB_WIDTH;
parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH;
// bus width assertions
initial begin
if (WORD_SIZE * STRB_WIDTH != DATA_WIDTH) begin
$error("Error: AXI data width not evenly divisble (instance %m)");
$finish;
end
if (2**$clog2(WORD_WIDTH) != WORD_WIDTH) begin
$error("Error: AXI word width must be even power of two (instance %m)");
$finish;
end
end
localparam [0:0]
READ_STATE_IDLE = 1'd0,
READ_STATE_BURST = 1'd1;
reg [0:0] read_state_reg = READ_STATE_IDLE, read_state_next;
localparam [1:0]
WRITE_STATE_IDLE = 2'd0,
WRITE_STATE_BURST = 2'd1,
WRITE_STATE_RESP = 2'd2;
reg [1:0] write_state_reg = WRITE_STATE_IDLE, write_state_next;
reg mem_wr_en;
reg mem_rd_en;
reg [ID_WIDTH-1:0] read_id_reg = {ID_WIDTH{1'b0}}, read_id_next;
reg [ADDR_WIDTH-1:0] read_addr_reg = {ADDR_WIDTH{1'b0}}, read_addr_next;
reg [7:0] read_count_reg = 8'd0, read_count_next;
reg [2:0] read_size_reg = 3'd0, read_size_next;
reg [1:0] read_burst_reg = 2'd0, read_burst_next;
reg [ID_WIDTH-1:0] write_id_reg = {ID_WIDTH{1'b0}}, write_id_next;
reg [ADDR_WIDTH-1:0] write_addr_reg = {ADDR_WIDTH{1'b0}}, write_addr_next;
reg [7:0] write_count_reg = 8'd0, write_count_next;
reg [2:0] write_size_reg = 3'd0, write_size_next;
reg [1:0] write_burst_reg = 2'd0, write_burst_next;
reg s_axi_awready_reg = 1'b0, s_axi_awready_next;
reg s_axi_wready_reg = 1'b0, s_axi_wready_next;
reg [ID_WIDTH-1:0] s_axi_bid_reg = {ID_WIDTH{1'b0}}, s_axi_bid_next;
reg s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next;
reg s_axi_arready_reg = 1'b0, s_axi_arready_next;
reg [ID_WIDTH-1:0] s_axi_rid_reg = {ID_WIDTH{1'b0}}, s_axi_rid_next;
reg [DATA_WIDTH-1:0] s_axi_rdata_reg = {DATA_WIDTH{1'b0}}, s_axi_rdata_next;
reg s_axi_rlast_reg = 1'b0, s_axi_rlast_next;
reg s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next;
reg [ID_WIDTH-1:0] s_axi_rid_pipe_reg = {ID_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] s_axi_rdata_pipe_reg = {DATA_WIDTH{1'b0}};
reg s_axi_rlast_pipe_reg = 1'b0;
reg s_axi_rvalid_pipe_reg = 1'b0;
// (* RAM_STYLE="BLOCK" *)
reg [DATA_WIDTH-1:0] mem[(2**VALID_ADDR_WIDTH)-1:0];
wire [VALID_ADDR_WIDTH-1:0] s_axi_awaddr_valid = s_axi_awaddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
wire [VALID_ADDR_WIDTH-1:0] s_axi_araddr_valid = s_axi_araddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
wire [VALID_ADDR_WIDTH-1:0] read_addr_valid = read_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
wire [VALID_ADDR_WIDTH-1:0] write_addr_valid = write_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
assign s_axi_awready = s_axi_awready_reg;
assign s_axi_wready = s_axi_wready_reg;
assign s_axi_bid = s_axi_bid_reg;
assign s_axi_bresp = 2'b00;
assign s_axi_bvalid = s_axi_bvalid_reg;
assign s_axi_arready = s_axi_arready_reg;
assign s_axi_rid = PIPELINE_OUTPUT ? s_axi_rid_pipe_reg : s_axi_rid_reg;
assign s_axi_rdata = PIPELINE_OUTPUT ? s_axi_rdata_pipe_reg : s_axi_rdata_reg;
assign s_axi_rresp = 2'b00;
assign s_axi_rlast = PIPELINE_OUTPUT ? s_axi_rlast_pipe_reg : s_axi_rlast_reg;
assign s_axi_rvalid = PIPELINE_OUTPUT ? s_axi_rvalid_pipe_reg : s_axi_rvalid_reg;
integer i, j;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (i = 0; i < 2**ADDR_WIDTH; i = i + 2**(ADDR_WIDTH/2)) begin
for (j = i; j < i + 2**(ADDR_WIDTH/2); j = j + 1) begin
mem[j] = 0;
end
end
end
always @* begin
write_state_next = WRITE_STATE_IDLE;
mem_wr_en = 1'b0;
write_id_next = write_id_reg;
write_addr_next = write_addr_reg;
write_count_next = write_count_reg;
write_size_next = write_size_reg;
write_burst_next = write_burst_reg;
s_axi_awready_next = 1'b0;
s_axi_wready_next = 1'b0;
s_axi_bid_next = s_axi_bid_reg;
s_axi_bvalid_next = s_axi_bvalid_reg && !s_axi_bready;
case (write_state_reg)
WRITE_STATE_IDLE: begin
s_axi_awready_next = 1'b1;
if (s_axi_awready && s_axi_awvalid) begin
write_id_next = s_axi_awid;
write_addr_next = s_axi_awaddr;
write_count_next = s_axi_awlen;
write_size_next = s_axi_awsize < $clog2(STRB_WIDTH) ? s_axi_awsize : $clog2(STRB_WIDTH);
write_burst_next = s_axi_awburst;
s_axi_awready_next = 1'b0;
s_axi_wready_next = 1'b1;
write_state_next = WRITE_STATE_BURST;
end else begin
write_state_next = WRITE_STATE_IDLE;
end
end
WRITE_STATE_BURST: begin
s_axi_wready_next = 1'b1;
if (s_axi_wready && s_axi_wvalid) begin
mem_wr_en = 1'b1;
if (write_burst_reg != 2'b00) begin
write_addr_next = write_addr_reg + (1 << write_size_reg);
end
write_count_next = write_count_reg - 1;
if (write_count_reg > 0) begin
write_state_next = WRITE_STATE_BURST;
end else begin
s_axi_wready_next = 1'b0;
if (s_axi_bready || !s_axi_bvalid) begin
s_axi_bid_next = write_id_reg;
s_axi_bvalid_next = 1'b1;
s_axi_awready_next = 1'b1;
write_state_next = WRITE_STATE_IDLE;
end else begin
write_state_next = WRITE_STATE_RESP;
end
end
end else begin
write_state_next = WRITE_STATE_BURST;
end
end
WRITE_STATE_RESP: begin
if (s_axi_bready || !s_axi_bvalid) begin
s_axi_bid_next = write_id_reg;
s_axi_bvalid_next = 1'b1;
s_axi_awready_next = 1'b1;
write_state_next = WRITE_STATE_IDLE;
end else begin
write_state_next = WRITE_STATE_RESP;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
write_state_reg <= WRITE_STATE_IDLE;
s_axi_awready_reg <= 1'b0;
s_axi_wready_reg <= 1'b0;
s_axi_bvalid_reg <= 1'b0;
end else begin
write_state_reg <= write_state_next;
s_axi_awready_reg <= s_axi_awready_next;
s_axi_wready_reg <= s_axi_wready_next;
s_axi_bvalid_reg <= s_axi_bvalid_next;
end
write_id_reg <= write_id_next;
write_addr_reg <= write_addr_next;
write_count_reg <= write_count_next;
write_size_reg <= write_size_next;
write_burst_reg <= write_burst_next;
s_axi_bid_reg <= s_axi_bid_next;
for (i = 0; i < WORD_WIDTH; i = i + 1) begin
if (mem_wr_en & s_axi_wstrb[i]) begin
mem[write_addr_valid][WORD_SIZE*i +: WORD_SIZE] <= s_axi_wdata[WORD_SIZE*i +: WORD_SIZE];
end
end
end
always @* begin
read_state_next = READ_STATE_IDLE;
mem_rd_en = 1'b0;
s_axi_rid_next = s_axi_rid_reg;
s_axi_rlast_next = s_axi_rlast_reg;
s_axi_rvalid_next = s_axi_rvalid_reg && !(s_axi_rready || (PIPELINE_OUTPUT && !s_axi_rvalid_pipe_reg));
read_id_next = read_id_reg;
read_addr_next = read_addr_reg;
read_count_next = read_count_reg;
read_size_next = read_size_reg;
read_burst_next = read_burst_reg;
s_axi_arready_next = 1'b0;
case (read_state_reg)
READ_STATE_IDLE: begin
s_axi_arready_next = 1'b1;
if (s_axi_arready && s_axi_arvalid) begin
read_id_next = s_axi_arid;
read_addr_next = s_axi_araddr;
read_count_next = s_axi_arlen;
read_size_next = s_axi_arsize < $clog2(STRB_WIDTH) ? s_axi_arsize : $clog2(STRB_WIDTH);
read_burst_next = s_axi_arburst;
s_axi_arready_next = 1'b0;
read_state_next = READ_STATE_BURST;
end else begin
read_state_next = READ_STATE_IDLE;
end
end
READ_STATE_BURST: begin
if (s_axi_rready || (PIPELINE_OUTPUT && !s_axi_rvalid_pipe_reg) || !s_axi_rvalid_reg) begin
mem_rd_en = 1'b1;
s_axi_rvalid_next = 1'b1;
s_axi_rid_next = read_id_reg;
s_axi_rlast_next = read_count_reg == 0;
if (read_burst_reg != 2'b00) begin
read_addr_next = read_addr_reg + (1 << read_size_reg);
end
read_count_next = read_count_reg - 1;
if (read_count_reg > 0) begin
read_state_next = READ_STATE_BURST;
end else begin
s_axi_arready_next = 1'b1;
read_state_next = READ_STATE_IDLE;
end
end else begin
read_state_next = READ_STATE_BURST;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
read_state_reg <= READ_STATE_IDLE;
s_axi_arready_reg <= 1'b0;
s_axi_rvalid_reg <= 1'b0;
s_axi_rvalid_pipe_reg <= 1'b0;
end else begin
read_state_reg <= read_state_next;
s_axi_arready_reg <= s_axi_arready_next;
s_axi_rvalid_reg <= s_axi_rvalid_next;
if (!s_axi_rvalid_pipe_reg || s_axi_rready) begin
s_axi_rvalid_pipe_reg <= s_axi_rvalid_reg;
end
end
read_id_reg <= read_id_next;
read_addr_reg <= read_addr_next;
read_count_reg <= read_count_next;
read_size_reg <= read_size_next;
read_burst_reg <= read_burst_next;
s_axi_rid_reg <= s_axi_rid_next;
s_axi_rlast_reg <= s_axi_rlast_next;
if (mem_rd_en) begin
s_axi_rdata_reg <= mem[read_addr_valid];
end
if (!s_axi_rvalid_pipe_reg || s_axi_rready) begin
s_axi_rid_pipe_reg <= s_axi_rid_reg;
s_axi_rdata_pipe_reg <= s_axi_rdata_reg;
s_axi_rlast_pipe_reg <= s_axi_rlast_reg;
end
end
endmodule
/*
Copyright (c) 2019 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* AXI4 RAM read interface
*/
module axi_ram_rd_if #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 16,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Width of ID signal
parameter ID_WIDTH = 8,
// Propagate aruser signal
parameter ARUSER_ENABLE = 0,
// Width of aruser signal
parameter ARUSER_WIDTH = 1,
// Propagate ruser signal
parameter RUSER_ENABLE = 0,
// Width of ruser signal
parameter RUSER_WIDTH = 1,
// Extra pipeline register on output
parameter PIPELINE_OUTPUT = 0
)
(
input wire clk,
input wire rst,
/*
* AXI slave interface
*/
input wire [ID_WIDTH-1:0] s_axi_arid,
input wire [ADDR_WIDTH-1:0] s_axi_araddr,
input wire [7:0] s_axi_arlen,
input wire [2:0] s_axi_arsize,
input wire [1:0] s_axi_arburst,
input wire s_axi_arlock,
input wire [3:0] s_axi_arcache,
input wire [2:0] s_axi_arprot,
input wire [3:0] s_axi_arqos,
input wire [3:0] s_axi_arregion,
input wire [ARUSER_WIDTH-1:0] s_axi_aruser,
input wire s_axi_arvalid,
output wire s_axi_arready,
output wire [ID_WIDTH-1:0] s_axi_rid,
output wire [DATA_WIDTH-1:0] s_axi_rdata,
output wire [1:0] s_axi_rresp,
output wire s_axi_rlast,
output wire [RUSER_WIDTH-1:0] s_axi_ruser,
output wire s_axi_rvalid,
input wire s_axi_rready,
/*
* RAM interface
*/
output wire [ID_WIDTH-1:0] ram_rd_cmd_id,
output wire [ADDR_WIDTH-1:0] ram_rd_cmd_addr,
output wire ram_rd_cmd_lock,
output wire [3:0] ram_rd_cmd_cache,
output wire [2:0] ram_rd_cmd_prot,
output wire [3:0] ram_rd_cmd_qos,
output wire [3:0] ram_rd_cmd_region,
output wire [ARUSER_WIDTH-1:0] ram_rd_cmd_auser,
output wire ram_rd_cmd_en,
output wire ram_rd_cmd_last,
input wire ram_rd_cmd_ready,
input wire [ID_WIDTH-1:0] ram_rd_resp_id,
input wire [DATA_WIDTH-1:0] ram_rd_resp_data,
input wire ram_rd_resp_last,
input wire [RUSER_WIDTH-1:0] ram_rd_resp_user,
input wire ram_rd_resp_valid,
output wire ram_rd_resp_ready
);
parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(STRB_WIDTH);
parameter WORD_WIDTH = STRB_WIDTH;
parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH;
// bus width assertions
initial begin
if (WORD_SIZE * STRB_WIDTH != DATA_WIDTH) begin
$error("Error: AXI data width not evenly divisble (instance %m)");
$finish;
end
if (2**$clog2(WORD_WIDTH) != WORD_WIDTH) begin
$error("Error: AXI word width must be even power of two (instance %m)");
$finish;
end
end
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_BURST = 1'd1;
reg [0:0] state_reg = STATE_IDLE, state_next;
reg [ID_WIDTH-1:0] read_id_reg = {ID_WIDTH{1'b0}}, read_id_next;
reg [ADDR_WIDTH-1:0] read_addr_reg = {ADDR_WIDTH{1'b0}}, read_addr_next;
reg read_lock_reg = 1'b0, read_lock_next;
reg [3:0] read_cache_reg = 4'd0, read_cache_next;
reg [2:0] read_prot_reg = 3'd0, read_prot_next;
reg [3:0] read_qos_reg = 4'd0, read_qos_next;
reg [3:0] read_region_reg = 4'd0, read_region_next;
reg [ARUSER_WIDTH-1:0] read_aruser_reg = {ARUSER_WIDTH{1'b0}}, read_aruser_next;
reg read_addr_valid_reg = 1'b0, read_addr_valid_next;
reg read_last_reg = 1'b0, read_last_next;
reg [7:0] read_count_reg = 8'd0, read_count_next;
reg [2:0] read_size_reg = 3'd0, read_size_next;
reg [1:0] read_burst_reg = 2'd0, read_burst_next;
reg s_axi_arready_reg = 1'b0, s_axi_arready_next;
reg [ID_WIDTH-1:0] s_axi_rid_pipe_reg = {ID_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] s_axi_rdata_pipe_reg = {DATA_WIDTH{1'b0}};
reg s_axi_rlast_pipe_reg = 1'b0;
reg [RUSER_WIDTH-1:0] s_axi_ruser_pipe_reg = {RUSER_WIDTH{1'b0}};
reg s_axi_rvalid_pipe_reg = 1'b0;
assign s_axi_arready = s_axi_arready_reg;
assign s_axi_rid = PIPELINE_OUTPUT ? s_axi_rid_pipe_reg : ram_rd_resp_id;
assign s_axi_rdata = PIPELINE_OUTPUT ? s_axi_rdata_pipe_reg : ram_rd_resp_data;
assign s_axi_rresp = 2'b00;
assign s_axi_rlast = PIPELINE_OUTPUT ? s_axi_rlast_pipe_reg : ram_rd_resp_last;
assign s_axi_ruser = PIPELINE_OUTPUT ? s_axi_ruser_pipe_reg : ram_rd_resp_user;
assign s_axi_rvalid = PIPELINE_OUTPUT ? s_axi_rvalid_pipe_reg : ram_rd_resp_valid;
assign ram_rd_cmd_id = read_id_reg;
assign ram_rd_cmd_addr = read_addr_reg;
assign ram_rd_cmd_lock = read_lock_reg;
assign ram_rd_cmd_cache = read_cache_reg;
assign ram_rd_cmd_prot = read_prot_reg;
assign ram_rd_cmd_qos = read_qos_reg;
assign ram_rd_cmd_region = read_region_reg;
assign ram_rd_cmd_auser = ARUSER_ENABLE ? read_aruser_reg : {ARUSER_WIDTH{1'b0}};
assign ram_rd_cmd_en = read_addr_valid_reg;
assign ram_rd_cmd_last = read_last_reg;
assign ram_rd_resp_ready = s_axi_rready || (PIPELINE_OUTPUT && !s_axi_rvalid_pipe_reg);
always @* begin
state_next = STATE_IDLE;
read_id_next = read_id_reg;
read_addr_next = read_addr_reg;
read_lock_next = read_lock_reg;
read_cache_next = read_cache_reg;
read_prot_next = read_prot_reg;
read_qos_next = read_qos_reg;
read_region_next = read_region_reg;
read_aruser_next = read_aruser_reg;
read_addr_valid_next = read_addr_valid_reg && !ram_rd_cmd_ready;
read_last_next = read_last_reg;
read_count_next = read_count_reg;
read_size_next = read_size_reg;
read_burst_next = read_burst_reg;
s_axi_arready_next = 1'b0;
case (state_reg)
STATE_IDLE: begin
s_axi_arready_next = 1'b1;
if (s_axi_arready && s_axi_arvalid) begin
read_id_next = s_axi_arid;
read_addr_next = s_axi_araddr;
read_lock_next = s_axi_arlock;
read_cache_next = s_axi_arcache;
read_prot_next = s_axi_arprot;
read_qos_next = s_axi_arqos;
read_region_next = s_axi_arregion;
read_aruser_next = s_axi_aruser;
read_count_next = s_axi_arlen;
read_size_next = s_axi_arsize < $clog2(STRB_WIDTH) ? s_axi_arsize : $clog2(STRB_WIDTH);
read_burst_next = s_axi_arburst;
s_axi_arready_next = 1'b0;
read_last_next = read_count_next == 0;
read_addr_valid_next = 1'b1;
state_next = STATE_BURST;
end else begin
state_next = STATE_IDLE;
end
end
STATE_BURST: begin
if (ram_rd_cmd_ready && ram_rd_cmd_en) begin
if (read_burst_reg != 2'b00) begin
read_addr_next = read_addr_reg + (1 << read_size_reg);
end
read_count_next = read_count_reg - 1;
read_last_next = read_count_next == 0;
if (read_count_reg > 0) begin
read_addr_valid_next = 1'b1;
state_next = STATE_BURST;
end else begin
s_axi_arready_next = 1'b1;
state_next = STATE_IDLE;
end
end else begin
state_next = STATE_BURST;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
read_addr_valid_reg <= 1'b0;
s_axi_arready_reg <= 1'b0;
s_axi_rvalid_pipe_reg <= 1'b0;
end else begin
state_reg <= state_next;
read_addr_valid_reg <= read_addr_valid_next;
s_axi_arready_reg <= s_axi_arready_next;
if (!s_axi_rvalid_pipe_reg || s_axi_rready) begin
s_axi_rvalid_pipe_reg <= ram_rd_resp_valid;
end
end
read_id_reg <= read_id_next;
read_addr_reg <= read_addr_next;
read_lock_reg <= read_lock_next;
read_cache_reg <= read_cache_next;
read_prot_reg <= read_prot_next;
read_qos_reg <= read_qos_next;
read_region_reg <= read_region_next;
read_aruser_reg <= read_aruser_next;
read_last_reg <= read_last_next;
read_count_reg <= read_count_next;
read_size_reg <= read_size_next;
read_burst_reg <= read_burst_next;
if (!s_axi_rvalid_pipe_reg || s_axi_rready) begin
s_axi_rid_pipe_reg <= ram_rd_resp_id;
s_axi_rdata_pipe_reg <= ram_rd_resp_data;
s_axi_rlast_pipe_reg <= ram_rd_resp_last;
s_axi_ruser_pipe_reg <= ram_rd_resp_user;
end
end
endmodule
/*
Copyright (c) 2019 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* AXI4 RAM write interface
*/
module axi_ram_wr_if #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 16,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Width of ID signal
parameter ID_WIDTH = 8,
// Propagate awuser signal
parameter AWUSER_ENABLE = 0,
// Width of awuser signal
parameter AWUSER_WIDTH = 1,
// Propagate wuser signal
parameter WUSER_ENABLE = 0,
// Width of wuser signal
parameter WUSER_WIDTH = 1,
// Propagate buser signal
parameter BUSER_ENABLE = 0,
// Width of buser signal
parameter BUSER_WIDTH = 1
)
(
input wire clk,
input wire rst,
/*
* AXI slave interface
*/
input wire [ID_WIDTH-1:0] s_axi_awid,
input wire [ADDR_WIDTH-1:0] s_axi_awaddr,
input wire [7:0] s_axi_awlen,
input wire [2:0] s_axi_awsize,
input wire [1:0] s_axi_awburst,
input wire s_axi_awlock,
input wire [3:0] s_axi_awcache,
input wire [2:0] s_axi_awprot,
input wire [3:0] s_axi_awqos,
input wire [3:0] s_axi_awregion,
input wire [AWUSER_WIDTH-1:0] s_axi_awuser,
input wire s_axi_awvalid,
output wire s_axi_awready,
input wire [DATA_WIDTH-1:0] s_axi_wdata,
input wire [STRB_WIDTH-1:0] s_axi_wstrb,
input wire s_axi_wlast,
input wire [WUSER_WIDTH-1:0] s_axi_wuser,
input wire s_axi_wvalid,
output wire s_axi_wready,
output wire [ID_WIDTH-1:0] s_axi_bid,
output wire [1:0] s_axi_bresp,
output wire [BUSER_WIDTH-1:0] s_axi_buser,
output wire s_axi_bvalid,
input wire s_axi_bready,
/*
* RAM interface
*/
output wire [ID_WIDTH-1:0] ram_wr_cmd_id,
output wire [ADDR_WIDTH-1:0] ram_wr_cmd_addr,
output wire ram_wr_cmd_lock,
output wire [3:0] ram_wr_cmd_cache,
output wire [2:0] ram_wr_cmd_prot,
output wire [3:0] ram_wr_cmd_qos,
output wire [3:0] ram_wr_cmd_region,
output wire [AWUSER_WIDTH-1:0] ram_wr_cmd_auser,
output wire [DATA_WIDTH-1:0] ram_wr_cmd_data,
output wire [STRB_WIDTH-1:0] ram_wr_cmd_strb,
output wire [WUSER_WIDTH-1:0] ram_wr_cmd_user,
output wire ram_wr_cmd_en,
output wire ram_wr_cmd_last,
input wire ram_wr_cmd_ready
);
parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(STRB_WIDTH);
parameter WORD_WIDTH = STRB_WIDTH;
parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH;
// bus width assertions
initial begin
if (WORD_SIZE * STRB_WIDTH != DATA_WIDTH) begin
$error("Error: AXI data width not evenly divisble (instance %m)");
$finish;
end
if (2**$clog2(WORD_WIDTH) != WORD_WIDTH) begin
$error("Error: AXI word width must be even power of two (instance %m)");
$finish;
end
end
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_BURST = 2'd1,
STATE_RESP = 2'd2;
reg [1:0] state_reg = STATE_IDLE, state_next;
reg [ID_WIDTH-1:0] write_id_reg = {ID_WIDTH{1'b0}}, write_id_next;
reg [ADDR_WIDTH-1:0] write_addr_reg = {ADDR_WIDTH{1'b0}}, write_addr_next;
reg write_lock_reg = 1'b0, write_lock_next;
reg [3:0] write_cache_reg = 4'd0, write_cache_next;
reg [2:0] write_prot_reg = 3'd0, write_prot_next;
reg [3:0] write_qos_reg = 4'd0, write_qos_next;
reg [3:0] write_region_reg = 4'd0, write_region_next;
reg [AWUSER_WIDTH-1:0] write_awuser_reg = {AWUSER_WIDTH{1'b0}}, write_awuser_next;
reg write_addr_valid_reg = 1'b0, write_addr_valid_next;
reg write_last_reg = 1'b0, write_last_next;
reg [7:0] write_count_reg = 8'd0, write_count_next;
reg [2:0] write_size_reg = 3'd0, write_size_next;
reg [1:0] write_burst_reg = 2'd0, write_burst_next;
reg s_axi_awready_reg = 1'b0, s_axi_awready_next;
reg [ID_WIDTH-1:0] s_axi_bid_reg = {ID_WIDTH{1'b0}}, s_axi_bid_next;
reg s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next;
assign s_axi_awready = s_axi_awready_reg;
assign s_axi_wready = write_addr_valid_reg && ram_wr_cmd_ready;
assign s_axi_bid = s_axi_bid_reg;
assign s_axi_bresp = 2'b00;
assign s_axi_buser = {BUSER_WIDTH{1'b0}};
assign s_axi_bvalid = s_axi_bvalid_reg;
assign ram_wr_cmd_id = write_id_reg;
assign ram_wr_cmd_addr = write_addr_reg;
assign ram_wr_cmd_lock = write_lock_reg;
assign ram_wr_cmd_cache = write_cache_reg;
assign ram_wr_cmd_prot = write_prot_reg;
assign ram_wr_cmd_qos = write_qos_reg;
assign ram_wr_cmd_region = write_region_reg;
assign ram_wr_cmd_auser = AWUSER_ENABLE ? write_awuser_reg : {AWUSER_WIDTH{1'b0}};
assign ram_wr_cmd_data = s_axi_wdata;
assign ram_wr_cmd_strb = s_axi_wstrb;
assign ram_wr_cmd_user = WUSER_ENABLE ? s_axi_wuser : {WUSER_WIDTH{1'b0}};
assign ram_wr_cmd_en = write_addr_valid_reg && s_axi_wvalid;
assign ram_wr_cmd_last = write_last_reg;
always @* begin
state_next = STATE_IDLE;
write_id_next = write_id_reg;
write_addr_next = write_addr_reg;
write_lock_next = write_lock_reg;
write_cache_next = write_cache_reg;
write_prot_next = write_prot_reg;
write_qos_next = write_qos_reg;
write_region_next = write_region_reg;
write_awuser_next = write_awuser_reg;
write_addr_valid_next = write_addr_valid_reg;
write_last_next = write_last_reg;
write_count_next = write_count_reg;
write_size_next = write_size_reg;
write_burst_next = write_burst_reg;
s_axi_awready_next = 1'b0;
s_axi_bid_next = s_axi_bid_reg;
s_axi_bvalid_next = s_axi_bvalid_reg && !s_axi_bready;
case (state_reg)
STATE_IDLE: begin
s_axi_awready_next = 1'b1;
if (s_axi_awready && s_axi_awvalid) begin
write_id_next = s_axi_awid;
write_addr_next = s_axi_awaddr;
write_lock_next = s_axi_awlock;
write_cache_next = s_axi_awcache;
write_prot_next = s_axi_awprot;
write_qos_next = s_axi_awqos;
write_region_next = s_axi_awregion;
write_awuser_next = s_axi_awuser;
write_count_next = s_axi_awlen;
write_size_next = s_axi_awsize < $clog2(STRB_WIDTH) ? s_axi_awsize : $clog2(STRB_WIDTH);
write_burst_next = s_axi_awburst;
write_addr_valid_next = 1'b1;
s_axi_awready_next = 1'b0;
if (s_axi_awlen > 0) begin
write_last_next = 1'b0;
end else begin
write_last_next = 1'b1;
end
state_next = STATE_BURST;
end else begin
state_next = STATE_IDLE;
end
end
STATE_BURST: begin
if (s_axi_wready && s_axi_wvalid) begin
if (write_burst_reg != 2'b00) begin
write_addr_next = write_addr_reg + (1 << write_size_reg);
end
write_count_next = write_count_reg - 1;
write_last_next = write_count_next == 0;
if (write_count_reg > 0) begin
write_addr_valid_next = 1'b1;
state_next = STATE_BURST;
end else begin
write_addr_valid_next = 1'b0;
if (s_axi_bready || !s_axi_bvalid) begin
s_axi_bid_next = write_id_reg;
s_axi_bvalid_next = 1'b1;
s_axi_awready_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_RESP;
end
end
end else begin
state_next = STATE_BURST;
end
end
STATE_RESP: begin
if (s_axi_bready || !s_axi_bvalid) begin
s_axi_bid_next = write_id_reg;
s_axi_bvalid_next = 1'b1;
s_axi_awready_next = 1'b1;
state_next = STATE_IDLE;
end else begin
state_next = STATE_RESP;
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
write_addr_valid_reg <= 1'b0;
s_axi_awready_reg <= 1'b0;
s_axi_bvalid_reg <= 1'b0;
end else begin
state_reg <= state_next;
write_addr_valid_reg <= write_addr_valid_next;
s_axi_awready_reg <= s_axi_awready_next;
s_axi_bvalid_reg <= s_axi_bvalid_next;
end
write_id_reg <= write_id_next;
write_addr_reg <= write_addr_next;
write_lock_reg <= write_lock_next;
write_cache_reg <= write_cache_next;
write_prot_reg <= write_prot_next;
write_qos_reg <= write_qos_next;
write_region_reg <= write_region_next;
write_awuser_reg <= write_awuser_next;
write_last_reg <= write_last_next;
write_count_reg <= write_count_next;
write_size_reg <= write_size_next;
write_burst_reg <= write_burst_next;
s_axi_bid_reg <= s_axi_bid_next;
end
endmodule
/*
Copyright (c) 2019 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale 1ns / 1ps
/*
* AXI4 RAM read/write interface
*/
module axi_ram_wr_rd_if #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 16,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Width of ID signal
parameter ID_WIDTH = 8,
// Propagate awuser signal
parameter AWUSER_ENABLE = 0,
// Width of awuser signal
parameter AWUSER_WIDTH = 1,
// Propagate wuser signal
parameter WUSER_ENABLE = 0,
// Width of wuser signal
parameter WUSER_WIDTH = 1,
// Propagate buser signal
parameter BUSER_ENABLE = 0,
// Width of buser signal
parameter BUSER_WIDTH = 1,
// Propagate aruser signal
parameter ARUSER_ENABLE = 0,
// Width of aruser signal
parameter ARUSER_WIDTH = 1,
// Propagate ruser signal
parameter RUSER_ENABLE = 0,
// Width of ruser signal
parameter RUSER_WIDTH = 1,
// Width of auser output
parameter AUSER_WIDTH = (ARUSER_ENABLE && (!AWUSER_ENABLE || ARUSER_WIDTH > AWUSER_WIDTH)) ? ARUSER_WIDTH : AWUSER_WIDTH,
// Extra pipeline register on output
parameter PIPELINE_OUTPUT = 0,
// Interleave read and write burst cycles
parameter INTERLEAVE = 0
)
(
input wire clk,
input wire rst,
/*
* AXI slave interface
*/
input wire [ID_WIDTH-1:0] s_axi_awid,
input wire [ADDR_WIDTH-1:0] s_axi_awaddr,
input wire [7:0] s_axi_awlen,
input wire [2:0] s_axi_awsize,
input wire [1:0] s_axi_awburst,
input wire s_axi_awlock,
input wire [3:0] s_axi_awcache,
input wire [2:0] s_axi_awprot,
input wire [3:0] s_axi_awqos,
input wire [3:0] s_axi_awregion,
input wire [AWUSER_WIDTH-1:0] s_axi_awuser,
input wire s_axi_awvalid,
output wire s_axi_awready,
input wire [DATA_WIDTH-1:0] s_axi_wdata,
input wire [STRB_WIDTH-1:0] s_axi_wstrb,
input wire s_axi_wlast,
input wire [WUSER_WIDTH-1:0] s_axi_wuser,
input wire s_axi_wvalid,
output wire s_axi_wready,
output wire [ID_WIDTH-1:0] s_axi_bid,
output wire [1:0] s_axi_bresp,
output wire [BUSER_WIDTH-1:0] s_axi_buser,
output wire s_axi_bvalid,
input wire s_axi_bready,
input wire [ID_WIDTH-1:0] s_axi_arid,
input wire [ADDR_WIDTH-1:0] s_axi_araddr,
input wire [7:0] s_axi_arlen,
input wire [2:0] s_axi_arsize,
input wire [1:0] s_axi_arburst,
input wire s_axi_arlock,
input wire [3:0] s_axi_arcache,
input wire [2:0] s_axi_arprot,
input wire [3:0] s_axi_arqos,
input wire [3:0] s_axi_arregion,
input wire [ARUSER_WIDTH-1:0] s_axi_aruser,
input wire s_axi_arvalid,
output wire s_axi_arready,
output wire [ID_WIDTH-1:0] s_axi_rid,
output wire [DATA_WIDTH-1:0] s_axi_rdata,
output wire [1:0] s_axi_rresp,
output wire s_axi_rlast,
output wire [RUSER_WIDTH-1:0] s_axi_ruser,
output wire s_axi_rvalid,
input wire s_axi_rready,
/*
* RAM interface
*/
output wire [ID_WIDTH-1:0] ram_cmd_id,
output wire [ADDR_WIDTH-1:0] ram_cmd_addr,
output wire ram_cmd_lock,
output wire [3:0] ram_cmd_cache,
output wire [2:0] ram_cmd_prot,
output wire [3:0] ram_cmd_qos,
output wire [3:0] ram_cmd_region,
output wire [AUSER_WIDTH-1:0] ram_cmd_auser,
output wire [DATA_WIDTH-1:0] ram_cmd_wr_data,
output wire [STRB_WIDTH-1:0] ram_cmd_wr_strb,
output wire [WUSER_WIDTH-1:0] ram_cmd_wr_user,
output wire ram_cmd_wr_en,
output wire ram_cmd_rd_en,
output wire ram_cmd_last,
input wire ram_cmd_ready,
input wire [ID_WIDTH-1:0] ram_rd_resp_id,
input wire [DATA_WIDTH-1:0] ram_rd_resp_data,
input wire ram_rd_resp_last,
input wire [RUSER_WIDTH-1:0] ram_rd_resp_user,
input wire ram_rd_resp_valid,
output wire ram_rd_resp_ready
);
wire [ID_WIDTH-1:0] ram_wr_cmd_id;
wire [ADDR_WIDTH-1:0] ram_wr_cmd_addr;
wire ram_wr_cmd_lock;
wire [3:0] ram_wr_cmd_cache;
wire [2:0] ram_wr_cmd_prot;
wire [3:0] ram_wr_cmd_qos;
wire [3:0] ram_wr_cmd_region;
wire [AWUSER_WIDTH-1:0] ram_wr_cmd_auser;
wire [ID_WIDTH-1:0] ram_rd_cmd_id;
wire [ADDR_WIDTH-1:0] ram_rd_cmd_addr;
wire ram_rd_cmd_lock;
wire [3:0] ram_rd_cmd_cache;
wire [2:0] ram_rd_cmd_prot;
wire [3:0] ram_rd_cmd_qos;
wire [3:0] ram_rd_cmd_region;
wire [AWUSER_WIDTH-1:0] ram_rd_cmd_auser;
axi_ram_wr_if #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.ID_WIDTH(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)
)
axi_ram_wr_if_inst (
.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_awregion(s_axi_awregion),
.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),
.ram_wr_cmd_id(ram_wr_cmd_id),
.ram_wr_cmd_addr(ram_wr_cmd_addr),
.ram_wr_cmd_lock(ram_wr_cmd_lock),
.ram_wr_cmd_cache(ram_wr_cmd_cache),
.ram_wr_cmd_prot(ram_wr_cmd_prot),
.ram_wr_cmd_qos(ram_wr_cmd_qos),
.ram_wr_cmd_region(ram_wr_cmd_region),
.ram_wr_cmd_auser(ram_wr_cmd_auser),
.ram_wr_cmd_data(ram_cmd_wr_data),
.ram_wr_cmd_strb(ram_cmd_wr_strb),
.ram_wr_cmd_user(ram_cmd_wr_user),
.ram_wr_cmd_en(ram_wr_cmd_en),
.ram_wr_cmd_last(ram_wr_cmd_last),
.ram_wr_cmd_ready(ram_wr_cmd_ready)
);
axi_ram_rd_if #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.ID_WIDTH(ID_WIDTH),
.ARUSER_ENABLE(ARUSER_ENABLE),
.ARUSER_WIDTH(ARUSER_WIDTH),
.RUSER_ENABLE(RUSER_ENABLE),
.RUSER_WIDTH(RUSER_WIDTH),
.PIPELINE_OUTPUT(PIPELINE_OUTPUT)
)
axi_ram_rd_if_inst (
.clk(clk),
.rst(rst),
.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_arregion(s_axi_arregion),
.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),
.ram_rd_cmd_id(ram_rd_cmd_id),
.ram_rd_cmd_addr(ram_rd_cmd_addr),
.ram_rd_cmd_lock(ram_rd_cmd_lock),
.ram_rd_cmd_cache(ram_rd_cmd_cache),
.ram_rd_cmd_prot(ram_rd_cmd_prot),
.ram_rd_cmd_qos(ram_rd_cmd_qos),
.ram_rd_cmd_region(ram_rd_cmd_region),
.ram_rd_cmd_auser(ram_rd_cmd_auser),
.ram_rd_cmd_en(ram_rd_cmd_en),
.ram_rd_cmd_last(ram_rd_cmd_last),
.ram_rd_cmd_ready(ram_rd_cmd_ready),
.ram_rd_resp_id(ram_rd_resp_id),
.ram_rd_resp_data(ram_rd_resp_data),
.ram_rd_resp_last(ram_rd_resp_last),
.ram_rd_resp_user(ram_rd_resp_user),
.ram_rd_resp_valid(ram_rd_resp_valid),
.ram_rd_resp_ready(ram_rd_resp_ready)
);
// arbitration
reg read_eligible;
reg write_eligible;
reg write_en;
reg read_en;
reg last_read_reg = 1'b0, last_read_next;
reg transaction_reg = 1'b0, transaction_next;
assign ram_cmd_wr_en = write_en;
assign ram_cmd_rd_en = read_en;
assign ram_cmd_id = ram_cmd_rd_en ? ram_rd_cmd_id : ram_wr_cmd_id;
assign ram_cmd_addr = ram_cmd_rd_en ? ram_rd_cmd_addr : ram_wr_cmd_addr;
assign ram_cmd_lock = ram_cmd_rd_en ? ram_rd_cmd_lock : ram_wr_cmd_lock;
assign ram_cmd_cache = ram_cmd_rd_en ? ram_rd_cmd_cache : ram_wr_cmd_cache;
assign ram_cmd_prot = ram_cmd_rd_en ? ram_rd_cmd_prot : ram_wr_cmd_prot;
assign ram_cmd_qos = ram_cmd_rd_en ? ram_rd_cmd_qos : ram_wr_cmd_qos;
assign ram_cmd_region = ram_cmd_rd_en ? ram_rd_cmd_region : ram_wr_cmd_region;
assign ram_cmd_auser = ram_cmd_rd_en ? ram_rd_cmd_auser : ram_wr_cmd_auser;
assign ram_cmd_last = ram_cmd_rd_en ? ram_rd_cmd_last : ram_wr_cmd_last;
assign ram_wr_cmd_ready = ram_cmd_ready && write_en;
assign ram_rd_cmd_ready = ram_cmd_ready && read_en;
always @* begin
write_en = 1'b0;
read_en = 1'b0;
last_read_next = last_read_reg;
transaction_next = transaction_reg;
write_eligible = ram_wr_cmd_en && ram_cmd_ready;
read_eligible = ram_rd_cmd_en && ram_cmd_ready;
if (write_eligible && (!read_eligible || last_read_reg || (!INTERLEAVE && transaction_reg)) && (INTERLEAVE || !transaction_reg || !last_read_reg)) begin
last_read_next = 1'b0;
transaction_next = !ram_wr_cmd_last;
write_en = 1'b1;
end else if (read_eligible && (INTERLEAVE || !transaction_reg || last_read_reg)) begin
last_read_next = 1'b1;
transaction_next = !ram_rd_cmd_last;
read_en = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
last_read_reg <= 1'b0;
transaction_reg <= 1'b0;
end else begin
last_read_reg <= last_read_next;
transaction_reg <= transaction_next;
end
end
endmodule
/*
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 register
*/
module axi_register #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Width of ID signal
parameter ID_WIDTH = 8,
// Propagate awuser signal
parameter AWUSER_ENABLE = 0,
// Width of awuser signal
parameter AWUSER_WIDTH = 1,
// Propagate wuser signal
parameter WUSER_ENABLE = 0,
// Width of wuser signal
parameter WUSER_WIDTH = 1,
// Propagate buser signal
parameter BUSER_ENABLE = 0,
// Width of buser signal
parameter BUSER_WIDTH = 1,
// Propagate aruser signal
parameter ARUSER_ENABLE = 0,
// Width of aruser signal
parameter ARUSER_WIDTH = 1,
// Propagate ruser signal
parameter RUSER_ENABLE = 0,
// Width of ruser signal
parameter RUSER_WIDTH = 1,
// AW channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter AW_REG_TYPE = 1,
// W channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter W_REG_TYPE = 2,
// B channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter B_REG_TYPE = 1,
// AR channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter AR_REG_TYPE = 1,
// R channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter R_REG_TYPE = 2
)
(
input wire clk,
input wire rst,
/*
* AXI slave interface
*/
input wire [ID_WIDTH-1:0] s_axi_awid,
input wire [ADDR_WIDTH-1:0] s_axi_awaddr,
input wire [7:0] s_axi_awlen,
input wire [2:0] s_axi_awsize,
input wire [1:0] s_axi_awburst,
input wire s_axi_awlock,
input wire [3:0] s_axi_awcache,
input wire [2:0] s_axi_awprot,
input wire [3:0] s_axi_awqos,
input wire [3:0] s_axi_awregion,
input wire [AWUSER_WIDTH-1:0] s_axi_awuser,
input wire s_axi_awvalid,
output wire s_axi_awready,
input wire [DATA_WIDTH-1:0] s_axi_wdata,
input wire [STRB_WIDTH-1:0] s_axi_wstrb,
input wire s_axi_wlast,
input wire [WUSER_WIDTH-1:0] s_axi_wuser,
input wire s_axi_wvalid,
output wire s_axi_wready,
output wire [ID_WIDTH-1:0] s_axi_bid,
output wire [1:0] s_axi_bresp,
output wire [BUSER_WIDTH-1:0] s_axi_buser,
output wire s_axi_bvalid,
input wire s_axi_bready,
input wire [ID_WIDTH-1:0] s_axi_arid,
input wire [ADDR_WIDTH-1:0] s_axi_araddr,
input wire [7:0] s_axi_arlen,
input wire [2:0] s_axi_arsize,
input wire [1:0] s_axi_arburst,
input wire s_axi_arlock,
input wire [3:0] s_axi_arcache,
input wire [2:0] s_axi_arprot,
input wire [3:0] s_axi_arqos,
input wire [3:0] s_axi_arregion,
input wire [ARUSER_WIDTH-1:0] s_axi_aruser,
input wire s_axi_arvalid,
output wire s_axi_arready,
output wire [ID_WIDTH-1:0] s_axi_rid,
output wire [DATA_WIDTH-1:0] s_axi_rdata,
output wire [1:0] s_axi_rresp,
output wire s_axi_rlast,
output wire [RUSER_WIDTH-1:0] s_axi_ruser,
output wire s_axi_rvalid,
input wire s_axi_rready,
/*
* AXI master interface
*/
output wire [ID_WIDTH-1:0] m_axi_awid,
output wire [ADDR_WIDTH-1:0] m_axi_awaddr,
output wire [7:0] m_axi_awlen,
output wire [2:0] m_axi_awsize,
output wire [1:0] m_axi_awburst,
output wire m_axi_awlock,
output wire [3:0] m_axi_awcache,
output wire [2:0] m_axi_awprot,
output wire [3:0] m_axi_awqos,
output wire [3:0] m_axi_awregion,
output wire [AWUSER_WIDTH-1:0] m_axi_awuser,
output wire m_axi_awvalid,
input wire m_axi_awready,
output wire [DATA_WIDTH-1:0] m_axi_wdata,
output wire [STRB_WIDTH-1:0] m_axi_wstrb,
output wire m_axi_wlast,
output wire [WUSER_WIDTH-1:0] m_axi_wuser,
output wire m_axi_wvalid,
input wire m_axi_wready,
input wire [ID_WIDTH-1:0] m_axi_bid,
input wire [1:0] m_axi_bresp,
input wire [BUSER_WIDTH-1:0] m_axi_buser,
input wire m_axi_bvalid,
output wire m_axi_bready,
output wire [ID_WIDTH-1:0] m_axi_arid,
output wire [ADDR_WIDTH-1:0] m_axi_araddr,
output wire [7:0] m_axi_arlen,
output wire [2:0] m_axi_arsize,
output wire [1:0] m_axi_arburst,
output wire m_axi_arlock,
output wire [3:0] m_axi_arcache,
output wire [2:0] m_axi_arprot,
output wire [3:0] m_axi_arqos,
output wire [3:0] m_axi_arregion,
output wire [ARUSER_WIDTH-1:0] m_axi_aruser,
output wire m_axi_arvalid,
input wire m_axi_arready,
input wire [ID_WIDTH-1:0] m_axi_rid,
input wire [DATA_WIDTH-1:0] m_axi_rdata,
input wire [1:0] m_axi_rresp,
input wire m_axi_rlast,
input wire [RUSER_WIDTH-1:0] m_axi_ruser,
input wire m_axi_rvalid,
output wire m_axi_rready
);
axi_register_wr #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.ID_WIDTH(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(AW_REG_TYPE),
.W_REG_TYPE(W_REG_TYPE),
.B_REG_TYPE(B_REG_TYPE)
)
axi_register_wr_inst (
.clk(clk),
.rst(rst),
/*
* AXI slave interface
*/
.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_awregion(s_axi_awregion),
.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 interface
*/
.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_register_rd #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH),
.STRB_WIDTH(STRB_WIDTH),
.ID_WIDTH(ID_WIDTH),
.ARUSER_ENABLE(ARUSER_ENABLE),
.ARUSER_WIDTH(ARUSER_WIDTH),
.RUSER_ENABLE(RUSER_ENABLE),
.RUSER_WIDTH(RUSER_WIDTH),
.AR_REG_TYPE(AR_REG_TYPE),
.R_REG_TYPE(R_REG_TYPE)
)
axi_register_rd_inst (
.clk(clk),
.rst(rst),
/*
* AXI slave interface
*/
.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_arregion(s_axi_arregion),
.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 interface
*/
.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
/*
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 register (read)
*/
module axi_register_rd #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Width of ID signal
parameter ID_WIDTH = 8,
// Propagate aruser signal
parameter ARUSER_ENABLE = 0,
// Width of aruser signal
parameter ARUSER_WIDTH = 1,
// Propagate ruser signal
parameter RUSER_ENABLE = 0,
// Width of ruser signal
parameter RUSER_WIDTH = 1,
// AR channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter AR_REG_TYPE = 1,
// R channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter R_REG_TYPE = 2
)
(
input wire clk,
input wire rst,
/*
* AXI slave interface
*/
input wire [ID_WIDTH-1:0] s_axi_arid,
input wire [ADDR_WIDTH-1:0] s_axi_araddr,
input wire [7:0] s_axi_arlen,
input wire [2:0] s_axi_arsize,
input wire [1:0] s_axi_arburst,
input wire s_axi_arlock,
input wire [3:0] s_axi_arcache,
input wire [2:0] s_axi_arprot,
input wire [3:0] s_axi_arqos,
input wire [3:0] s_axi_arregion,
input wire [ARUSER_WIDTH-1:0] s_axi_aruser,
input wire s_axi_arvalid,
output wire s_axi_arready,
output wire [ID_WIDTH-1:0] s_axi_rid,
output wire [DATA_WIDTH-1:0] s_axi_rdata,
output wire [1:0] s_axi_rresp,
output wire s_axi_rlast,
output wire [RUSER_WIDTH-1:0] s_axi_ruser,
output wire s_axi_rvalid,
input wire s_axi_rready,
/*
* AXI master interface
*/
output wire [ID_WIDTH-1:0] m_axi_arid,
output wire [ADDR_WIDTH-1:0] m_axi_araddr,
output wire [7:0] m_axi_arlen,
output wire [2:0] m_axi_arsize,
output wire [1:0] m_axi_arburst,
output wire m_axi_arlock,
output wire [3:0] m_axi_arcache,
output wire [2:0] m_axi_arprot,
output wire [3:0] m_axi_arqos,
output wire [3:0] m_axi_arregion,
output wire [ARUSER_WIDTH-1:0] m_axi_aruser,
output wire m_axi_arvalid,
input wire m_axi_arready,
input wire [ID_WIDTH-1:0] m_axi_rid,
input wire [DATA_WIDTH-1:0] m_axi_rdata,
input wire [1:0] m_axi_rresp,
input wire m_axi_rlast,
input wire [RUSER_WIDTH-1:0] m_axi_ruser,
input wire m_axi_rvalid,
output wire m_axi_rready
);
generate
// AR channel
if (AR_REG_TYPE > 1) begin
// skid buffer, no bubble cycles
// datapath registers
reg s_axi_arready_reg = 1'b0;
reg [ID_WIDTH-1:0] m_axi_arid_reg = {ID_WIDTH{1'b0}};
reg [ADDR_WIDTH-1:0] m_axi_araddr_reg = {ADDR_WIDTH{1'b0}};
reg [7:0] m_axi_arlen_reg = 8'd0;
reg [2:0] m_axi_arsize_reg = 3'd0;
reg [1:0] m_axi_arburst_reg = 2'd0;
reg m_axi_arlock_reg = 1'b0;
reg [3:0] m_axi_arcache_reg = 4'd0;
reg [2:0] m_axi_arprot_reg = 3'd0;
reg [3:0] m_axi_arqos_reg = 4'd0;
reg [3:0] m_axi_arregion_reg = 4'd0;
reg [ARUSER_WIDTH-1:0] m_axi_aruser_reg = {ARUSER_WIDTH{1'b0}};
reg m_axi_arvalid_reg = 1'b0, m_axi_arvalid_next;
reg [ID_WIDTH-1:0] temp_m_axi_arid_reg = {ID_WIDTH{1'b0}};
reg [ADDR_WIDTH-1:0] temp_m_axi_araddr_reg = {ADDR_WIDTH{1'b0}};
reg [7:0] temp_m_axi_arlen_reg = 8'd0;
reg [2:0] temp_m_axi_arsize_reg = 3'd0;
reg [1:0] temp_m_axi_arburst_reg = 2'd0;
reg temp_m_axi_arlock_reg = 1'b0;
reg [3:0] temp_m_axi_arcache_reg = 4'd0;
reg [2:0] temp_m_axi_arprot_reg = 3'd0;
reg [3:0] temp_m_axi_arqos_reg = 4'd0;
reg [3:0] temp_m_axi_arregion_reg = 4'd0;
reg [ARUSER_WIDTH-1:0] temp_m_axi_aruser_reg = {ARUSER_WIDTH{1'b0}};
reg temp_m_axi_arvalid_reg = 1'b0, temp_m_axi_arvalid_next;
// datapath control
reg store_axi_ar_input_to_output;
reg store_axi_ar_input_to_temp;
reg store_axi_ar_temp_to_output;
assign s_axi_arready = s_axi_arready_reg;
assign m_axi_arid = m_axi_arid_reg;
assign m_axi_araddr = m_axi_araddr_reg;
assign m_axi_arlen = m_axi_arlen_reg;
assign m_axi_arsize = m_axi_arsize_reg;
assign m_axi_arburst = m_axi_arburst_reg;
assign m_axi_arlock = m_axi_arlock_reg;
assign m_axi_arcache = m_axi_arcache_reg;
assign m_axi_arprot = m_axi_arprot_reg;
assign m_axi_arqos = m_axi_arqos_reg;
assign m_axi_arregion = m_axi_arregion_reg;
assign m_axi_aruser = ARUSER_ENABLE ? m_axi_aruser_reg : {ARUSER_WIDTH{1'b0}};
assign m_axi_arvalid = m_axi_arvalid_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
wire s_axi_arready_early = m_axi_arready | (~temp_m_axi_arvalid_reg & (~m_axi_arvalid_reg | ~s_axi_arvalid));
always @* begin
// transfer sink ready state to source
m_axi_arvalid_next = m_axi_arvalid_reg;
temp_m_axi_arvalid_next = temp_m_axi_arvalid_reg;
store_axi_ar_input_to_output = 1'b0;
store_axi_ar_input_to_temp = 1'b0;
store_axi_ar_temp_to_output = 1'b0;
if (s_axi_arready_reg) begin
// input is ready
if (m_axi_arready | ~m_axi_arvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axi_arvalid_next = s_axi_arvalid;
store_axi_ar_input_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axi_arvalid_next = s_axi_arvalid;
store_axi_ar_input_to_temp = 1'b1;
end
end else if (m_axi_arready) begin
// input is not ready, but output is ready
m_axi_arvalid_next = temp_m_axi_arvalid_reg;
temp_m_axi_arvalid_next = 1'b0;
store_axi_ar_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
s_axi_arready_reg <= 1'b0;
m_axi_arvalid_reg <= 1'b0;
temp_m_axi_arvalid_reg <= 1'b0;
end else begin
s_axi_arready_reg <= s_axi_arready_early;
m_axi_arvalid_reg <= m_axi_arvalid_next;
temp_m_axi_arvalid_reg <= temp_m_axi_arvalid_next;
end
// datapath
if (store_axi_ar_input_to_output) begin
m_axi_arid_reg <= s_axi_arid;
m_axi_araddr_reg <= s_axi_araddr;
m_axi_arlen_reg <= s_axi_arlen;
m_axi_arsize_reg <= s_axi_arsize;
m_axi_arburst_reg <= s_axi_arburst;
m_axi_arlock_reg <= s_axi_arlock;
m_axi_arcache_reg <= s_axi_arcache;
m_axi_arprot_reg <= s_axi_arprot;
m_axi_arqos_reg <= s_axi_arqos;
m_axi_arregion_reg <= s_axi_arregion;
m_axi_aruser_reg <= s_axi_aruser;
end else if (store_axi_ar_temp_to_output) begin
m_axi_arid_reg <= temp_m_axi_arid_reg;
m_axi_araddr_reg <= temp_m_axi_araddr_reg;
m_axi_arlen_reg <= temp_m_axi_arlen_reg;
m_axi_arsize_reg <= temp_m_axi_arsize_reg;
m_axi_arburst_reg <= temp_m_axi_arburst_reg;
m_axi_arlock_reg <= temp_m_axi_arlock_reg;
m_axi_arcache_reg <= temp_m_axi_arcache_reg;
m_axi_arprot_reg <= temp_m_axi_arprot_reg;
m_axi_arqos_reg <= temp_m_axi_arqos_reg;
m_axi_arregion_reg <= temp_m_axi_arregion_reg;
m_axi_aruser_reg <= temp_m_axi_aruser_reg;
end
if (store_axi_ar_input_to_temp) begin
temp_m_axi_arid_reg <= s_axi_arid;
temp_m_axi_araddr_reg <= s_axi_araddr;
temp_m_axi_arlen_reg <= s_axi_arlen;
temp_m_axi_arsize_reg <= s_axi_arsize;
temp_m_axi_arburst_reg <= s_axi_arburst;
temp_m_axi_arlock_reg <= s_axi_arlock;
temp_m_axi_arcache_reg <= s_axi_arcache;
temp_m_axi_arprot_reg <= s_axi_arprot;
temp_m_axi_arqos_reg <= s_axi_arqos;
temp_m_axi_arregion_reg <= s_axi_arregion;
temp_m_axi_aruser_reg <= s_axi_aruser;
end
end
end else if (AR_REG_TYPE == 1) begin
// simple register, inserts bubble cycles
// datapath registers
reg s_axi_arready_reg = 1'b0;
reg [ID_WIDTH-1:0] m_axi_arid_reg = {ID_WIDTH{1'b0}};
reg [ADDR_WIDTH-1:0] m_axi_araddr_reg = {ADDR_WIDTH{1'b0}};
reg [7:0] m_axi_arlen_reg = 8'd0;
reg [2:0] m_axi_arsize_reg = 3'd0;
reg [1:0] m_axi_arburst_reg = 2'd0;
reg m_axi_arlock_reg = 1'b0;
reg [3:0] m_axi_arcache_reg = 4'd0;
reg [2:0] m_axi_arprot_reg = 3'd0;
reg [3:0] m_axi_arqos_reg = 4'd0;
reg [3:0] m_axi_arregion_reg = 4'd0;
reg [ARUSER_WIDTH-1:0] m_axi_aruser_reg = {ARUSER_WIDTH{1'b0}};
reg m_axi_arvalid_reg = 1'b0, m_axi_arvalid_next;
// datapath control
reg store_axi_ar_input_to_output;
assign s_axi_arready = s_axi_arready_reg;
assign m_axi_arid = m_axi_arid_reg;
assign m_axi_araddr = m_axi_araddr_reg;
assign m_axi_arlen = m_axi_arlen_reg;
assign m_axi_arsize = m_axi_arsize_reg;
assign m_axi_arburst = m_axi_arburst_reg;
assign m_axi_arlock = m_axi_arlock_reg;
assign m_axi_arcache = m_axi_arcache_reg;
assign m_axi_arprot = m_axi_arprot_reg;
assign m_axi_arqos = m_axi_arqos_reg;
assign m_axi_arregion = m_axi_arregion_reg;
assign m_axi_aruser = ARUSER_ENABLE ? m_axi_aruser_reg : {ARUSER_WIDTH{1'b0}};
assign m_axi_arvalid = m_axi_arvalid_reg;
// enable ready input next cycle if output buffer will be empty
wire s_axi_arready_early = !m_axi_arvalid_next;
always @* begin
// transfer sink ready state to source
m_axi_arvalid_next = m_axi_arvalid_reg;
store_axi_ar_input_to_output = 1'b0;
if (s_axi_arready_reg) begin
m_axi_arvalid_next = s_axi_arvalid;
store_axi_ar_input_to_output = 1'b1;
end else if (m_axi_arready) begin
m_axi_arvalid_next = 1'b0;
end
end
always @(posedge clk) begin
if (rst) begin
s_axi_arready_reg <= 1'b0;
m_axi_arvalid_reg <= 1'b0;
end else begin
s_axi_arready_reg <= s_axi_arready_early;
m_axi_arvalid_reg <= m_axi_arvalid_next;
end
// datapath
if (store_axi_ar_input_to_output) begin
m_axi_arid_reg <= s_axi_arid;
m_axi_araddr_reg <= s_axi_araddr;
m_axi_arlen_reg <= s_axi_arlen;
m_axi_arsize_reg <= s_axi_arsize;
m_axi_arburst_reg <= s_axi_arburst;
m_axi_arlock_reg <= s_axi_arlock;
m_axi_arcache_reg <= s_axi_arcache;
m_axi_arprot_reg <= s_axi_arprot;
m_axi_arqos_reg <= s_axi_arqos;
m_axi_arregion_reg <= s_axi_arregion;
m_axi_aruser_reg <= s_axi_aruser;
end
end
end else begin
// bypass AR channel
assign m_axi_arid = s_axi_arid;
assign m_axi_araddr = s_axi_araddr;
assign m_axi_arlen = s_axi_arlen;
assign m_axi_arsize = s_axi_arsize;
assign m_axi_arburst = s_axi_arburst;
assign m_axi_arlock = s_axi_arlock;
assign m_axi_arcache = s_axi_arcache;
assign m_axi_arprot = s_axi_arprot;
assign m_axi_arqos = s_axi_arqos;
assign m_axi_arregion = s_axi_arregion;
assign m_axi_aruser = ARUSER_ENABLE ? s_axi_aruser : {ARUSER_WIDTH{1'b0}};
assign m_axi_arvalid = s_axi_arvalid;
assign s_axi_arready = m_axi_arready;
end
// R channel
if (R_REG_TYPE > 1) begin
// skid buffer, no bubble cycles
// datapath registers
reg m_axi_rready_reg = 1'b0;
reg [ID_WIDTH-1:0] s_axi_rid_reg = {ID_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] s_axi_rdata_reg = {DATA_WIDTH{1'b0}};
reg [1:0] s_axi_rresp_reg = 2'b0;
reg s_axi_rlast_reg = 1'b0;
reg [RUSER_WIDTH-1:0] s_axi_ruser_reg = {RUSER_WIDTH{1'b0}};
reg s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next;
reg [ID_WIDTH-1:0] temp_s_axi_rid_reg = {ID_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] temp_s_axi_rdata_reg = {DATA_WIDTH{1'b0}};
reg [1:0] temp_s_axi_rresp_reg = 2'b0;
reg temp_s_axi_rlast_reg = 1'b0;
reg [RUSER_WIDTH-1:0] temp_s_axi_ruser_reg = {RUSER_WIDTH{1'b0}};
reg temp_s_axi_rvalid_reg = 1'b0, temp_s_axi_rvalid_next;
// datapath control
reg store_axi_r_input_to_output;
reg store_axi_r_input_to_temp;
reg store_axi_r_temp_to_output;
assign m_axi_rready = m_axi_rready_reg;
assign s_axi_rid = s_axi_rid_reg;
assign s_axi_rdata = s_axi_rdata_reg;
assign s_axi_rresp = s_axi_rresp_reg;
assign s_axi_rlast = s_axi_rlast_reg;
assign s_axi_ruser = RUSER_ENABLE ? s_axi_ruser_reg : {RUSER_WIDTH{1'b0}};
assign s_axi_rvalid = s_axi_rvalid_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
wire m_axi_rready_early = s_axi_rready | (~temp_s_axi_rvalid_reg & (~s_axi_rvalid_reg | ~m_axi_rvalid));
always @* begin
// transfer sink ready state to source
s_axi_rvalid_next = s_axi_rvalid_reg;
temp_s_axi_rvalid_next = temp_s_axi_rvalid_reg;
store_axi_r_input_to_output = 1'b0;
store_axi_r_input_to_temp = 1'b0;
store_axi_r_temp_to_output = 1'b0;
if (m_axi_rready_reg) begin
// input is ready
if (s_axi_rready | ~s_axi_rvalid_reg) begin
// output is ready or currently not valid, transfer data to output
s_axi_rvalid_next = m_axi_rvalid;
store_axi_r_input_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_s_axi_rvalid_next = m_axi_rvalid;
store_axi_r_input_to_temp = 1'b1;
end
end else if (s_axi_rready) begin
// input is not ready, but output is ready
s_axi_rvalid_next = temp_s_axi_rvalid_reg;
temp_s_axi_rvalid_next = 1'b0;
store_axi_r_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_axi_rready_reg <= 1'b0;
s_axi_rvalid_reg <= 1'b0;
temp_s_axi_rvalid_reg <= 1'b0;
end else begin
m_axi_rready_reg <= m_axi_rready_early;
s_axi_rvalid_reg <= s_axi_rvalid_next;
temp_s_axi_rvalid_reg <= temp_s_axi_rvalid_next;
end
// datapath
if (store_axi_r_input_to_output) begin
s_axi_rid_reg <= m_axi_rid;
s_axi_rdata_reg <= m_axi_rdata;
s_axi_rresp_reg <= m_axi_rresp;
s_axi_rlast_reg <= m_axi_rlast;
s_axi_ruser_reg <= m_axi_ruser;
end else if (store_axi_r_temp_to_output) begin
s_axi_rid_reg <= temp_s_axi_rid_reg;
s_axi_rdata_reg <= temp_s_axi_rdata_reg;
s_axi_rresp_reg <= temp_s_axi_rresp_reg;
s_axi_rlast_reg <= temp_s_axi_rlast_reg;
s_axi_ruser_reg <= temp_s_axi_ruser_reg;
end
if (store_axi_r_input_to_temp) begin
temp_s_axi_rid_reg <= m_axi_rid;
temp_s_axi_rdata_reg <= m_axi_rdata;
temp_s_axi_rresp_reg <= m_axi_rresp;
temp_s_axi_rlast_reg <= m_axi_rlast;
temp_s_axi_ruser_reg <= m_axi_ruser;
end
end
end else if (R_REG_TYPE == 1) begin
// simple register, inserts bubble cycles
// datapath registers
reg m_axi_rready_reg = 1'b0;
reg [ID_WIDTH-1:0] s_axi_rid_reg = {ID_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] s_axi_rdata_reg = {DATA_WIDTH{1'b0}};
reg [1:0] s_axi_rresp_reg = 2'b0;
reg s_axi_rlast_reg = 1'b0;
reg [RUSER_WIDTH-1:0] s_axi_ruser_reg = {RUSER_WIDTH{1'b0}};
reg s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next;
// datapath control
reg store_axi_r_input_to_output;
assign m_axi_rready = m_axi_rready_reg;
assign s_axi_rid = s_axi_rid_reg;
assign s_axi_rdata = s_axi_rdata_reg;
assign s_axi_rresp = s_axi_rresp_reg;
assign s_axi_rlast = s_axi_rlast_reg;
assign s_axi_ruser = RUSER_ENABLE ? s_axi_ruser_reg : {RUSER_WIDTH{1'b0}};
assign s_axi_rvalid = s_axi_rvalid_reg;
// enable ready input next cycle if output buffer will be empty
wire m_axi_rready_early = !s_axi_rvalid_next;
always @* begin
// transfer sink ready state to source
s_axi_rvalid_next = s_axi_rvalid_reg;
store_axi_r_input_to_output = 1'b0;
if (m_axi_rready_reg) begin
s_axi_rvalid_next = m_axi_rvalid;
store_axi_r_input_to_output = 1'b1;
end else if (s_axi_rready) begin
s_axi_rvalid_next = 1'b0;
end
end
always @(posedge clk) begin
if (rst) begin
m_axi_rready_reg <= 1'b0;
s_axi_rvalid_reg <= 1'b0;
end else begin
m_axi_rready_reg <= m_axi_rready_early;
s_axi_rvalid_reg <= s_axi_rvalid_next;
end
// datapath
if (store_axi_r_input_to_output) begin
s_axi_rid_reg <= m_axi_rid;
s_axi_rdata_reg <= m_axi_rdata;
s_axi_rresp_reg <= m_axi_rresp;
s_axi_rlast_reg <= m_axi_rlast;
s_axi_ruser_reg <= m_axi_ruser;
end
end
end else begin
// bypass R channel
assign s_axi_rid = m_axi_rid;
assign s_axi_rdata = m_axi_rdata;
assign s_axi_rresp = m_axi_rresp;
assign s_axi_rlast = m_axi_rlast;
assign s_axi_ruser = RUSER_ENABLE ? m_axi_ruser : {RUSER_WIDTH{1'b0}};
assign s_axi_rvalid = m_axi_rvalid;
assign m_axi_rready = s_axi_rready;
end
endgenerate
endmodule
/*
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 register (write)
*/
module axi_register_wr #
(
// Width of data bus in bits
parameter DATA_WIDTH = 32,
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of wstrb (width of data bus in words)
parameter STRB_WIDTH = (DATA_WIDTH/8),
// Width of ID signal
parameter ID_WIDTH = 8,
// Propagate awuser signal
parameter AWUSER_ENABLE = 0,
// Width of awuser signal
parameter AWUSER_WIDTH = 1,
// Propagate wuser signal
parameter WUSER_ENABLE = 0,
// Width of wuser signal
parameter WUSER_WIDTH = 1,
// Propagate buser signal
parameter BUSER_ENABLE = 0,
// Width of buser signal
parameter BUSER_WIDTH = 1,
// AW channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter AW_REG_TYPE = 1,
// W channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter W_REG_TYPE = 2,
// B channel register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter B_REG_TYPE = 1
)
(
input wire clk,
input wire rst,
/*
* AXI slave interface
*/
input wire [ID_WIDTH-1:0] s_axi_awid,
input wire [ADDR_WIDTH-1:0] s_axi_awaddr,
input wire [7:0] s_axi_awlen,
input wire [2:0] s_axi_awsize,
input wire [1:0] s_axi_awburst,
input wire s_axi_awlock,
input wire [3:0] s_axi_awcache,
input wire [2:0] s_axi_awprot,
input wire [3:0] s_axi_awqos,
input wire [3:0] s_axi_awregion,
input wire [AWUSER_WIDTH-1:0] s_axi_awuser,
input wire s_axi_awvalid,
output wire s_axi_awready,
input wire [DATA_WIDTH-1:0] s_axi_wdata,
input wire [STRB_WIDTH-1:0] s_axi_wstrb,
input wire s_axi_wlast,
input wire [WUSER_WIDTH-1:0] s_axi_wuser,
input wire s_axi_wvalid,
output wire s_axi_wready,
output wire [ID_WIDTH-1:0] s_axi_bid,
output wire [1:0] s_axi_bresp,
output wire [BUSER_WIDTH-1:0] s_axi_buser,
output wire s_axi_bvalid,
input wire s_axi_bready,
/*
* AXI master interface
*/
output wire [ID_WIDTH-1:0] m_axi_awid,
output wire [ADDR_WIDTH-1:0] m_axi_awaddr,
output wire [7:0] m_axi_awlen,
output wire [2:0] m_axi_awsize,
output wire [1:0] m_axi_awburst,
output wire m_axi_awlock,
output wire [3:0] m_axi_awcache,
output wire [2:0] m_axi_awprot,
output wire [3:0] m_axi_awqos,
output wire [3:0] m_axi_awregion,
output wire [AWUSER_WIDTH-1:0] m_axi_awuser,
output wire m_axi_awvalid,
input wire m_axi_awready,
output wire [DATA_WIDTH-1:0] m_axi_wdata,
output wire [STRB_WIDTH-1:0] m_axi_wstrb,
output wire m_axi_wlast,
output wire [WUSER_WIDTH-1:0] m_axi_wuser,
output wire m_axi_wvalid,
input wire m_axi_wready,
input wire [ID_WIDTH-1:0] m_axi_bid,
input wire [1:0] m_axi_bresp,
input wire [BUSER_WIDTH-1:0] m_axi_buser,
input wire m_axi_bvalid,
output wire m_axi_bready
);
generate
// AW channel
if (AW_REG_TYPE > 1) begin
// skid buffer, no bubble cycles
// datapath registers
reg s_axi_awready_reg = 1'b0;
reg [ID_WIDTH-1:0] m_axi_awid_reg = {ID_WIDTH{1'b0}};
reg [ADDR_WIDTH-1:0] m_axi_awaddr_reg = {ADDR_WIDTH{1'b0}};
reg [7:0] m_axi_awlen_reg = 8'd0;
reg [2:0] m_axi_awsize_reg = 3'd0;
reg [1:0] m_axi_awburst_reg = 2'd0;
reg m_axi_awlock_reg = 1'b0;
reg [3:0] m_axi_awcache_reg = 4'd0;
reg [2:0] m_axi_awprot_reg = 3'd0;
reg [3:0] m_axi_awqos_reg = 4'd0;
reg [3:0] m_axi_awregion_reg = 4'd0;
reg [AWUSER_WIDTH-1:0] m_axi_awuser_reg = {AWUSER_WIDTH{1'b0}};
reg m_axi_awvalid_reg = 1'b0, m_axi_awvalid_next;
reg [ID_WIDTH-1:0] temp_m_axi_awid_reg = {ID_WIDTH{1'b0}};
reg [ADDR_WIDTH-1:0] temp_m_axi_awaddr_reg = {ADDR_WIDTH{1'b0}};
reg [7:0] temp_m_axi_awlen_reg = 8'd0;
reg [2:0] temp_m_axi_awsize_reg = 3'd0;
reg [1:0] temp_m_axi_awburst_reg = 2'd0;
reg temp_m_axi_awlock_reg = 1'b0;
reg [3:0] temp_m_axi_awcache_reg = 4'd0;
reg [2:0] temp_m_axi_awprot_reg = 3'd0;
reg [3:0] temp_m_axi_awqos_reg = 4'd0;
reg [3:0] temp_m_axi_awregion_reg = 4'd0;
reg [AWUSER_WIDTH-1:0] temp_m_axi_awuser_reg = {AWUSER_WIDTH{1'b0}};
reg temp_m_axi_awvalid_reg = 1'b0, temp_m_axi_awvalid_next;
// datapath control
reg store_axi_aw_input_to_output;
reg store_axi_aw_input_to_temp;
reg store_axi_aw_temp_to_output;
assign s_axi_awready = s_axi_awready_reg;
assign m_axi_awid = m_axi_awid_reg;
assign m_axi_awaddr = m_axi_awaddr_reg;
assign m_axi_awlen = m_axi_awlen_reg;
assign m_axi_awsize = m_axi_awsize_reg;
assign m_axi_awburst = m_axi_awburst_reg;
assign m_axi_awlock = m_axi_awlock_reg;
assign m_axi_awcache = m_axi_awcache_reg;
assign m_axi_awprot = m_axi_awprot_reg;
assign m_axi_awqos = m_axi_awqos_reg;
assign m_axi_awregion = m_axi_awregion_reg;
assign m_axi_awuser = AWUSER_ENABLE ? m_axi_awuser_reg : {AWUSER_WIDTH{1'b0}};
assign m_axi_awvalid = m_axi_awvalid_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
wire s_axi_awready_early = m_axi_awready | (~temp_m_axi_awvalid_reg & (~m_axi_awvalid_reg | ~s_axi_awvalid));
always @* begin
// transfer sink ready state to source
m_axi_awvalid_next = m_axi_awvalid_reg;
temp_m_axi_awvalid_next = temp_m_axi_awvalid_reg;
store_axi_aw_input_to_output = 1'b0;
store_axi_aw_input_to_temp = 1'b0;
store_axi_aw_temp_to_output = 1'b0;
if (s_axi_awready_reg) begin
// input is ready
if (m_axi_awready | ~m_axi_awvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axi_awvalid_next = s_axi_awvalid;
store_axi_aw_input_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axi_awvalid_next = s_axi_awvalid;
store_axi_aw_input_to_temp = 1'b1;
end
end else if (m_axi_awready) begin
// input is not ready, but output is ready
m_axi_awvalid_next = temp_m_axi_awvalid_reg;
temp_m_axi_awvalid_next = 1'b0;
store_axi_aw_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
s_axi_awready_reg <= 1'b0;
m_axi_awvalid_reg <= 1'b0;
temp_m_axi_awvalid_reg <= 1'b0;
end else begin
s_axi_awready_reg <= s_axi_awready_early;
m_axi_awvalid_reg <= m_axi_awvalid_next;
temp_m_axi_awvalid_reg <= temp_m_axi_awvalid_next;
end
// datapath
if (store_axi_aw_input_to_output) begin
m_axi_awid_reg <= s_axi_awid;
m_axi_awaddr_reg <= s_axi_awaddr;
m_axi_awlen_reg <= s_axi_awlen;
m_axi_awsize_reg <= s_axi_awsize;
m_axi_awburst_reg <= s_axi_awburst;
m_axi_awlock_reg <= s_axi_awlock;
m_axi_awcache_reg <= s_axi_awcache;
m_axi_awprot_reg <= s_axi_awprot;
m_axi_awqos_reg <= s_axi_awqos;
m_axi_awregion_reg <= s_axi_awregion;
m_axi_awuser_reg <= s_axi_awuser;
end else if (store_axi_aw_temp_to_output) begin
m_axi_awid_reg <= temp_m_axi_awid_reg;
m_axi_awaddr_reg <= temp_m_axi_awaddr_reg;
m_axi_awlen_reg <= temp_m_axi_awlen_reg;
m_axi_awsize_reg <= temp_m_axi_awsize_reg;
m_axi_awburst_reg <= temp_m_axi_awburst_reg;
m_axi_awlock_reg <= temp_m_axi_awlock_reg;
m_axi_awcache_reg <= temp_m_axi_awcache_reg;
m_axi_awprot_reg <= temp_m_axi_awprot_reg;
m_axi_awqos_reg <= temp_m_axi_awqos_reg;
m_axi_awregion_reg <= temp_m_axi_awregion_reg;
m_axi_awuser_reg <= temp_m_axi_awuser_reg;
end
if (store_axi_aw_input_to_temp) begin
temp_m_axi_awid_reg <= s_axi_awid;
temp_m_axi_awaddr_reg <= s_axi_awaddr;
temp_m_axi_awlen_reg <= s_axi_awlen;
temp_m_axi_awsize_reg <= s_axi_awsize;
temp_m_axi_awburst_reg <= s_axi_awburst;
temp_m_axi_awlock_reg <= s_axi_awlock;
temp_m_axi_awcache_reg <= s_axi_awcache;
temp_m_axi_awprot_reg <= s_axi_awprot;
temp_m_axi_awqos_reg <= s_axi_awqos;
temp_m_axi_awregion_reg <= s_axi_awregion;
temp_m_axi_awuser_reg <= s_axi_awuser;
end
end
end else if (AW_REG_TYPE == 1) begin
// simple register, inserts bubble cycles
// datapath registers
reg s_axi_awready_reg = 1'b0;
reg [ID_WIDTH-1:0] m_axi_awid_reg = {ID_WIDTH{1'b0}};
reg [ADDR_WIDTH-1:0] m_axi_awaddr_reg = {ADDR_WIDTH{1'b0}};
reg [7:0] m_axi_awlen_reg = 8'd0;
reg [2:0] m_axi_awsize_reg = 3'd0;
reg [1:0] m_axi_awburst_reg = 2'd0;
reg m_axi_awlock_reg = 1'b0;
reg [3:0] m_axi_awcache_reg = 4'd0;
reg [2:0] m_axi_awprot_reg = 3'd0;
reg [3:0] m_axi_awqos_reg = 4'd0;
reg [3:0] m_axi_awregion_reg = 4'd0;
reg [AWUSER_WIDTH-1:0] m_axi_awuser_reg = {AWUSER_WIDTH{1'b0}};
reg m_axi_awvalid_reg = 1'b0, m_axi_awvalid_next;
// datapath control
reg store_axi_aw_input_to_output;
assign s_axi_awready = s_axi_awready_reg;
assign m_axi_awid = m_axi_awid_reg;
assign m_axi_awaddr = m_axi_awaddr_reg;
assign m_axi_awlen = m_axi_awlen_reg;
assign m_axi_awsize = m_axi_awsize_reg;
assign m_axi_awburst = m_axi_awburst_reg;
assign m_axi_awlock = m_axi_awlock_reg;
assign m_axi_awcache = m_axi_awcache_reg;
assign m_axi_awprot = m_axi_awprot_reg;
assign m_axi_awqos = m_axi_awqos_reg;
assign m_axi_awregion = m_axi_awregion_reg;
assign m_axi_awuser = AWUSER_ENABLE ? m_axi_awuser_reg : {AWUSER_WIDTH{1'b0}};
assign m_axi_awvalid = m_axi_awvalid_reg;
// enable ready input next cycle if output buffer will be empty
wire s_axi_awready_eawly = !m_axi_awvalid_next;
always @* begin
// transfer sink ready state to source
m_axi_awvalid_next = m_axi_awvalid_reg;
store_axi_aw_input_to_output = 1'b0;
if (s_axi_awready_reg) begin
m_axi_awvalid_next = s_axi_awvalid;
store_axi_aw_input_to_output = 1'b1;
end else if (m_axi_awready) begin
m_axi_awvalid_next = 1'b0;
end
end
always @(posedge clk) begin
if (rst) begin
s_axi_awready_reg <= 1'b0;
m_axi_awvalid_reg <= 1'b0;
end else begin
s_axi_awready_reg <= s_axi_awready_eawly;
m_axi_awvalid_reg <= m_axi_awvalid_next;
end
// datapath
if (store_axi_aw_input_to_output) begin
m_axi_awid_reg <= s_axi_awid;
m_axi_awaddr_reg <= s_axi_awaddr;
m_axi_awlen_reg <= s_axi_awlen;
m_axi_awsize_reg <= s_axi_awsize;
m_axi_awburst_reg <= s_axi_awburst;
m_axi_awlock_reg <= s_axi_awlock;
m_axi_awcache_reg <= s_axi_awcache;
m_axi_awprot_reg <= s_axi_awprot;
m_axi_awqos_reg <= s_axi_awqos;
m_axi_awregion_reg <= s_axi_awregion;
m_axi_awuser_reg <= s_axi_awuser;
end
end
end else begin
// bypass AW channel
assign m_axi_awid = s_axi_awid;
assign m_axi_awaddr = s_axi_awaddr;
assign m_axi_awlen = s_axi_awlen;
assign m_axi_awsize = s_axi_awsize;
assign m_axi_awburst = s_axi_awburst;
assign m_axi_awlock = s_axi_awlock;
assign m_axi_awcache = s_axi_awcache;
assign m_axi_awprot = s_axi_awprot;
assign m_axi_awqos = s_axi_awqos;
assign m_axi_awregion = s_axi_awregion;
assign m_axi_awuser = AWUSER_ENABLE ? s_axi_awuser : {AWUSER_WIDTH{1'b0}};
assign m_axi_awvalid = s_axi_awvalid;
assign s_axi_awready = m_axi_awready;
end
// W channel
if (W_REG_TYPE > 1) begin
// skid buffer, no bubble cycles
// datapath registers
reg s_axi_wready_reg = 1'b0;
reg [DATA_WIDTH-1:0] m_axi_wdata_reg = {DATA_WIDTH{1'b0}};
reg [STRB_WIDTH-1:0] m_axi_wstrb_reg = {STRB_WIDTH{1'b0}};
reg m_axi_wlast_reg = 1'b0;
reg [WUSER_WIDTH-1:0] m_axi_wuser_reg = {WUSER_WIDTH{1'b0}};
reg m_axi_wvalid_reg = 1'b0, m_axi_wvalid_next;
reg [DATA_WIDTH-1:0] temp_m_axi_wdata_reg = {DATA_WIDTH{1'b0}};
reg [STRB_WIDTH-1:0] temp_m_axi_wstrb_reg = {STRB_WIDTH{1'b0}};
reg temp_m_axi_wlast_reg = 1'b0;
reg [WUSER_WIDTH-1:0] temp_m_axi_wuser_reg = {WUSER_WIDTH{1'b0}};
reg temp_m_axi_wvalid_reg = 1'b0, temp_m_axi_wvalid_next;
// datapath control
reg store_axi_w_input_to_output;
reg store_axi_w_input_to_temp;
reg store_axi_w_temp_to_output;
assign s_axi_wready = s_axi_wready_reg;
assign m_axi_wdata = m_axi_wdata_reg;
assign m_axi_wstrb = m_axi_wstrb_reg;
assign m_axi_wlast = m_axi_wlast_reg;
assign m_axi_wuser = WUSER_ENABLE ? m_axi_wuser_reg : {WUSER_WIDTH{1'b0}};
assign m_axi_wvalid = m_axi_wvalid_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
wire s_axi_wready_early = m_axi_wready | (~temp_m_axi_wvalid_reg & (~m_axi_wvalid_reg | ~s_axi_wvalid));
always @* begin
// transfer sink ready state to source
m_axi_wvalid_next = m_axi_wvalid_reg;
temp_m_axi_wvalid_next = temp_m_axi_wvalid_reg;
store_axi_w_input_to_output = 1'b0;
store_axi_w_input_to_temp = 1'b0;
store_axi_w_temp_to_output = 1'b0;
if (s_axi_wready_reg) begin
// input is ready
if (m_axi_wready | ~m_axi_wvalid_reg) begin
// output is ready or currently not valid, transfer data to output
m_axi_wvalid_next = s_axi_wvalid;
store_axi_w_input_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_m_axi_wvalid_next = s_axi_wvalid;
store_axi_w_input_to_temp = 1'b1;
end
end else if (m_axi_wready) begin
// input is not ready, but output is ready
m_axi_wvalid_next = temp_m_axi_wvalid_reg;
temp_m_axi_wvalid_next = 1'b0;
store_axi_w_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
s_axi_wready_reg <= 1'b0;
m_axi_wvalid_reg <= 1'b0;
temp_m_axi_wvalid_reg <= 1'b0;
end else begin
s_axi_wready_reg <= s_axi_wready_early;
m_axi_wvalid_reg <= m_axi_wvalid_next;
temp_m_axi_wvalid_reg <= temp_m_axi_wvalid_next;
end
// datapath
if (store_axi_w_input_to_output) begin
m_axi_wdata_reg <= s_axi_wdata;
m_axi_wstrb_reg <= s_axi_wstrb;
m_axi_wlast_reg <= s_axi_wlast;
m_axi_wuser_reg <= s_axi_wuser;
end else if (store_axi_w_temp_to_output) begin
m_axi_wdata_reg <= temp_m_axi_wdata_reg;
m_axi_wstrb_reg <= temp_m_axi_wstrb_reg;
m_axi_wlast_reg <= temp_m_axi_wlast_reg;
m_axi_wuser_reg <= temp_m_axi_wuser_reg;
end
if (store_axi_w_input_to_temp) begin
temp_m_axi_wdata_reg <= s_axi_wdata;
temp_m_axi_wstrb_reg <= s_axi_wstrb;
temp_m_axi_wlast_reg <= s_axi_wlast;
temp_m_axi_wuser_reg <= s_axi_wuser;
end
end
end else if (W_REG_TYPE == 1) begin
// simple register, inserts bubble cycles
// datapath registers
reg s_axi_wready_reg = 1'b0;
reg [DATA_WIDTH-1:0] m_axi_wdata_reg = {DATA_WIDTH{1'b0}};
reg [STRB_WIDTH-1:0] m_axi_wstrb_reg = {STRB_WIDTH{1'b0}};
reg m_axi_wlast_reg = 1'b0;
reg [WUSER_WIDTH-1:0] m_axi_wuser_reg = {WUSER_WIDTH{1'b0}};
reg m_axi_wvalid_reg = 1'b0, m_axi_wvalid_next;
// datapath control
reg store_axi_w_input_to_output;
assign s_axi_wready = s_axi_wready_reg;
assign m_axi_wdata = m_axi_wdata_reg;
assign m_axi_wstrb = m_axi_wstrb_reg;
assign m_axi_wlast = m_axi_wlast_reg;
assign m_axi_wuser = WUSER_ENABLE ? m_axi_wuser_reg : {WUSER_WIDTH{1'b0}};
assign m_axi_wvalid = m_axi_wvalid_reg;
// enable ready input next cycle if output buffer will be empty
wire s_axi_wready_ewly = !m_axi_wvalid_next;
always @* begin
// transfer sink ready state to source
m_axi_wvalid_next = m_axi_wvalid_reg;
store_axi_w_input_to_output = 1'b0;
if (s_axi_wready_reg) begin
m_axi_wvalid_next = s_axi_wvalid;
store_axi_w_input_to_output = 1'b1;
end else if (m_axi_wready) begin
m_axi_wvalid_next = 1'b0;
end
end
always @(posedge clk) begin
if (rst) begin
s_axi_wready_reg <= 1'b0;
m_axi_wvalid_reg <= 1'b0;
end else begin
s_axi_wready_reg <= s_axi_wready_ewly;
m_axi_wvalid_reg <= m_axi_wvalid_next;
end
// datapath
if (store_axi_w_input_to_output) begin
m_axi_wdata_reg <= s_axi_wdata;
m_axi_wstrb_reg <= s_axi_wstrb;
m_axi_wlast_reg <= s_axi_wlast;
m_axi_wuser_reg <= s_axi_wuser;
end
end
end else begin
// bypass W channel
assign m_axi_wdata = s_axi_wdata;
assign m_axi_wstrb = s_axi_wstrb;
assign m_axi_wlast = s_axi_wlast;
assign m_axi_wuser = WUSER_ENABLE ? s_axi_wuser : {WUSER_WIDTH{1'b0}};
assign m_axi_wvalid = s_axi_wvalid;
assign s_axi_wready = m_axi_wready;
end
// B channel
if (B_REG_TYPE > 1) begin
// skid buffer, no bubble cycles
// datapath registers
reg m_axi_bready_reg = 1'b0;
reg [ID_WIDTH-1:0] s_axi_bid_reg = {ID_WIDTH{1'b0}};
reg [1:0] s_axi_bresp_reg = 2'b0;
reg [BUSER_WIDTH-1:0] s_axi_buser_reg = {BUSER_WIDTH{1'b0}};
reg s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next;
reg [ID_WIDTH-1:0] temp_s_axi_bid_reg = {ID_WIDTH{1'b0}};
reg [1:0] temp_s_axi_bresp_reg = 2'b0;
reg [BUSER_WIDTH-1:0] temp_s_axi_buser_reg = {BUSER_WIDTH{1'b0}};
reg temp_s_axi_bvalid_reg = 1'b0, temp_s_axi_bvalid_next;
// datapath control
reg store_axi_b_input_to_output;
reg store_axi_b_input_to_temp;
reg store_axi_b_temp_to_output;
assign m_axi_bready = m_axi_bready_reg;
assign s_axi_bid = s_axi_bid_reg;
assign s_axi_bresp = s_axi_bresp_reg;
assign s_axi_buser = BUSER_ENABLE ? s_axi_buser_reg : {BUSER_WIDTH{1'b0}};
assign s_axi_bvalid = s_axi_bvalid_reg;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
wire m_axi_bready_early = s_axi_bready | (~temp_s_axi_bvalid_reg & (~s_axi_bvalid_reg | ~m_axi_bvalid));
always @* begin
// transfer sink ready state to source
s_axi_bvalid_next = s_axi_bvalid_reg;
temp_s_axi_bvalid_next = temp_s_axi_bvalid_reg;
store_axi_b_input_to_output = 1'b0;
store_axi_b_input_to_temp = 1'b0;
store_axi_b_temp_to_output = 1'b0;
if (m_axi_bready_reg) begin
// input is ready
if (s_axi_bready | ~s_axi_bvalid_reg) begin
// output is ready or currently not valid, transfer data to output
s_axi_bvalid_next = m_axi_bvalid;
store_axi_b_input_to_output = 1'b1;
end else begin
// output is not ready, store input in temp
temp_s_axi_bvalid_next = m_axi_bvalid;
store_axi_b_input_to_temp = 1'b1;
end
end else if (s_axi_bready) begin
// input is not ready, but output is ready
s_axi_bvalid_next = temp_s_axi_bvalid_reg;
temp_s_axi_bvalid_next = 1'b0;
store_axi_b_temp_to_output = 1'b1;
end
end
always @(posedge clk) begin
if (rst) begin
m_axi_bready_reg <= 1'b0;
s_axi_bvalid_reg <= 1'b0;
temp_s_axi_bvalid_reg <= 1'b0;
end else begin
m_axi_bready_reg <= m_axi_bready_early;
s_axi_bvalid_reg <= s_axi_bvalid_next;
temp_s_axi_bvalid_reg <= temp_s_axi_bvalid_next;
end
// datapath
if (store_axi_b_input_to_output) begin
s_axi_bid_reg <= m_axi_bid;
s_axi_bresp_reg <= m_axi_bresp;
s_axi_buser_reg <= m_axi_buser;
end else if (store_axi_b_temp_to_output) begin
s_axi_bid_reg <= temp_s_axi_bid_reg;
s_axi_bresp_reg <= temp_s_axi_bresp_reg;
s_axi_buser_reg <= temp_s_axi_buser_reg;
end
if (store_axi_b_input_to_temp) begin
temp_s_axi_bid_reg <= m_axi_bid;
temp_s_axi_bresp_reg <= m_axi_bresp;
temp_s_axi_buser_reg <= m_axi_buser;
end
end
end else if (B_REG_TYPE == 1) begin
// simple register, inserts bubble cycles
// datapath registers
reg m_axi_bready_reg = 1'b0;
reg [ID_WIDTH-1:0] s_axi_bid_reg = {ID_WIDTH{1'b0}};
reg [1:0] s_axi_bresp_reg = 2'b0;
reg [BUSER_WIDTH-1:0] s_axi_buser_reg = {BUSER_WIDTH{1'b0}};
reg s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next;
// datapath control
reg store_axi_b_input_to_output;
assign m_axi_bready = m_axi_bready_reg;
assign s_axi_bid = s_axi_bid_reg;
assign s_axi_bresp = s_axi_bresp_reg;
assign s_axi_buser = BUSER_ENABLE ? s_axi_buser_reg : {BUSER_WIDTH{1'b0}};
assign s_axi_bvalid = s_axi_bvalid_reg;
// enable ready input next cycle if output buffer will be empty
wire m_axi_bready_early = !s_axi_bvalid_next;
always @* begin
// transfer sink ready state to source
s_axi_bvalid_next = s_axi_bvalid_reg;
store_axi_b_input_to_output = 1'b0;
if (m_axi_bready_reg) begin
s_axi_bvalid_next = m_axi_bvalid;
store_axi_b_input_to_output = 1'b1;
end else if (s_axi_bready) begin
s_axi_bvalid_next = 1'b0;
end
end
always @(posedge clk) begin
if (rst) begin
m_axi_bready_reg <= 1'b0;
s_axi_bvalid_reg <= 1'b0;
end else begin
m_axi_bready_reg <= m_axi_bready_early;
s_axi_bvalid_reg <= s_axi_bvalid_next;
end
// datapath
if (store_axi_b_input_to_output) begin
s_axi_bid_reg <= m_axi_bid;
s_axi_bresp_reg <= m_axi_bresp;
s_axi_buser_reg <= m_axi_buser;
end
end
end else begin
// bypass B channel
assign s_axi_bid = m_axi_bid;
assign s_axi_bresp = m_axi_bresp;
assign s_axi_buser = BUSER_ENABLE ? m_axi_buser : {BUSER_WIDTH{1'b0}};
assign s_axi_bvalid = m_axi_bvalid;
assign m_axi_bready = s_axi_bready;
end
endgenerate
endmodule
/*
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 lite width adapter
*/
module axil_adapter #
(
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of input (slave) interface data bus in bits
parameter S_DATA_WIDTH = 32,
// Width of input (slave) interface wstrb (width of data bus in words)
parameter S_STRB_WIDTH = (S_DATA_WIDTH/8),
// Width of output (master) interface data bus in bits
parameter M_DATA_WIDTH = 32,
// Width of output (master) interface wstrb (width of data bus in words)
parameter M_STRB_WIDTH = (M_DATA_WIDTH/8)
)
(
input wire clk,
input wire rst,
/*
* AXI lite slave interface
*/
input wire [ADDR_WIDTH-1:0] s_axil_awaddr,
input wire [2:0] s_axil_awprot,
input wire s_axil_awvalid,
output wire s_axil_awready,
input wire [S_DATA_WIDTH-1:0] s_axil_wdata,
input wire [S_STRB_WIDTH-1:0] s_axil_wstrb,
input wire s_axil_wvalid,
output wire s_axil_wready,
output wire [1:0] s_axil_bresp,
output wire s_axil_bvalid,
input wire s_axil_bready,
input wire [ADDR_WIDTH-1:0] s_axil_araddr,
input wire [2:0] s_axil_arprot,
input wire s_axil_arvalid,
output wire s_axil_arready,
output wire [S_DATA_WIDTH-1:0] s_axil_rdata,
output wire [1:0] s_axil_rresp,
output wire s_axil_rvalid,
input wire s_axil_rready,
/*
* AXI lite master interface
*/
output wire [ADDR_WIDTH-1:0] m_axil_awaddr,
output wire [2:0] m_axil_awprot,
output wire m_axil_awvalid,
input wire m_axil_awready,
output wire [M_DATA_WIDTH-1:0] m_axil_wdata,
output wire [M_STRB_WIDTH-1:0] m_axil_wstrb,
output wire m_axil_wvalid,
input wire m_axil_wready,
input wire [1:0] m_axil_bresp,
input wire m_axil_bvalid,
output wire m_axil_bready,
output wire [ADDR_WIDTH-1:0] m_axil_araddr,
output wire [2:0] m_axil_arprot,
output wire m_axil_arvalid,
input wire m_axil_arready,
input wire [M_DATA_WIDTH-1:0] m_axil_rdata,
input wire [1:0] m_axil_rresp,
input wire m_axil_rvalid,
output wire m_axil_rready
);
axil_adapter_wr #(
.ADDR_WIDTH(ADDR_WIDTH),
.S_DATA_WIDTH(S_DATA_WIDTH),
.S_STRB_WIDTH(S_STRB_WIDTH),
.M_DATA_WIDTH(M_DATA_WIDTH),
.M_STRB_WIDTH(M_STRB_WIDTH)
)
axil_adapter_wr_inst (
.clk(clk),
.rst(rst),
/*
* AXI lite slave interface
*/
.s_axil_awaddr(s_axil_awaddr),
.s_axil_awprot(s_axil_awprot),
.s_axil_awvalid(s_axil_awvalid),
.s_axil_awready(s_axil_awready),
.s_axil_wdata(s_axil_wdata),
.s_axil_wstrb(s_axil_wstrb),
.s_axil_wvalid(s_axil_wvalid),
.s_axil_wready(s_axil_wready),
.s_axil_bresp(s_axil_bresp),
.s_axil_bvalid(s_axil_bvalid),
.s_axil_bready(s_axil_bready),
/*
* AXI lite master interface
*/
.m_axil_awaddr(m_axil_awaddr),
.m_axil_awprot(m_axil_awprot),
.m_axil_awvalid(m_axil_awvalid),
.m_axil_awready(m_axil_awready),
.m_axil_wdata(m_axil_wdata),
.m_axil_wstrb(m_axil_wstrb),
.m_axil_wvalid(m_axil_wvalid),
.m_axil_wready(m_axil_wready),
.m_axil_bresp(m_axil_bresp),
.m_axil_bvalid(m_axil_bvalid),
.m_axil_bready(m_axil_bready)
);
axil_adapter_rd #(
.ADDR_WIDTH(ADDR_WIDTH),
.S_DATA_WIDTH(S_DATA_WIDTH),
.S_STRB_WIDTH(S_STRB_WIDTH),
.M_DATA_WIDTH(M_DATA_WIDTH),
.M_STRB_WIDTH(M_STRB_WIDTH)
)
axil_adapter_rd_inst (
.clk(clk),
.rst(rst),
/*
* AXI lite slave interface
*/
.s_axil_araddr(s_axil_araddr),
.s_axil_arprot(s_axil_arprot),
.s_axil_arvalid(s_axil_arvalid),
.s_axil_arready(s_axil_arready),
.s_axil_rdata(s_axil_rdata),
.s_axil_rresp(s_axil_rresp),
.s_axil_rvalid(s_axil_rvalid),
.s_axil_rready(s_axil_rready),
/*
* AXI lite master interface
*/
.m_axil_araddr(m_axil_araddr),
.m_axil_arprot(m_axil_arprot),
.m_axil_arvalid(m_axil_arvalid),
.m_axil_arready(m_axil_arready),
.m_axil_rdata(m_axil_rdata),
.m_axil_rresp(m_axil_rresp),
.m_axil_rvalid(m_axil_rvalid),
.m_axil_rready(m_axil_rready)
);
endmodule
/*
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 lite width adapter (read)
*/
module axil_adapter_rd #
(
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of input (slave) interface data bus in bits
parameter S_DATA_WIDTH = 32,
// Width of input (slave) interface wstrb (width of data bus in words)
parameter S_STRB_WIDTH = (S_DATA_WIDTH/8),
// Width of output (master) interface data bus in bits
parameter M_DATA_WIDTH = 32,
// Width of output (master) interface wstrb (width of data bus in words)
parameter M_STRB_WIDTH = (M_DATA_WIDTH/8)
)
(
input wire clk,
input wire rst,
/*
* AXI lite slave interface
*/
input wire [ADDR_WIDTH-1:0] s_axil_araddr,
input wire [2:0] s_axil_arprot,
input wire s_axil_arvalid,
output wire s_axil_arready,
output wire [S_DATA_WIDTH-1:0] s_axil_rdata,
output wire [1:0] s_axil_rresp,
output wire s_axil_rvalid,
input wire s_axil_rready,
/*
* AXI lite master interface
*/
output wire [ADDR_WIDTH-1:0] m_axil_araddr,
output wire [2:0] m_axil_arprot,
output wire m_axil_arvalid,
input wire m_axil_arready,
input wire [M_DATA_WIDTH-1:0] m_axil_rdata,
input wire [1:0] m_axil_rresp,
input wire m_axil_rvalid,
output wire m_axil_rready
);
parameter S_ADDR_BIT_OFFSET = $clog2(S_STRB_WIDTH);
parameter M_ADDR_BIT_OFFSET = $clog2(M_STRB_WIDTH);
parameter S_WORD_WIDTH = S_STRB_WIDTH;
parameter M_WORD_WIDTH = M_STRB_WIDTH;
parameter S_WORD_SIZE = S_DATA_WIDTH/S_WORD_WIDTH;
parameter M_WORD_SIZE = M_DATA_WIDTH/M_WORD_WIDTH;
// output bus is wider
parameter EXPAND = M_STRB_WIDTH > S_STRB_WIDTH;
parameter DATA_WIDTH = EXPAND ? M_DATA_WIDTH : S_DATA_WIDTH;
parameter STRB_WIDTH = EXPAND ? M_STRB_WIDTH : S_STRB_WIDTH;
// required number of segments in wider bus
parameter SEGMENT_COUNT = EXPAND ? (M_STRB_WIDTH / S_STRB_WIDTH) : (S_STRB_WIDTH / M_STRB_WIDTH);
parameter SEGMENT_COUNT_WIDTH = SEGMENT_COUNT == 1 ? 1 : $clog2(SEGMENT_COUNT);
// data width and keep width per segment
parameter SEGMENT_DATA_WIDTH = DATA_WIDTH / SEGMENT_COUNT;
parameter SEGMENT_STRB_WIDTH = STRB_WIDTH / SEGMENT_COUNT;
// bus width assertions
initial begin
if (S_WORD_SIZE * S_STRB_WIDTH != S_DATA_WIDTH) begin
$error("Error: AXI slave interface data width not evenly divisble (instance %m)");
$finish;
end
if (M_WORD_SIZE * M_STRB_WIDTH != M_DATA_WIDTH) begin
$error("Error: AXI master interface data width not evenly divisble (instance %m)");
$finish;
end
if (S_WORD_SIZE != M_WORD_SIZE) begin
$error("Error: word size mismatch (instance %m)");
$finish;
end
if (2**$clog2(S_WORD_WIDTH) != S_WORD_WIDTH) begin
$error("Error: AXI slave interface word width must be even power of two (instance %m)");
$finish;
end
if (2**$clog2(M_WORD_WIDTH) != M_WORD_WIDTH) begin
$error("Error: AXI master interface word width must be even power of two (instance %m)");
$finish;
end
end
localparam [0:0]
STATE_IDLE = 1'd0,
STATE_DATA = 1'd1;
reg [0:0] state_reg = STATE_IDLE, state_next;
reg [SEGMENT_COUNT_WIDTH-1:0] current_segment_reg = 0, current_segment_next;
reg s_axil_arready_reg = 1'b0, s_axil_arready_next;
reg [S_DATA_WIDTH-1:0] s_axil_rdata_reg = {S_DATA_WIDTH{1'b0}}, s_axil_rdata_next;
reg [1:0] s_axil_rresp_reg = 2'd0, s_axil_rresp_next;
reg s_axil_rvalid_reg = 1'b0, s_axil_rvalid_next;
reg [ADDR_WIDTH-1:0] m_axil_araddr_reg = {ADDR_WIDTH{1'b0}}, m_axil_araddr_next;
reg [2:0] m_axil_arprot_reg = 3'd0, m_axil_arprot_next;
reg m_axil_arvalid_reg = 1'b0, m_axil_arvalid_next;
reg m_axil_rready_reg = 1'b0, m_axil_rready_next;
assign s_axil_arready = s_axil_arready_reg;
assign s_axil_rdata = s_axil_rdata_reg;
assign s_axil_rresp = s_axil_rresp_reg;
assign s_axil_rvalid = s_axil_rvalid_reg;
assign m_axil_araddr = m_axil_araddr_reg;
assign m_axil_arprot = m_axil_arprot_reg;
assign m_axil_arvalid = m_axil_arvalid_reg;
assign m_axil_rready = m_axil_rready_reg;
always @* begin
state_next = STATE_IDLE;
current_segment_next = current_segment_reg;
s_axil_arready_next = 1'b0;
s_axil_rdata_next = s_axil_rdata_reg;
s_axil_rresp_next = s_axil_rresp_reg;
s_axil_rvalid_next = s_axil_rvalid_reg && !s_axil_rready;
m_axil_araddr_next = m_axil_araddr_reg;
m_axil_arprot_next = m_axil_arprot_reg;
m_axil_arvalid_next = m_axil_arvalid_reg && !m_axil_arready;
m_axil_rready_next = 1'b0;
if (SEGMENT_COUNT == 1 || EXPAND) begin
// master output is same width or wider; single cycle direct transfer
case (state_reg)
STATE_IDLE: begin
s_axil_arready_next = !m_axil_arvalid;
if (s_axil_arready && s_axil_arvalid) begin
s_axil_arready_next = 1'b0;
m_axil_araddr_next = s_axil_araddr;
m_axil_arprot_next = s_axil_arprot;
m_axil_arvalid_next = 1'b1;
m_axil_rready_next = !m_axil_rvalid;
state_next = STATE_DATA;
end else begin
state_next = STATE_IDLE;
end
end
STATE_DATA: begin
m_axil_rready_next = !s_axil_rvalid;
if (m_axil_rready && m_axil_rvalid) begin
m_axil_rready_next = 1'b0;
if (M_WORD_WIDTH == S_WORD_WIDTH) begin
s_axil_rdata_next = m_axil_rdata;
end else begin
s_axil_rdata_next = m_axil_rdata >> (m_axil_araddr_reg[M_ADDR_BIT_OFFSET - 1:S_ADDR_BIT_OFFSET] * S_DATA_WIDTH);
end
s_axil_rresp_next = m_axil_rresp;
s_axil_rvalid_next = 1'b1;
s_axil_arready_next = !m_axil_arvalid;
state_next = STATE_IDLE;
end else begin
state_next = STATE_DATA;
end
end
endcase
end else begin
// master output is narrower; may need several cycles
case (state_reg)
STATE_IDLE: begin
s_axil_arready_next = !m_axil_arvalid;
current_segment_next = 0;
s_axil_rresp_next = 2'd0;
if (s_axil_arready && s_axil_arvalid) begin
s_axil_arready_next = 1'b0;
m_axil_araddr_next = s_axil_araddr & ({ADDR_WIDTH{1'b1}} << S_ADDR_BIT_OFFSET);
m_axil_arprot_next = s_axil_arprot;
m_axil_arvalid_next = 1'b1;
m_axil_rready_next = !m_axil_rvalid;
state_next = STATE_DATA;
end else begin
state_next = STATE_IDLE;
end
end
STATE_DATA: begin
m_axil_rready_next = !s_axil_rvalid;
if (m_axil_rready && m_axil_rvalid) begin
m_axil_rready_next = 1'b0;
s_axil_rdata_next[current_segment_reg*SEGMENT_DATA_WIDTH +: SEGMENT_DATA_WIDTH] = m_axil_rdata;
if (m_axil_rresp) begin
s_axil_rresp_next = m_axil_rresp;
end
if (current_segment_reg == SEGMENT_COUNT-1) begin
s_axil_rvalid_next = 1'b1;
s_axil_arready_next = !m_axil_arvalid;
state_next = STATE_IDLE;
end else begin
current_segment_next = current_segment_reg + 1;
m_axil_araddr_next = m_axil_araddr_reg + SEGMENT_STRB_WIDTH;
m_axil_arvalid_next = 1'b1;
state_next = STATE_DATA;
end
end else begin
state_next = STATE_DATA;
end
end
endcase
end
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
s_axil_arready_reg <= 1'b0;
s_axil_rvalid_reg <= 1'b0;
m_axil_arvalid_reg <= 1'b0;
m_axil_rready_reg <= 1'b0;
end else begin
state_reg <= state_next;
s_axil_arready_reg <= s_axil_arready_next;
s_axil_rvalid_reg <= s_axil_rvalid_next;
m_axil_arvalid_reg <= m_axil_arvalid_next;
m_axil_rready_reg <= m_axil_rready_next;
end
current_segment_reg <= current_segment_next;
s_axil_rdata_reg <= s_axil_rdata_next;
s_axil_rresp_reg <= s_axil_rresp_next;
m_axil_araddr_reg <= m_axil_araddr_next;
m_axil_arprot_reg <= m_axil_arprot_next;
end
endmodule
/*
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 lite width adapter (write)
*/
module axil_adapter_wr #
(
// Width of address bus in bits
parameter ADDR_WIDTH = 32,
// Width of input (slave) interface data bus in bits
parameter S_DATA_WIDTH = 32,
// Width of input (slave) interface wstrb (width of data bus in words)
parameter S_STRB_WIDTH = (S_DATA_WIDTH/8),
// Width of output (master) interface data bus in bits
parameter M_DATA_WIDTH = 32,
// Width of output (master) interface wstrb (width of data bus in words)
parameter M_STRB_WIDTH = (M_DATA_WIDTH/8)
)
(
input wire clk,
input wire rst,
/*
* AXI lite slave interface
*/
input wire [ADDR_WIDTH-1:0] s_axil_awaddr,
input wire [2:0] s_axil_awprot,
input wire s_axil_awvalid,
output wire s_axil_awready,
input wire [S_DATA_WIDTH-1:0] s_axil_wdata,
input wire [S_STRB_WIDTH-1:0] s_axil_wstrb,
input wire s_axil_wvalid,
output wire s_axil_wready,
output wire [1:0] s_axil_bresp,
output wire s_axil_bvalid,
input wire s_axil_bready,
/*
* AXI lite master interface
*/
output wire [ADDR_WIDTH-1:0] m_axil_awaddr,
output wire [2:0] m_axil_awprot,
output wire m_axil_awvalid,
input wire m_axil_awready,
output wire [M_DATA_WIDTH-1:0] m_axil_wdata,
output wire [M_STRB_WIDTH-1:0] m_axil_wstrb,
output wire m_axil_wvalid,
input wire m_axil_wready,
input wire [1:0] m_axil_bresp,
input wire m_axil_bvalid,
output wire m_axil_bready
);
parameter S_ADDR_BIT_OFFSET = $clog2(S_STRB_WIDTH);
parameter M_ADDR_BIT_OFFSET = $clog2(M_STRB_WIDTH);
parameter S_WORD_WIDTH = S_STRB_WIDTH;
parameter M_WORD_WIDTH = M_STRB_WIDTH;
parameter S_WORD_SIZE = S_DATA_WIDTH/S_WORD_WIDTH;
parameter M_WORD_SIZE = M_DATA_WIDTH/M_WORD_WIDTH;
// output bus is wider
parameter EXPAND = M_STRB_WIDTH > S_STRB_WIDTH;
parameter DATA_WIDTH = EXPAND ? M_DATA_WIDTH : S_DATA_WIDTH;
parameter STRB_WIDTH = EXPAND ? M_STRB_WIDTH : S_STRB_WIDTH;
// required number of segments in wider bus
parameter SEGMENT_COUNT = EXPAND ? (M_STRB_WIDTH / S_STRB_WIDTH) : (S_STRB_WIDTH / M_STRB_WIDTH);
parameter SEGMENT_COUNT_WIDTH = SEGMENT_COUNT == 1 ? 1 : $clog2(SEGMENT_COUNT);
// data width and keep width per segment
parameter SEGMENT_DATA_WIDTH = DATA_WIDTH / SEGMENT_COUNT;
parameter SEGMENT_STRB_WIDTH = STRB_WIDTH / SEGMENT_COUNT;
// bus width assertions
initial begin
if (S_WORD_SIZE * S_STRB_WIDTH != S_DATA_WIDTH) begin
$error("Error: AXI slave interface data width not evenly divisble (instance %m)");
$finish;
end
if (M_WORD_SIZE * M_STRB_WIDTH != M_DATA_WIDTH) begin
$error("Error: AXI master interface data width not evenly divisble (instance %m)");
$finish;
end
if (S_WORD_SIZE != M_WORD_SIZE) begin
$error("Error: word size mismatch (instance %m)");
$finish;
end
if (2**$clog2(S_WORD_WIDTH) != S_WORD_WIDTH) begin
$error("Error: AXI slave interface word width must be even power of two (instance %m)");
$finish;
end
if (2**$clog2(M_WORD_WIDTH) != M_WORD_WIDTH) begin
$error("Error: AXI master interface word width must be even power of two (instance %m)");
$finish;
end
end
localparam [1:0]
STATE_IDLE = 2'd0,
STATE_DATA = 2'd1,
STATE_RESP = 2'd3;
reg [1:0] state_reg = STATE_IDLE, state_next;
reg [DATA_WIDTH-1:0] data_reg = {DATA_WIDTH{1'b0}}, data_next;
reg [STRB_WIDTH-1:0] strb_reg = {STRB_WIDTH{1'b0}}, strb_next;
reg [SEGMENT_COUNT_WIDTH-1:0] current_segment_reg = 0, current_segment_next;
reg s_axil_awready_reg = 1'b0, s_axil_awready_next;
reg s_axil_wready_reg = 1'b0, s_axil_wready_next;
reg [1:0] s_axil_bresp_reg = 2'd0, s_axil_bresp_next;
reg s_axil_bvalid_reg = 1'b0, s_axil_bvalid_next;
reg [ADDR_WIDTH-1:0] m_axil_awaddr_reg = {ADDR_WIDTH{1'b0}}, m_axil_awaddr_next;
reg [2:0] m_axil_awprot_reg = 3'd0, m_axil_awprot_next;
reg m_axil_awvalid_reg = 1'b0, m_axil_awvalid_next;
reg [M_DATA_WIDTH-1:0] m_axil_wdata_reg = {M_DATA_WIDTH{1'b0}}, m_axil_wdata_next;
reg [M_STRB_WIDTH-1:0] m_axil_wstrb_reg = {M_STRB_WIDTH{1'b0}}, m_axil_wstrb_next;
reg m_axil_wvalid_reg = 1'b0, m_axil_wvalid_next;
reg m_axil_bready_reg = 1'b0, m_axil_bready_next;
assign s_axil_awready = s_axil_awready_reg;
assign s_axil_wready = s_axil_wready_reg;
assign s_axil_bresp = s_axil_bresp_reg;
assign s_axil_bvalid = s_axil_bvalid_reg;
assign m_axil_awaddr = m_axil_awaddr_reg;
assign m_axil_awprot = m_axil_awprot_reg;
assign m_axil_awvalid = m_axil_awvalid_reg;
assign m_axil_wdata = m_axil_wdata_reg;
assign m_axil_wstrb = m_axil_wstrb_reg;
assign m_axil_wvalid = m_axil_wvalid_reg;
assign m_axil_bready = m_axil_bready_reg;
always @* begin
state_next = STATE_IDLE;
data_next = data_reg;
strb_next = strb_reg;
current_segment_next = current_segment_reg;
s_axil_awready_next = 1'b0;
s_axil_wready_next = 1'b0;
s_axil_bresp_next = s_axil_bresp_reg;
s_axil_bvalid_next = s_axil_bvalid_reg && !s_axil_bready;
m_axil_awaddr_next = m_axil_awaddr_reg;
m_axil_awprot_next = m_axil_awprot_reg;
m_axil_awvalid_next = m_axil_awvalid_reg && !m_axil_awready;
m_axil_wdata_next = m_axil_wdata_reg;
m_axil_wstrb_next = m_axil_wstrb_reg;
m_axil_wvalid_next = m_axil_wvalid_reg && !m_axil_wready;
m_axil_bready_next = 1'b0;
if (SEGMENT_COUNT == 1 || EXPAND) begin
// master output is same width or wider; single cycle direct transfer
case (state_reg)
STATE_IDLE: begin
s_axil_awready_next = !m_axil_awvalid;
if (s_axil_awready && s_axil_awvalid) begin
s_axil_awready_next = 1'b0;
m_axil_awaddr_next = s_axil_awaddr;
m_axil_awprot_next = s_axil_awprot;
m_axil_awvalid_next = 1'b1;
s_axil_wready_next = !m_axil_wvalid;
state_next = STATE_DATA;
end else begin
state_next = STATE_IDLE;
end
end
STATE_DATA: begin
s_axil_wready_next = !m_axil_wvalid;
if (s_axil_wready && s_axil_wvalid) begin
s_axil_wready_next = 1'b0;
if (M_WORD_WIDTH == S_WORD_WIDTH) begin
m_axil_wdata_next = s_axil_wdata;
m_axil_wstrb_next = s_axil_wstrb;
end else begin
m_axil_wdata_next = {(M_WORD_WIDTH/S_WORD_WIDTH){s_axil_wdata}};
m_axil_wstrb_next = s_axil_wstrb << (m_axil_awaddr_reg[M_ADDR_BIT_OFFSET - 1:S_ADDR_BIT_OFFSET] * S_STRB_WIDTH);
end
m_axil_wvalid_next = 1'b1;
m_axil_bready_next = !s_axil_bvalid;
state_next = STATE_RESP;
end else begin
state_next = STATE_DATA;
end
end
STATE_RESP: begin
m_axil_bready_next = !s_axil_bvalid;
if (m_axil_bready && m_axil_bvalid) begin
m_axil_bready_next = 1'b0;
s_axil_bresp_next = m_axil_bresp;
s_axil_bvalid_next = 1'b1;
s_axil_awready_next = !m_axil_awvalid;
state_next = STATE_IDLE;
end else begin
state_next = STATE_RESP;
end
end
endcase
end else begin
// master output is narrower; may need several cycles
case (state_reg)
STATE_IDLE: begin
s_axil_awready_next = !m_axil_awvalid;
current_segment_next = 0;
s_axil_bresp_next = 2'd0;
if (s_axil_awready && s_axil_awvalid) begin
s_axil_awready_next = 1'b0;
m_axil_awaddr_next = s_axil_awaddr & ({ADDR_WIDTH{1'b1}} << S_ADDR_BIT_OFFSET);
m_axil_awprot_next = s_axil_awprot;
m_axil_awvalid_next = 1'b1;
s_axil_wready_next = !m_axil_wvalid;
state_next = STATE_DATA;
end else begin
state_next = STATE_IDLE;
end
end
STATE_DATA: begin
s_axil_wready_next = !m_axil_wvalid;
if (s_axil_wready && s_axil_wvalid) begin
s_axil_wready_next = 1'b0;
data_next = s_axil_wdata;
strb_next = s_axil_wstrb;
m_axil_wdata_next = s_axil_wdata;
m_axil_wstrb_next = s_axil_wstrb;
m_axil_wvalid_next = 1'b1;
m_axil_bready_next = !s_axil_bvalid;
state_next = STATE_RESP;
end else begin
state_next = STATE_DATA;
end
end
STATE_RESP: begin
m_axil_bready_next = !s_axil_bvalid;
if (m_axil_bready && m_axil_bvalid) begin
m_axil_bready_next = 1'b0;
if (m_axil_bresp != 0) begin
s_axil_bresp_next = m_axil_bresp;
end
if (current_segment_reg == SEGMENT_COUNT-1) begin
s_axil_bvalid_next = 1'b1;
s_axil_awready_next = !m_axil_awvalid;
state_next = STATE_IDLE;
end else begin
current_segment_next = current_segment_reg + 1;
m_axil_awaddr_next = m_axil_awaddr_reg + SEGMENT_STRB_WIDTH;
m_axil_awvalid_next = 1'b1;
m_axil_wdata_next = data_reg >> (current_segment_reg+1)*SEGMENT_DATA_WIDTH;
m_axil_wstrb_next = strb_reg >> (current_segment_reg+1)*SEGMENT_STRB_WIDTH;
m_axil_wvalid_next = 1'b1;
state_next = STATE_RESP;
end
end else begin
state_next = STATE_RESP;
end
end
endcase
end
end
always @(posedge clk) begin
if (rst) begin
state_reg <= STATE_IDLE;
s_axil_awready_reg <= 1'b0;
s_axil_wready_reg <= 1'b0;
s_axil_bvalid_reg <= 1'b0;
m_axil_awvalid_reg <= 1'b0;
m_axil_wvalid_reg <= 1'b0;
m_axil_bready_reg <= 1'b0;
end else begin
state_reg <= state_next;
s_axil_awready_reg <= s_axil_awready_next;
s_axil_wready_reg <= s_axil_wready_next;
s_axil_bvalid_reg <= s_axil_bvalid_next;
m_axil_awvalid_reg <= m_axil_awvalid_next;
m_axil_wvalid_reg <= m_axil_wvalid_next;
m_axil_bready_reg <= m_axil_bready_next;
end
data_reg <= data_next;
strb_reg <= strb_next;
current_segment_reg <= current_segment_next;
s_axil_bresp_reg <= s_axil_bresp_next;
m_axil_awaddr_reg <= m_axil_awaddr_next;
m_axil_awprot_reg <= m_axil_awprot_next;
m_axil_wdata_reg <= m_axil_wdata_next;
m_axil_wstrb_reg <= m_axil_wstrb_next;
end
endmodule
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment