blob: aeeb6a3d86c34fb748d2717a5798754ae3e45ae5 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Filename: axi2axi3.v
//
// Project: WB2AXIPSP: bus bridges and other odds and ends
//
// Purpose: Bridge from an AXI4 slave to an AXI3 master
//
// The goal here is to not lose bus resolution, capacity or capability,
// while bridging from AXI4 to AXI3. The biggest problem with such
// a bridge is that we'll need to break large requests (AxLEN>15) up
// into smaller packets. After that, everything should work as normal
// with only minor modifications for AxCACHE.
//
// Opportunity:
// The cost of this core is very much determined by the number of ID's
// supported. It should be possible, with little extra cost or effort,
// to reduce the ID space herein. This should be a topic for future
// exploration.
//
// Status:
// This core is an unverified first draft. It has past neither formal
// nor simulation testing. Therefore, it is almost certain to have bugs
// within it. Use it at your own risk.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020, Gisselquist Technology, LLC
//
// This file is part of the WB2AXIP project.
//
// The WB2AXIP project contains free software and gateware, licensed under the
// Apache License, Version 2.0 (the "License"). You may not use this project,
// or this file, except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype none
//
//
module axi2axi3 #(
parameter C_AXI_ID_WIDTH = 1,
parameter C_AXI_ADDR_WIDTH = 32,
parameter C_AXI_DATA_WIDTH = 32,
//
localparam ADDRLSB= $clog2(C_AXI_DATA_WIDTH)-3
) (
input wire S_AXI_ACLK,
input wire S_AXI_ARESETN,
//
// The AXI4 incoming/slave interface
input reg S_AXI_AWVALID,
output wire S_AXI_AWREADY,
input reg [C_AXI_ID_WIDTH-1:0] S_AXI_AWID,
input reg [C_AXI_ADDR_WIDTH-1:0] S_AXI_AWADDR,
input reg [7:0] S_AXI_AWLEN,
input reg [2:0] S_AXI_AWSIZE,
input reg [1:0] S_AXI_AWBURST,
input reg S_AXI_AWLOCK,
input reg [3:0] S_AXI_AWCACHE,
input reg [2:0] S_AXI_AWPROT,
input reg [3:0] S_AXI_AWQOS,
//
//
input wire S_AXI_WVALID,
output wire S_AXI_WREADY,
input wire [C_AXI_DATA_WIDTH-1:0] S_AXI_WDATA,
input wire [C_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB,
input wire S_AXI_WLAST,
//
//
output wire S_AXI_BVALID,
input wire S_AXI_BREADY,
output wire [C_AXI_ID_WIDTH-1:0] S_AXI_BID,
output wire [1:0] S_AXI_BRESP,
//
//
input wire S_AXI_ARVALID,
output wire S_AXI_ARREADY,
input wire [C_AXI_ID_WIDTH-1:0] S_AXI_ARID,
input wire [C_AXI_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,
//
output wire S_AXI_RVALID,
input wire S_AXI_RREADY,
output wire [C_AXI_ID_WIDTH-1:0] S_AXI_RID,
output wire [C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA,
output wire S_AXI_RLAST,
output wire [1:0] S_AXI_RRESP,
//
//
// The AXI3 Master (outgoing) interface
output wire M_AXI_AWVALID,
input wire M_AXI_AWREADY,
output wire [C_AXI_ID_WIDTH-1:0] M_AXI_AWID,
output wire [C_AXI_ADDR_WIDTH-1:0] M_AXI_AWADDR,
output wire [3:0] M_AXI_AWLEN,
output wire [2:0] M_AXI_AWSIZE,
output wire [1:0] M_AXI_AWBURST,
output wire [1:0] 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 M_AXI_WVALID,
input wire M_AXI_WREADY,
output wire [C_AXI_ID_WIDTH-1:0] M_AXI_WID,
output wire [C_AXI_DATA_WIDTH-1:0] M_AXI_WDATA,
output wire [C_AXI_DATA_WIDTH/8-1:0] M_AXI_WSTRB,
output wire M_AXI_WLAST,
//
//
input wire M_AXI_BVALID,
output wire M_AXI_BREADY,
input wire [C_AXI_ID_WIDTH-1:0] M_AXI_BID,
input wire [1:0] M_AXI_BRESP,
//
//
output wire M_AXI_ARVALID,
input wire M_AXI_ARREADY,
output wire [C_AXI_ID_WIDTH-1:0] M_AXI_ARID,
output wire [C_AXI_ADDR_WIDTH-1:0] M_AXI_ARADDR,
output wire [3:0] M_AXI_ARLEN,
output wire [2:0] M_AXI_ARSIZE,
output wire [1:0] M_AXI_ARBURST,
output wire [1:0] M_AXI_ARLOCK,
output wire [3:0] M_AXI_ARCACHE,
output wire [2:0] M_AXI_ARPROT,
output wire [3:0] M_AXI_ARQOS,
//
input wire M_AXI_RVALID,
output wire M_AXI_RREADY,
input wire [C_AXI_ID_WIDTH-1:0] M_AXI_RID,
input wire [C_AXI_DATA_WIDTH-1:0] M_AXI_RDATA,
input wire M_AXI_RLAST,
input wire [1:0] M_AXI_RRESP
);
localparam [0:0] OPT_LOWPOWER = 1'b0;
localparam LGWFIFO = 4;
localparam NID = (1<<C_AXI_ID_WIDTH);
parameter LGFIFO = 8;
genvar ID;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//
// WRITE SIDE
// {{{
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//
// Write address channel
// {{{
////////////////////////////////////////////////////////////////////////
//
//
reg [7:0] r_awlen;
reg [3:0] next_wlen;
wire awskd_valid;
reg awskd_ready;
wire [C_AXI_ID_WIDTH-1:0] awskd_id;
wire [C_AXI_ADDR_WIDTH-1:0] awskd_addr;
wire [7:0] awskd_len;
wire [2:0] awskd_size;
wire [1:0] awskd_burst;
wire awskd_lock;
wire [3:0] awskd_cache;
wire [2:0] awskd_prot;
wire [3:0] awskd_qos;
reg axi_awvalid;
reg [C_AXI_ID_WIDTH-1:0] axi_awid;
reg [C_AXI_ADDR_WIDTH-1:0] axi_awaddr;
reg [3:0] axi_awlen;
reg [2:0] axi_awsize;
reg [1:0] axi_awburst;
reg [1:0] axi_awlock;
reg [3:0] axi_awcache;
reg [2:0] axi_awprot;
reg [3:0] axi_awqos;
skidbuffer #(
.DW(C_AXI_ADDR_WIDTH + C_AXI_ID_WIDTH + 8 + 3 + 2 + 1+4+3+4),
.OPT_OUTREG(1'b0)
) awskid (
.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
.i_valid(S_AXI_AWVALID), .o_ready(S_AXI_AWREADY),
.i_data({ S_AXI_AWID, S_AXI_AWADDR, S_AXI_AWLEN,
S_AXI_AWSIZE, S_AXI_AWBURST, S_AXI_AWLOCK,
S_AXI_AWCACHE, S_AXI_AWPROT, S_AXI_AWQOS }),
.o_valid(awskd_valid), .i_ready(awskd_ready),
.o_data({ awskd_id, awskd_addr, awskd_len,
awskd_size, awskd_burst, awskd_lock,
awskd_cache, awskd_prot, awskd_qos })
);
always @(*)
begin
awskd_ready = 1;
if (r_awlen > 0)
awskd_ready = 0;
if (M_AXI_AWVALID && M_AXI_AWREADY)
awskd_ready = 0;
if (|wfifo_fill[LGWFIFO:LGWFIFO-1])
awskd_ready = 0;
end
initial axi_awvalid = 1'b0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
axi_awvalid <= 0;
else if (awskd_valid || r_awlen > 0)
axi_awvalid <= 1;
else if (M_AXI_AWREADY)
axi_awvalid <= 0;
initial r_awlen = 0;
initial axi_awlen = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
begin
r_awlen <= 0;
axi_awlen <= 0;
end else if (!M_AXI_AWVALID || M_AXI_AWREADY)
begin
if (r_awlen > 15)
begin
axi_awlen <= 4'd15;
r_awlen <= r_awlen - 8'd16;
end else if (r_awlen > 0)
begin
axi_awlen[3:0] <= r_awlen[3:0] - 1;
r_awlen <= 0;
end else if (awskd_valid)
begin
if (awskd_len > 15)
begin
r_awlen <= awskd_len + 1'b1 - 8'd16;
axi_awlen <= 4'd15;
end else begin
r_awlen <= 0;
axi_awlen <= awskd_len[3:0];
end
end else begin
r_awlen <= 0;
axi_awlen <= 0;
end
end
always @(posedge S_AXI_ACLK)
if (awskd_valid && awskd_ready)
axi_awaddr <= awskd_addr;
else if (M_AXI_AWVALID && M_AXI_AWREADY)
begin
// Verilator lint_off WIDTH
axi_awaddr <= axi_awaddr + ((M_AXI_AWLEN + 1) << M_AXI_AWSIZE);
// Verilator lint_on WIDTH
case(M_AXI_AWSIZE)
3'b000: begin end
3'b001: axi_awaddr[ 0] <= 0;
3'b010: axi_awaddr[1:0] <= 0;
3'b011: axi_awaddr[2:0] <= 0;
3'b100: axi_awaddr[3:0] <= 0;
3'b101: axi_awaddr[4:0] <= 0;
3'b110: axi_awaddr[5:0] <= 0;
3'b111: axi_awaddr[6:0] <= 0;
endcase
end
initial M_AXI_AWSIZE = ADDRLSB[2:0];
always @(posedge S_AXI_ACLK)
begin
if (awskd_valid && awskd_ready)
begin
axi_awid <= awskd_id;
axi_awsize <= awskd_size;
axi_awburst <= awskd_burst;
axi_awlock[0]<=awskd_lock;
axi_awcache <= awskd_cache;
axi_awprot <= awskd_prot;
axi_awqos <= awskd_qos;
end
if (C_AXI_DATA_WIDTH < 16)
axi_awsize <= 3'b000;
else if (C_AXI_DATA_WIDTH < 32)
axi_awsize[2:1] <= 2'b00;
else if (C_AXI_DATA_WIDTH < 128)
axi_awsize[2] <= 1'b0;
axi_awlock[1] <= 1'b0;
end
assign M_AXI_AWVALID = axi_awvalid;
assign M_AXI_AWID = axi_awid;
assign M_AXI_AWADDR = axi_awaddr;
assign M_AXI_AWLEN = axi_awlen;
assign M_AXI_AWSIZE = axi_awsize;
assign M_AXI_AWBURST = axi_awburst;
assign M_AXI_AWLOCK = axi_awlock;
assign M_AXI_AWCACHE = axi_awcache;
assign M_AXI_AWPROT = axi_awprot;
assign M_AXI_AWQOS = axi_awqos;
// }}}
////////////////////////////////////////////////////////////////////////
//
// Write data channel
// {{{
////////////////////////////////////////////////////////////////////////
//
//
wire wskd_valid;
reg wskd_ready, write_idle;
wire [C_AXI_DATA_WIDTH-1:0] wskd_data;
wire [C_AXI_DATA_WIDTH/8-1:0] wskd_strb;
wire wskd_last;
reg [4:0] r_wlen;
wire [C_AXI_ID_WIDTH-1:0] wfifo_id, raw_wfifo_id;
wire [3:0] wfifo_wlen, raw_wfifo_wlen;
reg next_wlast, r_wlast;
wire raw_wfifo_last;
wire wfifo_empty, wfifo_full;
wire [LGWFIFO:0] wfifo_fill;
reg axi_wvalid;
reg [C_AXI_DATA_WIDTH-1:0] axi_wdata;
reg [C_AXI_DATA_WIDTH/8-1:0] axi_wstrb;
reg [C_AXI_ID_WIDTH-1:0] axi_wid;
reg axi_wlast;
skidbuffer #(
.DW(C_AXI_DATA_WIDTH + (C_AXI_DATA_WIDTH/8) + 1),
.OPT_OUTREG(1'b0)
) wskid (
.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
.i_valid(S_AXI_WVALID), .o_ready(S_AXI_WREADY),
.i_data({ S_AXI_WDATA, S_AXI_WSTRB, S_AXI_WLAST }),
.o_valid(wskd_valid), .i_ready(wskd_ready),
.o_data({ wskd_data, wskd_strb, wskd_last })
);
always @(*)
wskd_ready = !M_AXI_WVALID || M_AXI_WREADY;
initial axi_wvalid = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
axi_wvalid <= 0;
else if (wskd_valid)
axi_wvalid <= 1;
else if (M_AXI_WREADY)
axi_wvalid <= 0;
initial write_idle = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
write_idle <= 1;
else if (M_AXI_WVALID && M_AXI_WREADY && M_AXI_WLAST && !wskd_valid)
write_idle <= 1;
else if (wskd_valid && wskd_ready)
write_idle <= 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN && OPT_LOWPOWER)
begin
axi_wdata <= 0;
axi_wstrb <= 0;
end else if (!M_AXI_WVALID || M_AXI_WREADY)
begin
axi_wdata <= wskd_data;
axi_wstrb <= wskd_strb;
if (OPT_LOWPOWER && !wskd_valid)
begin
axi_wdata <= 0;
axi_wstrb <= 0;
end
end
always @(*)
begin
if (r_awlen[7:4] != 0)
next_wlen = 4'd15;
else if (r_awlen[3:0] != 0)
next_wlen = r_awlen[3:0];
else if (awskd_len[7:4] != 0)
next_wlen = 4'd15;
else
next_wlen = awskd_len[3:0];
if (r_awlen != 0)
next_wlast = (r_awlen[7:4] == 0);
else
next_wlast = (awskd_len[7:4] == 0);
end
sfifo #(.BW(C_AXI_ID_WIDTH+4+1), .LGFLEN(LGWFIFO))
wfifo(S_AXI_ACLK, !S_AXI_ARESETN,
(!M_AXI_AWVALID || M_AXI_AWREADY)&&(awskd_valid||(r_awlen > 0))
&& !write_idle,
// The length of the next burst
{ ((r_awlen != 0) ? M_AXI_AWID : awskd_id),
next_wlen, next_wlast },
wfifo_full, wfifo_fill,
//
(!M_AXI_WVALID || M_AXI_WREADY),
{ raw_wfifo_id, raw_wfifo_wlen, raw_wfifo_last },
wfifo_empty);
assign wfifo_id = (wfifo_empty) ? awskd_id : raw_wfifo_id;
assign wfifo_wlen = (wfifo_empty) ? next_wlen : raw_wfifo_wlen;
initial r_wlen = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN && OPT_LOWPOWER)
r_wlen <= 0;
else if (!M_AXI_WVALID || M_AXI_WREADY)
begin
if (r_wlen > 1)
r_wlen <= r_wlen - 1;
else if (!wfifo_empty)
r_wlen <= raw_wfifo_wlen + 1;
else if (awskd_valid && awskd_ready)
r_wlen <= next_wlen + 1;
end
initial r_wlast = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN && OPT_LOWPOWER)
r_wlast <= 0;
else if (!M_AXI_WVALID || M_AXI_WREADY)
begin
if (r_wlen > 0)
r_wlast <= (r_wlen <= 1);
else
r_wlast <= raw_wfifo_last;
end
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN && OPT_LOWPOWER)
begin
axi_wid <= 0;
axi_wlast <= 0;
end else if (!M_AXI_WVALID || M_AXI_WREADY)
begin
axi_wid <= wfifo_id;
axi_wlast <= r_wlast;
if (OPT_LOWPOWER && !wskd_valid)
begin
axi_wid <= 0;
axi_wlast <= 0;
end
end
assign M_AXI_WVALID = axi_wvalid;
assign M_AXI_WDATA = axi_wdata;
assign M_AXI_WSTRB = axi_wstrb;
assign M_AXI_WID = axi_wid;
assign M_AXI_WLAST = axi_wlast;
// }}}
////////////////////////////////////////////////////////////////////////
//
// Write return channel
// {{{
////////////////////////////////////////////////////////////////////////
//
//
wire bskd_valid;
reg bskd_ready;
wire [C_AXI_ID_WIDTH-1:0] bskd_id;
wire [1:0] bskd_resp;
reg [1:0] bburst_err [0:NID-1];
reg [NID-1:0] wbfifo_valid;
reg [NID-1:0] wbfifo_last;
reg axi_bvalid;
reg [C_AXI_ID_WIDTH-1:0] axi_bid;
reg [1:0] axi_bresp;
skidbuffer #(.DW(C_AXI_ID_WIDTH + 2), .OPT_OUTREG(1'b0)
) bskid (
.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
.i_valid(M_AXI_BVALID), .o_ready(M_AXI_BREADY),
.i_data({ M_AXI_BID, M_AXI_BRESP }),
.o_valid(bskd_valid), .i_ready(bskd_ready),
.o_data({ bskd_id, bskd_resp })
);
generate for(ID=0; ID < NID; ID = ID + 1)
begin : WRITE_BURST_TRACKING
wire wbfifo_empty, wbfifo_full;
wire [LGFIFO:0] wbfifo_fill;
initial wbfifo_valid[ID] = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
wbfifo_valid[ID] <= 0;
else if (!wbfifo_valid[ID] && !wbfifo_empty)
wbfifo_valid[ID] <= 1;
else if (bskd_valid && bskd_ready && bskd_id==ID)
wbfifo_valid[ID] <= !wbfifo_empty;
sfifo #(.BW(1), .LGFLEN(LGFIFO))
wbfifo(S_AXI_ACLK, !S_AXI_ARESETN,
(M_AXI_WVALID && M_AXI_WREADY && M_AXI_WLAST)
&& (M_AXI_WID == ID),
(r_wlen == 0) ? 1'b1 : 1'b0,
wbfifo_full, wbfifo_fill,
//
(!wbfifo_valid[ID] || (M_AXI_BVALID && M_AXI_BREADY
&& M_AXI_BID == ID)),
wbfifo_last[ID], wbfifo_empty
);
// Verilator lint_off UNUSED
wire unused;
assign unused = &{ 1'b0, wbfifo_full, wbfifo_fill };
// Verilator lint_on UNUSED
end endgenerate
always @(*)
bskd_ready = (!S_AXI_BVALID || S_AXI_BREADY);
initial axi_bvalid = 1'b0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
axi_bvalid <= 1'b0;
else if (bskd_valid && bskd_ready)
axi_bvalid <= wbfifo_last[bskd_id];
else if (M_AXI_BREADY)
axi_bvalid <= 1'b0;
generate for(ID=0; ID < NID; ID = ID + 1)
begin : WRITE_ERR_BY_ID
initial bburst_err[ID] = 2'b0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
bburst_err[ID] <= 2'b0;
else if (S_AXI_BVALID && S_AXI_BREADY && S_AXI_BID == ID
&& wbfifo_last[ID])
bburst_err[ID] <= 2'b0;
else if (bskd_valid && bskd_id == ID)
bburst_err[ID] <= bburst_err[ID] | bskd_resp;
end endgenerate
initial axi_bid = 0;
initial axi_bresp = 0;
always @(posedge S_AXI_ACLK)
if (OPT_LOWPOWER && !S_AXI_ARESETN)
begin
axi_bid <= 0;
axi_bresp <= 0;
end else if (!S_AXI_BVALID || S_AXI_BREADY)
begin
axi_bid <= bskd_id;
axi_bresp <= bskd_resp | bburst_err[bskd_id];
if (OPT_LOWPOWER && !bskd_valid)
begin
axi_bid <= 0;
axi_bresp <= 0;
end
end
assign S_AXI_BVALID = axi_bvalid;
assign S_AXI_BID = axi_bid;
assign S_AXI_BRESP = axi_bresp;
// }}}
// }}}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//
// READ SIDE
// {{{
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//
// Read address channel
// {{{
////////////////////////////////////////////////////////////////////////
//
//
reg [7:0] r_arlen;
wire arskd_valid;
reg arskd_ready;
wire [C_AXI_ID_WIDTH-1:0] arskd_id;
wire [C_AXI_ADDR_WIDTH-1:0] arskd_addr;
wire [7:0] arskd_len;
wire [2:0] arskd_size;
wire [1:0] arskd_burst;
wire arskd_lock;
wire [3:0] arskd_cache;
wire [2:0] arskd_prot;
wire [3:0] arskd_qos;
reg axi_arvalid;
reg [C_AXI_ID_WIDTH-1:0] axi_arid;
reg [C_AXI_ADDR_WIDTH-1:0] axi_araddr;
reg [3:0] axi_arlen;
reg [2:0] axi_arsize;
reg [1:0] axi_arburst;
reg [1:0] axi_arlock;
reg [3:0] axi_arcache;
reg [2:0] axi_arprot;
reg [3:0] axi_arqos;
skidbuffer #(
.DW(C_AXI_ADDR_WIDTH + C_AXI_ID_WIDTH + 8 + 3 + 2 + 1+4+3+4),
.OPT_OUTREG(1'b0)
) arskid (
.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
.i_valid(S_AXI_ARVALID), .o_ready(S_AXI_ARREADY),
.i_data({ S_AXI_ARID, S_AXI_ARADDR, S_AXI_ARLEN,
S_AXI_ARSIZE, S_AXI_ARBURST, S_AXI_ARLOCK,
S_AXI_ARCACHE, S_AXI_ARPROT, S_AXI_ARQOS }),
.o_valid(arskd_valid), .i_ready(arskd_ready),
.o_data({ arskd_id, arskd_addr, arskd_len,
arskd_size, arskd_burst, arskd_lock,
arskd_cache, arskd_prot, arskd_qos })
);
always @(*)
begin
arskd_ready = 1;
if (r_arlen > 0)
arskd_ready = 0;
if (M_AXI_ARVALID && M_AXI_ARREADY)
arskd_ready = 0;
end
initial axi_arvalid = 1'b0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
axi_arvalid <= 1'b0;
else if (r_arlen > 0)
axi_arvalid <= 1'b1;
else if (arskd_ready)
axi_arvalid <= 1'b1;
else if (M_AXI_ARREADY)
axi_arvalid <= 1'b0;
initial r_arlen = 0;
initial M_AXI_ARLEN = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
begin
r_arlen <= 0;
axi_arlen <= 0;
end else if (!M_AXI_ARVALID || M_AXI_ARREADY)
begin
if (r_arlen[7:4] != 0)
begin
axi_arlen <= 4'd15;
r_arlen <= r_arlen - 16;
end else if (r_arlen[3:0] != 0)
begin
axi_arlen <= r_arlen[3:0] - 1;
r_arlen <= 0;
end else if (arskd_valid)
begin
if (arskd_len[7:4] != 0)
begin
r_arlen <= arskd_len + 1 - 16;
axi_arlen <= 4'd15;
end else begin
r_arlen <= 0;
axi_arlen <= arskd_len[3:0];
end
end else begin
r_arlen <= 0;
axi_arlen <= 0;
end
end
always @(posedge S_AXI_ACLK)
if (arskd_valid && arskd_ready)
axi_araddr <= arskd_addr;
else if (M_AXI_ARVALID && M_AXI_ARREADY)
begin
// Verilator lint_off WIDTH
axi_araddr <= axi_araddr + ((M_AXI_ARLEN + 1) << M_AXI_ARSIZE);
// Verilator lint_on WIDTH
case(M_AXI_AWSIZE)
3'b000: begin end
3'b001: axi_araddr[ 0] <= 0;
3'b010: axi_araddr[1:0] <= 0;
3'b011: axi_araddr[2:0] <= 0;
3'b100: axi_araddr[3:0] <= 0;
3'b101: axi_araddr[4:0] <= 0;
3'b110: axi_araddr[5:0] <= 0;
3'b111: axi_araddr[6:0] <= 0;
endcase
end
initial axi_arsize = ADDRLSB[2:0];
always @(posedge S_AXI_ACLK)
begin
if (arskd_valid && arskd_ready)
begin
axi_arid <= arskd_id;
axi_arsize <= arskd_size;
axi_arburst <= arskd_burst;
axi_arlock[0] <= arskd_lock;
axi_arcache <= arskd_cache;
axi_arprot <= arskd_prot;
axi_arqos <= arskd_qos;
end
// Propagate constants, to help the optimizer out out a touch
axi_arlock[1] <= 1'b0;
if (C_AXI_DATA_WIDTH < 16)
axi_arsize <= 3'b000;
else if (C_AXI_DATA_WIDTH < 32)
axi_arsize[2:1] <= 2'b00;
else if (C_AXI_DATA_WIDTH < 128)
axi_arsize[2] <= 1'b0;
end
generate for(ID=0; ID < NID; ID = ID + 1)
begin : READ_BURST_TRACKING
wire rbfifo_empty, rbfifo_full;
wire [LGFIFO:0] rbfifo_fill;
initial rbfifo_valid[ID] = 0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
rbfifo_valid[ID] <= 0;
else if (!rbfifo_valid[ID] && !rbfifo_empty)
rbfifo_valid[ID] <= 1;
else if (rskd_valid && rskd_ready && rskd_last && rskd_id==ID)
rbfifo_valid[ID] <= !rbfifo_empty;
sfifo #(.BW(1), .LGFLEN(LGFIFO))
rbfifo(S_AXI_ACLK, !S_AXI_ARESETN,
(!M_AXI_ARVALID || M_AXI_ARREADY)
&& (((r_arlen>0)&&(M_AXI_ARID==ID))
|| (arskd_valid && arskd_id == ID)),
((arskd_valid && arskd_ready && arskd_len <= 15)
||(r_arlen <= 15)) ? 1'b1 : 1'b0,
rbfifo_full, rbfifo_fill,
//
(!rbfifo_valid[ID] || (M_AXI_RVALID && M_AXI_RREADY
&& M_AXI_RID == ID && M_AXI_RLAST)),
rid_last[ID], rbfifo_empty
);
// Verilator lint_off UNUSED
wire unused;
assign unused = &{ 1'b0, rbfifo_full, rbfifo_fill };
// Verilator lint_on UNUSED
end endgenerate
assign M_AXI_ARVALID= axi_arvalid;
assign M_AXI_ARID = axi_arid;
assign M_AXI_ARADDR = axi_araddr;
assign M_AXI_ARLEN = axi_arlen;
assign M_AXI_ARSIZE = axi_arsize;
assign M_AXI_ARBURST= axi_arburst;
assign M_AXI_ARLOCK = axi_arlock;
assign M_AXI_ARCACHE= axi_arcache;
assign M_AXI_ARPROT = axi_arprot;
assign M_AXI_ARQOS = axi_arqos;
// }}}
////////////////////////////////////////////////////////////////////////
//
// Read data channel
// {{{
////////////////////////////////////////////////////////////////////////
//
//
wire rskd_valid;
reg rskd_ready;
wire [C_AXI_ID_WIDTH-1:0] rskd_id;
wire [C_AXI_DATA_WIDTH-1:0] rskd_data;
wire rskd_last;
wire [1:0] rskd_resp;
reg [1:0] rburst_err [0:NID-1];
reg [NID-1:0] rbfifo_valid;
reg [NID-1:0] rid_last;
reg axi_rvalid;
reg [C_AXI_ID_WIDTH-1:0] axi_rid;
reg [C_AXI_DATA_WIDTH-1:0] axi_rdata;
reg axi_rlast;
reg [1:0] axi_rresp;
skidbuffer #(
.DW(C_AXI_DATA_WIDTH + C_AXI_ID_WIDTH + 3),
.OPT_OUTREG(1'b0)
) rskid (
.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
.i_valid(M_AXI_RVALID), .o_ready(M_AXI_RREADY),
.i_data({ M_AXI_RID, M_AXI_RDATA, M_AXI_RLAST,
M_AXI_RRESP }),
.o_valid(rskd_valid), .i_ready(rskd_ready),
.o_data({ rskd_id, rskd_data, rskd_last, rskd_resp })
);
always @(*)
rskd_ready = !S_AXI_RVALID || S_AXI_RREADY;
initial axi_rvalid = 1'b0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
axi_rvalid <= 1'b0;
else if (rskd_valid && rskd_ready)
axi_rvalid <= 1'b1;
else if (S_AXI_RREADY)
axi_rvalid <= 1'b0;
generate for(ID=0; ID < NID; ID = ID + 1)
begin : READ_ERR_BY_ID
initial rburst_err[ID] = 2'b0;
always @(posedge S_AXI_ACLK)
if (!S_AXI_ARESETN)
rburst_err[ID] <= 2'b0;
else if (S_AXI_RVALID && S_AXI_RREADY && S_AXI_RLAST
&& S_AXI_RID == ID)
rburst_err[ID] <= 2'b0;
else if (rskd_valid && rskd_id == ID)
rburst_err[ID] <= rburst_err[ID] | rskd_resp;
end endgenerate
always @(posedge S_AXI_ACLK)
if (!S_AXI_RVALID || S_AXI_RREADY)
begin
axi_rid <= rskd_id;
axi_rdata <= rskd_data;
axi_rresp <= rskd_resp | rburst_err[rskd_id];
axi_rlast <= rid_last[rskd_id] && rskd_last;
end
assign S_AXI_RVALID= axi_rvalid;
assign S_AXI_RID = axi_rid;
assign S_AXI_RDATA = axi_rdata;
assign S_AXI_RRESP = axi_rresp;
assign S_AXI_RLAST = axi_rlast;
// }}}
// }}}
// Make Verilator happy
// {{{
// Verilator lint_off UNUSED
wire unused;
assign unused = &{ 1'b0, wfifo_fill[LGWFIFO-2:0], wskd_last,
wfifo_wlen, wfifo_full };
// Verilator lint_on UNUSED
// }}}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
// Formal property section
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
`ifdef FORMAL
//
// This design has not been formally verified.
//
`endif
endmodule