summaryrefslogtreecommitdiff
path: root/rtl/wb2axip/axi32axi.v
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/wb2axip/axi32axi.v')
-rw-r--r--rtl/wb2axip/axi32axi.v376
1 files changed, 376 insertions, 0 deletions
diff --git a/rtl/wb2axip/axi32axi.v b/rtl/wb2axip/axi32axi.v
new file mode 100644
index 0000000..fd1badb
--- /dev/null
+++ b/rtl/wb2axip/axi32axi.v
@@ -0,0 +1,376 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: axi32axi.v
+// {{{
+// Project: WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose: Bridge from an AXI3 slave to an AXI4 master
+//
+// The goal here is to support as high a bus speed as possible, maintain
+// burst support (if possible) and (more important) allow bus requests
+// coming from the ARM within either the Zynq or one of Intel's SOC chips
+// to speak with an AutoFPGA based design.
+//
+// Note that if you aren't using AutoFPGA, then you probably don't need
+// this core--the vendor tools should be able to handle this conversion
+// quietly and automatically for you.
+//
+// Notes:
+// AxCACHE is remapped as per the AXI4 specification, since the values
+// aren't truly equivalent. This forces a single clock delay in the Ax*
+// channels and (likely) the W* channel as well as a system level
+// consequence.
+//
+// AXI3 locking is not supported under AXI4. As per the AXI4 spec,
+// AxLOCK is converteted from AXI3 to AXI4 by just dropping the high
+// order bit.
+//
+// The WID input is ignored. Whether or not this input can be ignored
+// is based upon how the ARM is implemented internally. After a bit
+// of research into both Zynq's and Intel SOCs, this appears to be the
+// appropriate answer here.
+//
+// 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 axi32axi #(
+ // {{{
+ parameter C_AXI_ID_WIDTH = 1,
+ parameter C_AXI_ADDR_WIDTH = 32,
+ parameter C_AXI_DATA_WIDTH = 32,
+ parameter OPT_REORDER_METHOD = 0,
+ parameter [0:0] OPT_TRANSFORM_AXCACHE = 1,
+ parameter [0:0] OPT_LOWPOWER = 0,
+ parameter [0:0] OPT_LOW_LATENCY = 0,
+ parameter WID_LGAWFIFO = 3,
+ parameter WID_LGWFIFO = 3
+ //
+ // }}}
+ ) (
+ // {{{
+ input wire S_AXI_ACLK,
+ input wire S_AXI_ARESETN,
+ //
+ // The AXI3 incoming/slave interface
+ input wire S_AXI_AWVALID,
+ output wire S_AXI_AWREADY,
+ input wire [C_AXI_ID_WIDTH-1:0] S_AXI_AWID,
+ input wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_AWADDR,
+ input wire [3:0] S_AXI_AWLEN,
+ input wire [2:0] S_AXI_AWSIZE,
+ input wire [1:0] S_AXI_AWBURST,
+ input wire [1:0] 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 S_AXI_WVALID,
+ output wire S_AXI_WREADY,
+ input wire [C_AXI_ID_WIDTH-1:0] S_AXI_WID,
+ 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 [3:0] S_AXI_ARLEN,
+ input wire [2:0] S_AXI_ARSIZE,
+ input wire [1:0] S_AXI_ARBURST,
+ input wire [1:0] 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 AXI4 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 [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 M_AXI_WVALID,
+ input wire M_AXI_WREADY,
+ 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 [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,
+ //
+ 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
+ // }}}
+ );
+
+ // Register/net declarations
+ // {{{
+ // localparam ADDRLSB= $clog2(C_AXI_DATA_WIDTH)-3;
+ localparam IW=C_AXI_ID_WIDTH;
+ reg [3:0] axi4_awcache, axi4_arcache;
+ reg axi4_awlock, axi4_arlock;
+ wire awskd_ready;
+ wire wid_reorder_awready;
+ wire [IW-1:0] reordered_wid;
+ // }}}
+
+ // Write cache remapping
+ // {{{
+ always @(*)
+ case(S_AXI_AWCACHE)
+ 4'b1010: axi4_awcache = 4'b1110;
+ 4'b1011: axi4_awcache = 4'b1111;
+ default: axi4_awcache = S_AXI_AWCACHE;
+ endcase
+ // }}}
+
+ // AWLOCK
+ // {{{
+ always @(*)
+ axi4_awlock = S_AXI_AWLOCK[0];
+ // }}}
+
+ // AW Skid buffer
+ // {{{
+ generate if (OPT_TRANSFORM_AXCACHE)
+ begin : GEN_AWCACHE
+ // {{{
+ skidbuffer #(
+ .DW(C_AXI_ADDR_WIDTH + C_AXI_ID_WIDTH
+ + 4 + 3 + 2 + 1+4+3+4),
+ .OPT_OUTREG(1'b1)
+ ) awskid (
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_valid(S_AXI_AWVALID && wid_reorder_awready),
+ .o_ready(awskd_ready),
+ .i_data({ S_AXI_AWID, S_AXI_AWADDR, S_AXI_AWLEN,
+ S_AXI_AWSIZE, S_AXI_AWBURST,axi4_awlock,
+ axi4_awcache, S_AXI_AWPROT, S_AXI_AWQOS
+ }),
+ .o_valid(M_AXI_AWVALID), .i_ready(M_AXI_AWREADY),
+ .o_data({ M_AXI_AWID, M_AXI_AWADDR,
+ M_AXI_AWLEN[3:0],
+ M_AXI_AWSIZE,M_AXI_AWBURST,M_AXI_AWLOCK,
+ M_AXI_AWCACHE,M_AXI_AWPROT, M_AXI_AWQOS
+ })
+ );
+
+ assign M_AXI_AWLEN[7:4] = 4'h0;
+ assign S_AXI_AWREADY = awskd_ready && wid_reorder_awready;
+ // }}}
+ end else begin : IGN_AWCACHE
+ // {{{
+ assign M_AXI_AWVALID = S_AXI_AWVALID && wid_reorder_awready;
+ assign S_AXI_AWREADY = M_AXI_AWREADY;
+ assign M_AXI_AWID = S_AXI_AWID;
+ assign M_AXI_AWADDR = S_AXI_AWADDR;
+ assign M_AXI_AWLEN = { 4'h0, S_AXI_AWLEN };
+ assign M_AXI_AWSIZE = S_AXI_AWSIZE;
+ assign M_AXI_AWBURST = S_AXI_AWBURST;
+ assign M_AXI_AWLOCK = axi4_awlock;
+ assign M_AXI_AWCACHE = axi4_awcache;
+ assign M_AXI_AWPROT = S_AXI_AWPROT;
+ assign M_AXI_AWQOS = S_AXI_AWQOS;
+
+ assign awskd_ready = 1;
+ // }}}
+ end endgenerate
+ // }}}
+
+ // Handle write channel de-interleaving
+ // {{{
+ axi3reorder #(
+ // {{{
+ .C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+ .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+ .OPT_METHOD(OPT_REORDER_METHOD),
+ .OPT_LOWPOWER(OPT_LOWPOWER),
+ .OPT_LOW_LATENCY(OPT_LOW_LATENCY),
+ .LGAWFIFO(WID_LGAWFIFO),
+ .LGWFIFO(WID_LGWFIFO)
+ // }}}
+ ) widreorder (
+ // {{{
+ .S_AXI_ACLK(S_AXI_ACLK), .S_AXI_ARESETN(S_AXI_ARESETN),
+ // Incoming Write address ID
+ .S_AXI3_AWVALID(S_AXI_AWVALID && S_AXI_AWREADY),
+ .S_AXI3_AWREADY(wid_reorder_awready),
+ .S_AXI3_AWID(S_AXI_AWID),
+ // Incoming Write data info
+ .S_AXI3_WVALID(S_AXI_WVALID),
+ .S_AXI3_WREADY(S_AXI_WREADY),
+ .S_AXI3_WID(S_AXI_WID),
+ .S_AXI3_WDATA(S_AXI_WDATA),
+ .S_AXI3_WSTRB(S_AXI_WSTRB),
+ .S_AXI3_WLAST(S_AXI_WLAST),
+ // Outgoing write data channel
+ .M_AXI_WVALID(M_AXI_WVALID),
+ .M_AXI_WREADY(M_AXI_WREADY),
+ .M_AXI_WID(reordered_wid),
+ .M_AXI_WDATA(M_AXI_WDATA),
+ .M_AXI_WSTRB(M_AXI_WSTRB),
+ .M_AXI_WLAST(M_AXI_WLAST)
+ // }}}
+ );
+ // }}}
+
+ // Forward the B* channel return
+ // {{{
+ assign S_AXI_BVALID = M_AXI_BVALID;
+ assign M_AXI_BREADY = S_AXI_BREADY;
+ assign S_AXI_BID = M_AXI_BID;
+ assign S_AXI_BRESP = M_AXI_BRESP;
+ // }}}
+
+ // Read cache remapping
+ // {{{
+ always @(*)
+ case(S_AXI_ARCACHE)
+ 4'b0110: axi4_arcache = 4'b1110;
+ 4'b0111: axi4_arcache = 4'b1111;
+ default: axi4_arcache = S_AXI_ARCACHE;
+ endcase
+ // }}}
+
+ // ARLOCK
+ // {{{
+ always @(*)
+ axi4_arlock = S_AXI_ARLOCK[0];
+ // }}}
+
+ // AR Skid buffer
+ // {{{
+ generate if (OPT_TRANSFORM_AXCACHE)
+ begin : GEN_ARCACHE
+ // {{{
+ skidbuffer #(
+ .DW(C_AXI_ADDR_WIDTH + C_AXI_ID_WIDTH
+ + 4 + 3 + 2 + 1+4+3+4),
+ .OPT_OUTREG(1'b1)
+ ) 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, axi4_arlock,
+ axi4_arcache, S_AXI_ARPROT, S_AXI_ARQOS }),
+ .o_valid(M_AXI_ARVALID), .i_ready(M_AXI_ARREADY),
+ .o_data({ M_AXI_ARID, M_AXI_ARADDR, M_AXI_ARLEN[3:0],
+ M_AXI_ARSIZE, M_AXI_ARBURST, M_AXI_ARLOCK,
+ M_AXI_ARCACHE, M_AXI_ARPROT, M_AXI_ARQOS })
+ );
+
+ assign M_AXI_ARLEN[7:4] = 4'h0;
+ // }}}
+ end else begin : IGN_ARCACHE
+ // {{{
+ assign M_AXI_ARVALID = S_AXI_ARVALID;
+ assign S_AXI_ARREADY = M_AXI_ARREADY;
+ assign M_AXI_ARID = S_AXI_ARID;
+ assign M_AXI_ARADDR = S_AXI_ARADDR;
+ assign M_AXI_ARLEN = { 4'h0, S_AXI_ARLEN };
+ assign M_AXI_ARSIZE = S_AXI_ARSIZE;
+ assign M_AXI_ARBURST = S_AXI_ARBURST;
+ assign M_AXI_ARLOCK = axi4_arlock;
+ assign M_AXI_ARCACHE = axi4_arcache;
+ assign M_AXI_ARPROT = S_AXI_ARPROT;
+ assign M_AXI_ARQOS = S_AXI_ARQOS;
+ // }}}
+ end endgenerate
+ // }}}
+
+ // Forward the R* channel return
+ // {{{
+ assign S_AXI_RVALID = M_AXI_RVALID;
+ assign M_AXI_RREADY = S_AXI_RREADY;
+ assign S_AXI_RID = M_AXI_RID;
+ assign S_AXI_RDATA = M_AXI_RDATA;
+ assign S_AXI_RLAST = M_AXI_RLAST;
+ assign S_AXI_RRESP = M_AXI_RRESP;
+ // }}}
+
+ // Verilator lint_off UNUSED
+ wire unused;
+ assign unused = &{ 1'b0, S_AXI_AWLOCK[1], S_AXI_ARLOCK[1],
+ reordered_wid };
+ // Verilator lint_on UNUSED
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal property section
+//
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef FORMAL
+//
+// This design has not been formally verified.
+//
+`endif
+endmodule