diff options
| author | Alejandro Soto <alejandro@34project.org> | 2024-03-06 02:38:24 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2024-03-06 02:38:24 -0600 |
| commit | 3038edc09a2eb15762f2e58533f429489107520b (patch) | |
| tree | f7a45e424d39e6fef0d59e329c1bf6ea206e2886 /rtl/wb2axip/axi2axi3.v | |
| parent | 3b62399f92e9faa2602ac30865e5fc3c7c4e12b8 (diff) | |
rtl/wb2axip: add to version control
Diffstat (limited to 'rtl/wb2axip/axi2axi3.v')
| -rw-r--r-- | rtl/wb2axip/axi2axi3.v | 897 |
1 files changed, 897 insertions, 0 deletions
diff --git a/rtl/wb2axip/axi2axi3.v b/rtl/wb2axip/axi2axi3.v new file mode 100644 index 0000000..3682949 --- /dev/null +++ b/rtl/wb2axip/axi2axi3.v @@ -0,0 +1,897 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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-2024, 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 + // }}} + ) ( + // {{{ + 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 ADDRLSB= $clog2(C_AXI_DATA_WIDTH)-3; + 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 |
