diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_Addr_Translator.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_Addr_Translator.bsv
index 241024d..8513fbd 100644
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_Addr_Translator.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4/AXI4_Addr_Translator.bsv
@@ -1,4 +1,5 @@
// Copyright (c) 2020 Bluespec, Inc. All Rights Reserved
+// Copyright (c) 2024 Rishiyur S. Nikhil.
//
// SPDX-License-Identifier: BSD-3-Clause
@@ -8,6 +9,8 @@ package AXI4_Addr_Translator;
// This package defines transformers for AXI4_M and AXI4_S interfaces
// that perform a simple 'address-translator' (add/subtract a fixed
// constant from address).
+// Each transformer copies AW and AR, just adjusting the address,
+// and just copies W, B and R.
// ================================================================
// Bluespec library imports
@@ -15,169 +18,139 @@ package AXI4_Addr_Translator;
// none
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
-// none
+import Semi_FIFOF :: *;
// ================================================================
// Project imports
-import AXI4_Types :: *;
+import AXI4_Types :: *;
// ================================================================
-// M-to-M interface transformer with address translation
+// M-to-M interface transformer with address translation.
-function AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user)
- fv_AXI4_M_Address_Translator (Bool add_not_sub,
- Bit #(wd_addr) addr_delta,
- AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user) ifc);
+function AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user)
+ fv_AXI4_M_Address_Translator (Bool add_not_sub,
+ Bit #(wd_addr) addr_delta,
+ AXI4_M_IFC #(wd_id,
+ wd_addr,
+ wd_data,
+ wd_user) ifc_M);
function Bit #(wd_addr) fv_addr_translate (Bit #(wd_addr) addr);
return (add_not_sub ? addr + addr_delta : addr - addr_delta);
endfunction
return interface AXI4_M_IFC
- // Wr Addr channel
- method Bool m_awvalid = ifc.m_awvalid; // out
- method Bit #(wd_id) m_awid = ifc.m_awid; // out
- method Bit #(wd_addr) m_awaddr = fv_addr_translate (ifc.m_awaddr); // out
- method Bit #(8) m_awlen = ifc.m_awlen; // out
- method AXI4_Size m_awsize = ifc.m_awsize; // out
- method Bit #(2) m_awburst = ifc.m_awburst; // out
- method Bit #(1) m_awlock = ifc.m_awlock; // out
- method Bit #(4) m_awcache = ifc.m_awcache; // out
- method Bit #(3) m_awprot = ifc.m_awprot; // out
- method Bit #(4) m_awqos = ifc.m_awqos; // out
- method Bit #(4) m_awregion = ifc.m_awregion; // out
- method Bit #(wd_user) m_awuser = ifc.m_awuser; // out
- method Action m_awready (Bool awready) = ifc.m_awready (awready); // in
-
- // Wr Data channel
- method Bool m_wvalid = ifc.m_wvalid; // out
- method Bit #(wd_data) m_wdata = ifc.m_wdata; // out
- method Bit #(TDiv #(wd_data, 8)) m_wstrb = ifc.m_wstrb; // out
- method Bool m_wlast = ifc.m_wlast; // out
- method Bit #(wd_user) m_wuser = ifc.m_wuser; // out
-
- method Action m_wready (Bool wready) = ifc.m_wready (wready); // in
-
- // Wr Response channel
- method Action m_bvalid (Bool bvalid, // in
- Bit #(wd_id) bid, // in
- Bit #(2) bresp, // in
- Bit #(wd_user) buser); // in
- ifc.m_bvalid (bvalid, bid, bresp, buser);
- endmethod
- method Bool m_bready = ifc.m_bready; // out
-
- // Rd Addr channel
- method Bool m_arvalid = ifc.m_arvalid; // out
- method Bit #(wd_id) m_arid = ifc.m_arid; // out
- method Bit #(wd_addr) m_araddr = fv_addr_translate (ifc.m_araddr); // out
- method Bit #(8) m_arlen = ifc.m_arlen; // out
- method AXI4_Size m_arsize = ifc.m_arsize; // out
- method Bit #(2) m_arburst = ifc.m_arburst; // out
- method Bit #(1) m_arlock = ifc.m_arlock; // out
- method Bit #(4) m_arcache = ifc.m_arcache; // out
- method Bit #(3) m_arprot = ifc.m_arprot; // out
- method Bit #(4) m_arqos = ifc.m_arqos; // out
- method Bit #(4) m_arregion = ifc.m_arregion; // out
- method Bit #(wd_user) m_aruser = ifc.m_aruser; // out
- method Action m_arready (Bool arready) = ifc.m_arready (arready); // in
-
- // Rd Data channel
- method Action m_rvalid (Bool rvalid, // in
- Bit #(wd_id) rid, // in
- Bit #(wd_data) rdata, // in
- Bit #(2) rresp, // in
- Bool rlast, // in
- Bit #(wd_user) ruser); // in
- ifc.m_rvalid (rvalid, rid, rdata, rresp, rlast, ruser);
- endmethod
- method Bool m_rready = ifc.m_rready; // out
+ interface FIFOF_O o_AW;
+ method first;
+ let aw_in = ifc_M.o_AW.first;
+ let aw_out = AXI4_AW {awid: aw_in.awid,
+ awaddr: fv_addr_translate (aw_in.awaddr),
+ awlen: aw_in.awlen,
+ awsize: aw_in.awsize,
+ awburst: aw_in.awburst,
+ awlock: aw_in.awlock,
+ awcache: aw_in.awcache,
+ awprot: aw_in.awprot,
+ awqos: aw_in.awqos,
+ awregion: aw_in.awregion,
+ awuser: aw_in.awuser};
+ return aw_out;
+ endmethod
+ method deq = ifc_M.o_AW.deq;
+ method notEmpty = ifc_M.o_AW.notEmpty;
+ endinterface
+
+ interface FIFOF_I o_W = ifc_M.o_W;
+
+ interface FIFOF_I i_B = ifc_M.i_B;
+
+ interface FIFOF_O o_AR;
+ method first;
+ let ar_in = ifc_M.o_AR.first;
+ let ar_out = AXI4_AR {arid: ar_in.arid,
+ araddr: fv_addr_translate (ar_in.araddr),
+ arlen: ar_in.arlen,
+ arsize: ar_in.arsize,
+ arburst: ar_in.arburst,
+ arlock: ar_in.arlock,
+ arcache: ar_in.arcache,
+ arprot: ar_in.arprot,
+ arqos: ar_in.arqos,
+ arregion: ar_in.arregion,
+ aruser: ar_in.aruser};
+ return ar_out;
+ endmethod
+ method deq = ifc_M.o_AR.deq;
+ method notEmpty = ifc_M.o_AR.notEmpty;
+ endinterface
+
+ interface FIFOF_I i_R = ifc_M.i_R;
endinterface;
endfunction
// ================================================================
// S-to-S interface transformer with address translation
-function AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user)
- fv_AXI4_S_Address_Translator (Bool add_not_sub,
- Bit #(wd_addr) addr_delta,
- AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user) ifc);
+function AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user)
+ fv_AXI4_S_Address_Translator (Bool add_not_sub,
+ Bit #(wd_addr) addr_delta,
+ AXI4_S_IFC #(wd_id,
+ wd_addr,
+ wd_data,
+ wd_user) ifc_S);
function Bit #(wd_addr) fv_addr_translate (Bit #(wd_addr) addr);
return (add_not_sub ? addr + addr_delta : addr - addr_delta);
endfunction
return interface AXI4_S_IFC
- // Wr Addr channel
- method Action m_awvalid (Bool awvalid,
- Bit #(wd_id) awid,
- Bit #(wd_addr) awaddr,
- Bit #(8) awlen,
- AXI4_Size awsize,
- Bit #(2) awburst,
- Bit #(1) awlock,
- Bit #(4) awcache,
- Bit #(3) awprot,
- Bit #(4) awqos,
- Bit #(4) awregion,
- Bit #(wd_user) awuser);
- ifc.m_awvalid (awvalid, awid,
- fv_addr_translate (awaddr),
- awlen, awsize, awburst,
- awlock, awcache, awprot, awqos, awregion, awuser);
- endmethod
- method Bool m_awready = ifc.m_awready;
-
- // Wr Data channel
- method Action m_wvalid (Bool wvalid,
- Bit #(wd_data) wdata,
- Bit #(TDiv #(wd_data, 8)) wstrb,
- Bool wlast,
- Bit #(wd_user) wuser);
- ifc.m_wvalid (wvalid, wdata, wstrb, wlast, wuser);
- endmethod
- method Bool m_wready = ifc.m_wready;
-
- // Wr Response channel
- method Bool m_bvalid = ifc.m_bvalid;
- method Bit #(wd_id) m_bid = ifc.m_bid;
- method Bit #(2) m_bresp = ifc.m_bresp;
- method Bit #(wd_user) m_buser = ifc.m_buser;
- method Action m_bready (Bool bready) = ifc.m_bready (bready);
-
- // Rd Addr channel
- method Action m_arvalid (Bool arvalid,
- Bit #(wd_id) arid,
- Bit #(wd_addr) araddr,
- Bit #(8) arlen,
- AXI4_Size arsize,
- Bit #(2) arburst,
- Bit #(1) arlock,
- Bit #(4) arcache,
- Bit #(3) arprot,
- Bit #(4) arqos,
- Bit #(4) arregion,
- Bit #(wd_user) aruser);
- ifc.m_arvalid (arvalid, arid,
- fv_addr_translate (araddr),
- arlen, arsize, arburst,
- arlock, arcache, arprot, arqos, arregion, aruser);
- endmethod
- method Bool m_arready = ifc.m_arready;
-
- // Rd Data channel
- method Bool m_rvalid = ifc.m_rvalid;
- method Bit #(wd_id) m_rid = ifc.m_rid;
- method Bit #(wd_data) m_rdata = ifc.m_rdata;
- method Bit #(2) m_rresp = ifc.m_rresp;
- method Bool m_rlast = ifc.m_rlast;
- method Bit #(wd_user) m_ruser = ifc.m_ruser;
- method Action m_rready (Bool rready);
- ifc.m_rready (rready);
- endmethod
+ interface FIFOF_I i_AW;
+ method Action enq (AXI4_AW #(wd_id, wd_addr, wd_user) aw_in);
+ action
+ let aw_out = AXI4_AW {awid: aw_in.awid,
+ awaddr: fv_addr_translate (aw_in.awaddr),
+ awlen: aw_in.awlen,
+ awsize: aw_in.awsize,
+ awburst: aw_in.awburst,
+ awlock: aw_in.awlock,
+ awcache: aw_in.awcache,
+ awprot: aw_in.awprot,
+ awqos: aw_in.awqos,
+ awregion: aw_in.awregion,
+ awuser: aw_in.awuser};
+ ifc_S.i_AW.enq (aw_out);
+ endaction
+ endmethod
+ method notFull = ifc_S.i_AW.notFull;
+ endinterface
+
+ interface FIFOF_I i_W = ifc_S.i_W;
+ interface FIFOF_O o_B = ifc_S.o_B;
+
+ interface FIFOF_I i_AR;
+ method Action enq (AXI4_AR #(wd_id, wd_addr, wd_user) ar_in);
+ action
+ let ar_out = AXI4_AR {arid: ar_in.arid,
+ araddr: fv_addr_translate (ar_in.araddr),
+ arlen: ar_in.arlen,
+ arsize: ar_in.arsize,
+ arburst: ar_in.arburst,
+ arlock: ar_in.arlock,
+ arcache: ar_in.arcache,
+ arprot: ar_in.arprot,
+ arqos: ar_in.arqos,
+ arregion: ar_in.arregion,
+ aruser: ar_in.aruser};
+ ifc_S.i_AR.enq (ar_out);
+ endaction
+ endmethod
+ method notFull = ifc_S.i_AR.notFull;
+ endinterface
+
+ interface FIFOF_O o_R = ifc_S.o_R;
endinterface;
endfunction
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_BSV_RTL.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_BSV_RTL.bsv
new file mode 100644
index 0000000..4b890d9
--- /dev/null
+++ b/Libraries/AMBA_Fabrics/AXI4/AXI4_BSV_RTL.bsv
@@ -0,0 +1,1065 @@
+// Copyright (c) 2019-2023 Bluespec, Inc. All Rights Reserved
+// Copyright (c) 2024 Rishiyur S. Nikhil.
+
+// SPDX-License-Identifier: BSD-3-Clause
+
+package AXI4_BSV_RTL;
+
+// ****************************************************************
+// ****************************************************************
+
+// This package provides facilities for AXI4 connections between BSV
+// and RTL:
+
+// BSV: AW,W,B,AR,R are bit-vectors but always viewed as structs,
+// whose fields correspond to AXI4 sub-buses.
+// Some of those fields are always viewed as enums
+// Communication is via FIFOs.
+
+// RTL: AW,W,B,AR,R are buses, with named sub-buses.
+// Communication is via handshake on two more wires per bus:
+// ready,valid
+
+// Transactors ("xactors") are buffers to cross the BSV-RTL boundary
+// The BSV side uses standard BSV FIFO interfaces.
+// The RTL side uses standard AMBA signaling, allowing it to connect
+// to any AXI IP written in RTL or in BSV.
+//
+// Two kinds of transactors
+// (in both cases "x_to_y" means to connect an M to an S
+//
+// +----------------------------+
+// | AXI4_BSV_to_RTL |
+// BSV |AXI4_S_IFC AXI4_RTL_M_IFC| RTL
+// M <---> |ifc_S rtl_M|<--> S
+// +----------------------------+
+//
+// +----------------------------+
+// | AXI4_RTL_to_BSV |
+// RTL |AXI4_RTL_S_IFC AXI4_M_IFC| BSV
+// M <---> |rtl_S ifc_M|<--> S
+// +----------------------------+
+//
+// ****************************************************************
+// ****************************************************************
+// BSV library imports
+
+import FIFOF :: *;
+import Connectable :: *;
+
+// ----------------
+// Bluespec misc. libs
+
+import Semi_FIFOF :: *;
+import EdgeFIFOFs :: *;
+
+// ----------------
+// Project imports
+
+import AXI4_Types :: *;
+
+// ****************************************************************
+// ****************************************************************
+// Section: Interfaces with standard AMBA RTL-level signaling
+// (ready/valid handshakes, standard AMBA signal names)
+
+// ================================================================
+// These are the signal-level interfaces for an AXI4 M.
+// The (*..*) attributes ensure that when bsc compiles this to Verilog,
+// we get exactly the signals specified in the ARM spec.
+
+interface AXI4_RTL_M_IFC #(numeric type wd_id,
+ numeric type wd_addr,
+ numeric type wd_data,
+ numeric type wd_user);
+ // ----------------
+ // Wr Addr channel
+ (* always_ready, result="awvalid" *) method Bool m_awvalid; // out
+
+ (* always_ready, result="awid" *) method Bit #(wd_id) m_awid; // out
+ (* always_ready, result="awaddr" *) method Bit #(wd_addr) m_awaddr; // out
+ (* always_ready, result="awlen" *) method Bit #(8) m_awlen; // out
+ (* always_ready, result="awsize" *) method AXI4_Size m_awsize; // out
+ (* always_ready, result="awburst" *) method Bit #(2) m_awburst; // out
+ (* always_ready, result="awlock" *) method Bit #(1) m_awlock; // out
+ (* always_ready, result="awcache" *) method Bit #(4) m_awcache; // out
+ (* always_ready, result="awprot" *) method Bit #(3) m_awprot; // out
+ (* always_ready, result="awqos" *) method Bit #(4) m_awqos; // out
+ (* always_ready, result="awregion" *) method Bit #(4) m_awregion; // out
+ (* always_ready, result="awuser" *) method Bit #(wd_user) m_awuser; // out
+
+ (* always_ready, always_enabled, prefix="" *)
+ method Action m_awready ((* port="awready" *) Bool awready); // in
+
+ // ----------------
+ // Wr Data channel
+ (* always_ready, result="wvalid" *) method Bool m_wvalid; // out
+
+ (* always_ready, result="wdata" *) method Bit #(wd_data) m_wdata; // out
+ (* always_ready, result="wstrb" *) method Bit #(TDiv #(wd_data, 8)) m_wstrb; // out
+ (* always_ready, result="wlast" *) method Bool m_wlast; // out
+ (* always_ready, result="wuser" *) method Bit #(wd_user) m_wuser; // out
+
+ (* always_ready, always_enabled, prefix = "" *)
+ method Action m_wready ((* port="wready" *) Bool wready); // in
+
+ // ----------------
+ // Wr Response channel
+ (* always_ready, always_enabled, prefix = "" *)
+ method Action m_bvalid ((* port="bvalid" *) Bool bvalid, // in
+ (* port="bid" *) Bit #(wd_id) bid, // in
+ (* port="bresp" *) Bit #(2) bresp, // in
+ (* port="buser" *) Bit #(wd_user) buser); // in
+
+ (* always_ready, prefix = "", result="bready" *)
+ method Bool m_bready; // out
+
+ // ----------------
+ // Rd Addr channel
+ (* always_ready, result="arvalid" *) method Bool m_arvalid; // out
+
+ (* always_ready, result="arid" *) method Bit #(wd_id) m_arid; // out
+ (* always_ready, result="araddr" *) method Bit #(wd_addr) m_araddr; // out
+ (* always_ready, result="arlen" *) method Bit #(8) m_arlen; // out
+ (* always_ready, result="arsize" *) method AXI4_Size m_arsize; // out
+ (* always_ready, result="arburst" *) method Bit #(2) m_arburst; // out
+ (* always_ready, result="arlock" *) method Bit #(1) m_arlock; // out
+ (* always_ready, result="arcache" *) method Bit #(4) m_arcache; // out
+ (* always_ready, result="arprot" *) method Bit #(3) m_arprot; // out
+ (* always_ready, result="arqos" *) method Bit #(4) m_arqos; // out
+ (* always_ready, result="arregion" *) method Bit #(4) m_arregion; // out
+ (* always_ready, result="aruser" *) method Bit #(wd_user) m_aruser; // out
+
+ (* always_ready, always_enabled, prefix="" *)
+ method Action m_arready ((* port="arready" *) Bool arready); // in
+
+ // ----------------
+ // Rd Data channel
+ (* always_ready, always_enabled, prefix = "" *)
+ method Action m_rvalid ((* port="rvalid" *) Bool rvalid, // in
+ (* port="rid" *) Bit #(wd_id) rid, // in
+ (* port="rdata" *) Bit #(wd_data) rdata, // in
+ (* port="rresp" *) Bit #(2) rresp, // in
+ (* port="rlast" *) Bool rlast, // in
+ (* port="ruser" *) Bit #(wd_user) ruser); // in
+
+ (* always_ready, result="rready" *)
+ method Bool m_rready; // out
+endinterface: AXI4_RTL_M_IFC
+
+// ================================================================
+// These are the signal-level interfaces for an AXI4-Lite S.
+// The (*..*) attributes ensure that when bsc compiles this to Verilog,
+// we get exactly the signals specified in the ARM spec.
+
+interface AXI4_RTL_S_IFC #(numeric type wd_id,
+ numeric type wd_addr,
+ numeric type wd_data,
+ numeric type wd_user);
+ // Wr Addr channel
+ (* always_ready, always_enabled, prefix = "" *)
+ method Action m_awvalid ((* port="awvalid" *) Bool awvalid, // in
+ (* port="awid" *) Bit #(wd_id) awid, // in
+ (* port="awaddr" *) Bit #(wd_addr) awaddr, // in
+ (* port="awlen" *) Bit #(8) awlen, // in
+ (* port="awsize" *) AXI4_Size awsize, // in
+ (* port="awburst" *) Bit #(2) awburst, // in
+ (* port="awlock" *) Bit #(1) awlock, // in
+ (* port="awcache" *) Bit #(4) awcache, // in
+ (* port="awprot" *) Bit #(3) awprot, // in
+ (* port="awqos" *) Bit #(4) awqos, // in
+ (* port="awregion" *) Bit #(4) awregion, // in
+ (* port="awuser" *) Bit #(wd_user) awuser); // in
+ (* always_ready, result="awready" *)
+ method Bool m_awready; // out
+
+ // Wr Data channel
+ (* always_ready, always_enabled, prefix = "" *)
+ method Action m_wvalid ((* port="wvalid" *) Bool wvalid, // in
+ (* port="wdata" *) Bit #(wd_data) wdata, // in
+ (* port="wstrb" *) Bit #(TDiv #(wd_data,8)) wstrb, // in
+ (* port="wlast" *) Bool wlast, // in
+ (* port="wuser" *) Bit #(wd_user) wuser); // in
+ (* always_ready, result="wready" *)
+ method Bool m_wready; // out
+
+ // Wr Response channel
+ (* always_ready, result="bvalid" *) method Bool m_bvalid; // out
+ (* always_ready, result="bid" *) method Bit #(wd_id) m_bid; // out
+ (* always_ready, result="bresp" *) method Bit #(2) m_bresp; // out
+ (* always_ready, result="buser" *) method Bit #(wd_user) m_buser; // out
+ (* always_ready, always_enabled, prefix="" *)
+ method Action m_bready ((* port="bready" *) Bool bready); // in
+
+ // Rd Addr channel
+ (* always_ready, always_enabled, prefix = "" *)
+ method Action m_arvalid ((* port="arvalid" *) Bool arvalid, // in
+ (* port="arid" *) Bit #(wd_id) arid, // in
+ (* port="araddr" *) Bit #(wd_addr) araddr, // in
+ (* port="arlen" *) Bit #(8) arlen, // in
+ (* port="arsize" *) AXI4_Size arsize, // in
+ (* port="arburst" *) Bit #(2) arburst, // in
+ (* port="arlock" *) Bit #(1) arlock, // in
+ (* port="arcache" *) Bit #(4) arcache, // in
+ (* port="arprot" *) Bit #(3) arprot, // in
+ (* port="arqos" *) Bit #(4) arqos, // in
+ (* port="arregion" *) Bit #(4) arregion, // in
+ (* port="aruser" *) Bit #(wd_user) aruser); // in
+ (* always_ready, result="arready" *)
+ method Bool m_arready; // out
+
+ // Rd Data channel
+ (* always_ready, result="rvalid" *) method Bool m_rvalid; // out
+ (* always_ready, result="rid" *) method Bit #(wd_id) m_rid; // out
+ (* always_ready, result="rdata" *) method Bit #(wd_data) m_rdata; // out
+ (* always_ready, result="rresp" *) method Bit #(2) m_rresp; // out
+ (* always_ready, result="rlast" *) method Bool m_rlast; // out
+ (* always_ready, result="ruser" *) method Bit #(wd_user) m_ruser; // out
+ (* always_ready, always_enabled, prefix="" *)
+ method Action m_rready ((* port="rready" *) Bool rready); // in
+endinterface: AXI4_RTL_S_IFC
+
+// ================================================================
+// Connecting RTL-level interfaces
+
+instance Connectable #(AXI4_RTL_M_IFC #(wd_id, wd_addr, wd_data, wd_user),
+ AXI4_RTL_S_IFC #(wd_id, wd_addr, wd_data, wd_user));
+
+ module mkConnection #(AXI4_RTL_M_IFC #(wd_id, wd_addr, wd_data, wd_user) axim,
+ AXI4_RTL_S_IFC #(wd_id, wd_addr, wd_data, wd_user) axis)
+ (Empty);
+
+ (* fire_when_enabled, no_implicit_conditions *)
+ rule rl_AW;
+ axis.m_awvalid (axim.m_awvalid,
+ axim.m_awid,
+ axim.m_awaddr,
+ axim.m_awlen,
+ axim.m_awsize,
+ axim.m_awburst,
+ axim.m_awlock,
+ axim.m_awcache,
+ axim.m_awprot,
+ axim.m_awqos,
+ axim.m_awregion,
+ axim.m_awuser);
+ axim.m_awready (axis.m_awready);
+ endrule
+
+ (* fire_when_enabled, no_implicit_conditions *)
+ rule rl_W;
+ axis.m_wvalid (axim.m_wvalid,
+ axim.m_wdata,
+ axim.m_wstrb,
+ axim.m_wlast,
+ axim.m_wuser);
+ axim.m_wready (axis.m_wready);
+ endrule
+
+ (* fire_when_enabled, no_implicit_conditions *)
+ rule rl_B;
+ axim.m_bvalid (axis.m_bvalid,
+ axis.m_bid,
+ axis.m_bresp,
+ axis.m_buser);
+ axis.m_bready (axim.m_bready);
+ endrule
+
+ (* fire_when_enabled, no_implicit_conditions *)
+ rule rl_AR;
+ axis.m_arvalid (axim.m_arvalid,
+ axim.m_arid,
+ axim.m_araddr,
+ axim.m_arlen,
+ axim.m_arsize,
+ axim.m_arburst,
+ axim.m_arlock,
+ axim.m_arcache,
+ axim.m_arprot,
+ axim.m_arqos,
+ axim.m_arregion,
+ axim.m_aruser);
+ axim.m_arready (axis.m_arready);
+ endrule
+
+ (* fire_when_enabled, no_implicit_conditions *)
+ rule rl_R;
+ axim.m_rvalid (axis.m_rvalid,
+ axis.m_rid,
+ axis.m_rdata,
+ axis.m_rresp,
+ axis.m_rlast,
+ axis.m_ruser);
+ axis.m_rready (axim.m_rready);
+ endrule
+ endmodule
+endinstance
+
+// ================================================================
+// AXI4 dummy M: never produces requests, never accepts responses
+
+AXI4_RTL_M_IFC #(wd_id, wd_addr, wd_data, wd_user)
+dummy_AXI4_RTL_M_ifc
+= interface AXI4_RTL_M_IFC
+ // Wr Addr channel
+ method Bool m_awvalid = False; // out
+ method Bit #(wd_id) m_awid = ?; // out
+ method Bit #(wd_addr) m_awaddr = ?; // out
+ method Bit #(8) m_awlen = ?; // out
+ method AXI4_Size m_awsize = ?; // out
+ method Bit #(2) m_awburst = ?; // out
+ method Bit #(1) m_awlock = ?; // out
+ method Bit #(4) m_awcache = ?; // out
+ method Bit #(3) m_awprot = ?; // out
+ method Bit #(4) m_awqos = ?; // out
+ method Bit #(4) m_awregion = ?; // out
+ method Bit #(wd_user) m_awuser = ?; // out
+ method Action m_awready (Bool awready) = noAction; // in
+
+ // Wr Data channel
+ method Bool m_wvalid = False; // out
+ method Bit #(wd_data) m_wdata = ?; // out
+ method Bit #(TDiv #(wd_data, 8)) m_wstrb = ?; // out
+ method Bool m_wlast = ?; // out
+ method Bit #(wd_user) m_wuser = ?; // out
+
+ method Action m_wready (Bool wready) = noAction; // in
+
+ // Wr Response channel
+ method Action m_bvalid (Bool bvalid, // in
+ Bit #(wd_id) bid, // in
+ Bit #(2) bresp, // in
+ Bit #(wd_user) buser); // in
+ noAction;
+ endmethod
+ method Bool m_bready = False; // out
+
+ // Rd Addr channel
+ method Bool m_arvalid = False; // out
+ method Bit #(wd_id) m_arid = ?; // out
+ method Bit #(wd_addr) m_araddr = ?; // out
+ method Bit #(8) m_arlen = ?; // out
+ method AXI4_Size m_arsize = ?; // out
+ method Bit #(2) m_arburst = ?; // out
+ method Bit #(1) m_arlock = ?; // out
+ method Bit #(4) m_arcache = ?; // out
+ method Bit #(3) m_arprot = ?; // out
+ method Bit #(4) m_arqos = ?; // out
+ method Bit #(4) m_arregion = ?; // out
+ method Bit #(wd_user) m_aruser = ?; // out
+ method Action m_arready (Bool arready) = noAction; // in
+
+ // Rd Data channel
+ method Action m_rvalid (Bool rvalid, // in
+ Bit #(wd_id) rid, // in
+ Bit #(wd_data) rdata, // in
+ Bit #(2) rresp, // in
+ Bool rlast, // in
+ Bit #(wd_user) ruser); // in
+ noAction;
+ endmethod
+ method Bool m_rready = False; // out
+ endinterface;
+
+// ================================================================
+// AXI4 dummy S: never accepts requests, never produces responses
+
+AXI4_RTL_S_IFC #(wd_id, wd_addr, wd_data, wd_user)
+dummy_AXI4_RTL_S_ifc
+= interface AXI4_RTL_S_IFC
+ // Wr Addr channel
+ method Action m_awvalid (Bool awvalid,
+ Bit #(wd_id) awid,
+ Bit #(wd_addr) awaddr,
+ Bit #(8) awlen,
+ AXI4_Size awsize,
+ Bit #(2) awburst,
+ Bit #(1) awlock,
+ Bit #(4) awcache,
+ Bit #(3) awprot,
+ Bit #(4) awqos,
+ Bit #(4) awregion,
+ Bit #(wd_user) awuser);
+ noAction;
+ endmethod
+
+ method Bool m_awready;
+ return False;
+ endmethod
+
+ // Wr Data channel
+ method Action m_wvalid (Bool wvalid,
+ Bit #(wd_data) wdata,
+ Bit #(TDiv #(wd_data, 8)) wstrb,
+ Bool wlast,
+ Bit #(wd_user) wuser);
+ noAction;
+ endmethod
+
+ method Bool m_wready;
+ return False;
+ endmethod
+
+ // Wr Response channel
+ method Bool m_bvalid;
+ return False;
+ endmethod
+
+ method Bit #(wd_id) m_bid;
+ return ?;
+ endmethod
+
+ method Bit #(2) m_bresp;
+ return 0;
+ endmethod
+
+ method Bit #(wd_user) m_buser;
+ return ?;
+ endmethod
+
+ method Action m_bready (Bool bready);
+ noAction;
+ endmethod
+
+ // Rd Addr channel
+ method Action m_arvalid (Bool arvalid,
+ Bit #(wd_id) arid,
+ Bit #(wd_addr) araddr,
+ Bit #(8) arlen,
+ AXI4_Size arsize,
+ Bit #(2) arburst,
+ Bit #(1) arlock,
+ Bit #(4) arcache,
+ Bit #(3) arprot,
+ Bit #(4) arqos,
+ Bit #(4) arregion,
+ Bit #(wd_user) aruser);
+ noAction;
+ endmethod
+
+ method Bool m_arready;
+ return False;
+ endmethod
+
+ // Rd Data channel
+ method Bool m_rvalid;
+ return False;
+ endmethod
+
+ method Bit #(wd_id) m_rid;
+ return 0;
+ endmethod
+
+ method Bit #(wd_data) m_rdata;
+ return 0;
+ endmethod
+
+ method Bit #(2) m_rresp;
+ return 0;
+ endmethod
+
+ method Bool m_rlast;
+ return True;
+ endmethod
+
+ method Bit #(wd_user) m_ruser;
+ return ?;
+ endmethod
+
+ method Action m_rready (Bool rready);
+ noAction;
+ endmethod
+ endinterface;
+
+// ****************************************************************
+
+interface AXI4_BSV_to_RTL_IFC #(numeric type wd_id,
+ numeric type wd_addr,
+ numeric type wd_data,
+ numeric type wd_user);
+ interface AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user) ifc_S;
+ interface AXI4_RTL_M_IFC #(wd_id, wd_addr, wd_data, wd_user) rtl_M;
+endinterface: AXI4_BSV_to_RTL_IFC
+
+interface AXI4_RTL_to_BSV_IFC #(numeric type wd_id,
+ numeric type wd_addr,
+ numeric type wd_data,
+ numeric type wd_user);
+ interface AXI4_RTL_S_IFC #(wd_id, wd_addr, wd_data, wd_user) rtl_S;
+ interface AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user) ifc_M;
+endinterface: AXI4_RTL_to_BSV_IFC
+
+// ================================================================
+// M transactor
+// This version uses FIFOFs for total decoupling.
+
+module mkAXI4_BSV_to_RTL (AXI4_BSV_to_RTL_IFC #(wd_id, wd_addr, wd_data, wd_user));
+
+ Bool unguarded = True;
+ Bool guarded = False;
+
+ // These FIFOs are guarded on BSV side, unguarded on AXI side
+ FIFOF #(AXI4_AW #(wd_id, wd_addr, wd_user)) f_AW <- mkGFIFOF (guarded, unguarded);
+ FIFOF #(AXI4_W #(wd_data, wd_user)) f_W <- mkGFIFOF (guarded, unguarded);
+ FIFOF #(AXI4_B #(wd_id, wd_user)) f_B <- mkGFIFOF (unguarded, guarded);
+
+ FIFOF #(AXI4_AR #(wd_id, wd_addr, wd_user)) f_AR <- mkGFIFOF (guarded, unguarded);
+ FIFOF #(AXI4_R #(wd_id, wd_data, wd_user)) f_R <- mkGFIFOF (unguarded, guarded);
+
+ // ----------------------------------------------------------------
+ // INTERFACE
+
+ // RTL side
+ interface AXI4_RTL_M_IFC rtl_M;
+ // Wr Addr channel
+ method Bool m_awvalid = f_AW.notEmpty;
+ method Bit #(wd_id) m_awid = f_AW.first.awid;
+ method Bit #(wd_addr) m_awaddr = f_AW.first.awaddr;
+ method Bit #(8) m_awlen = f_AW.first.awlen;
+ method AXI4_Size m_awsize = f_AW.first.awsize;
+ method Bit #(2) m_awburst = f_AW.first.awburst;
+ method Bit #(1) m_awlock = f_AW.first.awlock;
+ method Bit #(4) m_awcache = f_AW.first.awcache;
+ method Bit #(3) m_awprot = f_AW.first.awprot;
+ method Bit #(4) m_awqos = f_AW.first.awqos;
+ method Bit #(4) m_awregion = f_AW.first.awregion;
+ method Bit #(wd_user) m_awuser = f_AW.first.awuser;
+ method Action m_awready (Bool awready);
+ if (f_AW.notEmpty && awready) f_AW.deq;
+ endmethod
+
+ // Wr Data channel
+ method Bool m_wvalid = f_W.notEmpty;
+ method Bit #(wd_data) m_wdata = f_W.first.wdata;
+ method Bit #(TDiv #(wd_data, 8)) m_wstrb = f_W.first.wstrb;
+ method Bool m_wlast = f_W.first.wlast;
+ method Bit #(wd_user) m_wuser = f_W.first.wuser;
+ method Action m_wready (Bool wready);
+ if (f_W.notEmpty && wready) f_W.deq;
+ endmethod
+
+ // Wr Response channel
+ method Action m_bvalid (Bool bvalid,
+ Bit #(wd_id) bid,
+ Bit #(2) bresp,
+ Bit #(wd_user) buser);
+ if (bvalid && f_B.notFull)
+ f_B.enq (AXI4_B {bid: bid,
+ bresp: bresp,
+ buser: buser});
+ endmethod
+
+ method Bool m_bready;
+ return f_B.notFull;
+ endmethod
+
+ // Rd Addr channel
+ method Bool m_arvalid = f_AR.notEmpty;
+ method Bit #(wd_id) m_arid = f_AR.first.arid;
+ method Bit #(wd_addr) m_araddr = f_AR.first.araddr;
+ method Bit #(8) m_arlen = f_AR.first.arlen;
+ method AXI4_Size m_arsize = f_AR.first.arsize;
+ method Bit #(2) m_arburst = f_AR.first.arburst;
+ method Bit #(1) m_arlock = f_AR.first.arlock;
+ method Bit #(4) m_arcache = f_AR.first.arcache;
+ method Bit #(3) m_arprot = f_AR.first.arprot;
+ method Bit #(4) m_arqos = f_AR.first.arqos;
+ method Bit #(4) m_arregion = f_AR.first.arregion;
+ method Bit #(wd_user) m_aruser = f_AR.first.aruser;
+
+ method Action m_arready (Bool arready);
+ if (f_AR.notEmpty && arready) f_AR.deq;
+ endmethod
+
+ // Rd Data channel
+ method Action m_rvalid (Bool rvalid, // in
+ Bit #(wd_id) rid, // in
+ Bit #(wd_data) rdata, // in
+ Bit #(2) rresp, // in
+ Bool rlast, // in
+ Bit #(wd_user) ruser); // in
+ if (rvalid && f_R.notFull)
+ f_R.enq (AXI4_R {rid: rid,
+ rdata: rdata,
+ rresp: rresp,
+ rlast: rlast,
+ ruser: ruser});
+ endmethod
+
+ method Bool m_rready;
+ return f_R.notFull;
+ endmethod
+
+ endinterface
+
+ // BSV side
+ interface AXI4_S_IFC ifc_S;
+ interface i_AW = to_FIFOF_I (f_AW);
+ interface i_W = to_FIFOF_I (f_W);
+ interface o_B = to_FIFOF_O (f_B);
+
+ interface i_AR = to_FIFOF_I (f_AR);
+ interface o_R = to_FIFOF_O (f_R);
+ endinterface
+endmodule: mkAXI4_BSV_to_RTL
+
+// ================================================================
+// This version uses FIFOFs for total decoupling.
+
+module mkAXI4_RTL_to_BSV (AXI4_RTL_to_BSV_IFC #(wd_id, wd_addr, wd_data, wd_user));
+
+ Bool unguarded = True;
+ Bool guarded = False;
+
+ // These FIFOs are guarded on BSV side, unguarded on AXI side
+ FIFOF #(AXI4_AW #(wd_id, wd_addr, wd_user)) f_AW <- mkGFIFOF (unguarded, guarded);
+ FIFOF #(AXI4_W #(wd_data, wd_user)) f_W <- mkGFIFOF (unguarded, guarded);
+ FIFOF #(AXI4_B #(wd_id, wd_user)) f_B <- mkGFIFOF (guarded, unguarded);
+
+ FIFOF #(AXI4_AR #(wd_id, wd_addr, wd_user)) f_AR <- mkGFIFOF (unguarded, guarded);
+ FIFOF #(AXI4_R #(wd_id, wd_data, wd_user)) f_R <- mkGFIFOF (guarded, unguarded);
+
+ // ----------------------------------------------------------------
+ // INTERFACE
+
+ // AXI side
+ interface AXI4_RTL_S_IFC rtl_S;
+ // Wr Addr channel
+ method Action m_awvalid (Bool awvalid,
+ Bit #(wd_id) awid,
+ Bit #(wd_addr) awaddr,
+ Bit #(8) awlen,
+ AXI4_Size awsize,
+ Bit #(2) awburst,
+ Bit #(1) awlock,
+ Bit #(4) awcache,
+ Bit #(3) awprot,
+ Bit #(4) awqos,
+ Bit #(4) awregion,
+ Bit #(wd_user) awuser);
+ if (awvalid && f_AW.notFull)
+ f_AW.enq (AXI4_AW {awid: awid,
+ awaddr: awaddr,
+ awlen: awlen,
+ awsize: awsize,
+ awburst: awburst,
+ awlock: awlock,
+ awcache: awcache,
+ awprot: awprot,
+ awqos: awqos,
+ awregion: awregion,
+ awuser: awuser});
+ endmethod
+
+ method Bool m_awready;
+ return f_AW.notFull;
+ endmethod
+
+ // Wr Data channel
+ method Action m_wvalid (Bool wvalid,
+ Bit #(wd_data) wdata,
+ Bit #(TDiv #(wd_data, 8)) wstrb,
+ Bool wlast,
+ Bit #(wd_user) wuser);
+ if (wvalid && f_W.notFull)
+ f_W.enq (AXI4_W {wdata: wdata,
+ wstrb: wstrb,
+ wlast: wlast,
+ wuser: wuser});
+ endmethod
+
+ method Bool m_wready;
+ return f_W.notFull;
+ endmethod
+
+ // Wr Response channel
+ method Bool m_bvalid = f_B.notEmpty;
+ method Bit #(wd_id) m_bid = f_B.first.bid;
+ method Bit #(2) m_bresp = f_B.first.bresp;
+ method Bit #(wd_user) m_buser = f_B.first.buser;
+ method Action m_bready (Bool bready);
+ if (bready && f_B.notEmpty)
+ f_B.deq;
+ endmethod
+
+ // Rd Addr channel
+ method Action m_arvalid (Bool arvalid,
+ Bit #(wd_id) arid,
+ Bit #(wd_addr) araddr,
+ Bit #(8) arlen,
+ AXI4_Size arsize,
+ Bit #(2) arburst,
+ Bit #(1) arlock,
+ Bit #(4) arcache,
+ Bit #(3) arprot,
+ Bit #(4) arqos,
+ Bit #(4) arregion,
+ Bit #(wd_user) aruser);
+ if (arvalid && f_AR.notFull)
+ f_AR.enq (AXI4_AR {arid: arid,
+ araddr: araddr,
+ arlen: arlen,
+ arsize: arsize,
+ arburst: arburst,
+ arlock: arlock,
+ arcache: arcache,
+ arprot: arprot,
+ arqos: arqos,
+ arregion: arregion,
+ aruser: aruser});
+ endmethod
+
+ method Bool m_arready;
+ return f_AR.notFull;
+ endmethod
+
+ // Rd Data channel
+ method Bool m_rvalid = f_R.notEmpty;
+ method Bit #(wd_id) m_rid = f_R.first.rid;
+ method Bit #(wd_data) m_rdata = f_R.first.rdata;
+ method Bit #(2) m_rresp = f_R.first.rresp;
+ method Bool m_rlast = f_R.first.rlast;
+ method Bit #(wd_user) m_ruser = f_R.first.ruser;
+ method Action m_rready (Bool rready);
+ if (rready && f_R.notEmpty)
+ f_R.deq;
+ endmethod
+ endinterface
+
+ // BSV side
+ interface AXI4_M_IFC ifc_M;
+ interface o_AW = to_FIFOF_O (f_AW);
+ interface o_W = to_FIFOF_O (f_W);
+ interface i_B = to_FIFOF_I (f_B);
+
+ interface o_AR = to_FIFOF_O (f_AR);
+ interface i_R = to_FIFOF_I (f_R);
+ endinterface
+endmodule: mkAXI4_RTL_to_BSV
+
+// ================================================================
+// Help function: fn_crg_and_rg_to_FIFOF_I
+// In the modules below, we use a crg_full and a rg_data to represent a fifo.
+// These functions convert these to FIFOF_I and FIFOF_O interfaces.
+
+function FIFOF_I #(t) fn_crg_and_rg_to_FIFOF_I (Reg #(Bool) rg_full, Reg #(t) rg_data);
+ return interface FIFOF_I;
+ method Action enq (t x) if (! rg_full);
+ rg_full <= True;
+ rg_data <= x;
+ endmethod
+ method Bool notFull;
+ return (! rg_full);
+ endmethod
+ endinterface;
+endfunction
+
+function FIFOF_O #(t) fn_crg_and_rg_to_FIFOF_O (Reg #(Bool) rg_full, Reg #(t) rg_data);
+ return interface FIFOF_O;
+ method t first () if (rg_full);
+ return rg_data;
+ endmethod
+ method Action deq () if (rg_full);
+ rg_full <= False;
+ endmethod
+ method notEmpty;
+ return rg_full;
+ endmethod
+ endinterface;
+endfunction
+
+// ================================================================
+// M transactor
+// This version uses crgs and regs instead of FIFOFs.
+// This uses 1/2 the resources, but introduces scheduling dependencies.
+
+module mkAXI4_BSV_to_RTL_2 (AXI4_BSV_to_RTL_IFC #(wd_id, wd_addr, wd_data, wd_user));
+
+ // Each crg_full, rg_data pair below represents a 1-element fifo.
+
+ Array #(Reg #(Bool)) crg_AW_full <- mkCReg (3, False);
+ Reg #(AXI4_AW #(wd_id, wd_addr, wd_user)) rg_AW <- mkRegU;
+
+ Array #(Reg #(Bool)) crg_W_full <- mkCReg (3, False);
+ Reg #(AXI4_W #(wd_data, wd_user)) rg_W <- mkRegU;
+
+ Array #(Reg #(Bool)) crg_B_full <- mkCReg (3, False);
+ Reg #(AXI4_B #(wd_id, wd_user)) rg_B <- mkRegU;
+
+ Array #(Reg #(Bool)) crg_AR_full <- mkCReg (3, False);
+ Reg #(AXI4_AR #(wd_id, wd_addr, wd_user)) rg_AR <- mkRegU;
+
+ Array #(Reg #(Bool)) crg_R_full <- mkCReg (3, False);
+ Reg #(AXI4_R #(wd_id, wd_data, wd_user)) rg_R <- mkRegU;
+
+ // The following CReg port indexes specify the relative scheduling of:
+ // {first,deq,notEmpty} {enq,notFull} clear
+
+ // TODO: 'deq/enq/clear = 1/2/0' is unusual, but eliminates a
+ // scheduling cycle in Piccolo's DCache. Normally should be 0/1/2.
+
+ Integer port_deq = 1;
+ Integer port_enq = 2;
+ Integer port_clear = 0;
+
+ // ----------------------------------------------------------------
+ // INTERFACE
+
+ // RTL side
+ interface AXI4_RTL_M_IFC rtl_M;
+ // Wr Addr channel
+ method Bool m_awvalid = crg_AW_full [port_deq];
+ method Bit #(wd_id) m_awid = rg_AW.awid;
+ method Bit #(wd_addr) m_awaddr = rg_AW.awaddr;
+ method Bit #(8) m_awlen = rg_AW.awlen;
+ method AXI4_Size m_awsize = rg_AW.awsize;
+ method Bit #(2) m_awburst = rg_AW.awburst;
+ method Bit #(1) m_awlock = rg_AW.awlock;
+ method Bit #(4) m_awcache = rg_AW.awcache;
+ method Bit #(3) m_awprot = rg_AW.awprot;
+ method Bit #(4) m_awqos = rg_AW.awqos;
+ method Bit #(4) m_awregion = rg_AW.awregion;
+ method Bit #(wd_user) m_awuser = rg_AW.awuser;
+ method Action m_awready (Bool awready);
+ if (crg_AW_full [port_deq] && awready)
+ crg_AW_full [port_deq] <= False; // deq
+ endmethod
+
+ // Wr Data channel
+ method Bool m_wvalid = crg_W_full [port_deq];
+ method Bit #(wd_data) m_wdata = rg_W.wdata;
+ method Bit #(TDiv #(wd_data, 8)) m_wstrb = rg_W.wstrb;
+ method Bool m_wlast = rg_W.wlast;
+ method Bit #(wd_user) m_wuser = rg_W.wuser;
+ method Action m_wready (Bool wready);
+ if (crg_W_full [port_deq] && wready)
+ crg_W_full [port_deq] <= False;
+ endmethod
+
+ // Wr Response channel
+ method Action m_bvalid (Bool bvalid,
+ Bit #(wd_id) bid,
+ Bit #(2) bresp,
+ Bit #(wd_user) buser);
+ if (bvalid && (! (crg_B_full [port_enq]))) begin
+ crg_B_full [port_enq] <= True;
+ rg_B <= AXI4_B {bid: bid,
+ bresp: bresp,
+ buser: buser};
+ end
+ endmethod
+
+ method Bool m_bready;
+ return (! (crg_B_full [port_enq]));
+ endmethod
+
+ // Rd Addr channel
+ method Bool m_arvalid = crg_AR_full [port_deq];
+ method Bit #(wd_id) m_arid = rg_AR.arid;
+ method Bit #(wd_addr) m_araddr = rg_AR.araddr;
+ method Bit #(8) m_arlen = rg_AR.arlen;
+ method AXI4_Size m_arsize = rg_AR.arsize;
+ method Bit #(2) m_arburst = rg_AR.arburst;
+ method Bit #(1) m_arlock = rg_AR.arlock;
+ method Bit #(4) m_arcache = rg_AR.arcache;
+ method Bit #(3) m_arprot = rg_AR.arprot;
+ method Bit #(4) m_arqos = rg_AR.arqos;
+ method Bit #(4) m_arregion = rg_AR.arregion;
+ method Bit #(wd_user) m_aruser = rg_AR.aruser;
+ method Action m_arready (Bool arready);
+ if (crg_AR_full [port_deq] && arready)
+ crg_AR_full [port_deq] <= False; // deq
+ endmethod
+
+ // Rd Data channel
+ method Action m_rvalid (Bool rvalid,
+ Bit #(wd_id) rid,
+ Bit #(wd_data) rdata,
+ Bit #(2) rresp,
+ Bool rlast,
+ Bit #(wd_user) ruser);
+ if (rvalid && (! (crg_R_full [port_enq])))
+ crg_R_full [port_enq] <= True;
+ rg_R <= (AXI4_R {rid: rid,
+ rdata: rdata,
+ rresp: rresp,
+ rlast: rlast,
+ ruser: ruser});
+ endmethod
+
+ method Bool m_rready;
+ return (! (crg_R_full [port_enq]));
+ endmethod
+
+ endinterface
+
+ // BSV side
+ interface AXI4_S_IFC ifc_S;
+ interface i_AW = fn_crg_and_rg_to_FIFOF_I (crg_AW_full [port_enq], rg_AW);
+ interface i_W = fn_crg_and_rg_to_FIFOF_I (crg_W_full [port_enq], rg_W);
+ interface o_B = fn_crg_and_rg_to_FIFOF_O (crg_B_full [port_deq], rg_B);
+
+ interface i_AR = fn_crg_and_rg_to_FIFOF_I (crg_AR_full [port_enq], rg_AR);
+ interface o_R = fn_crg_and_rg_to_FIFOF_O (crg_R_full [port_deq], rg_R);
+ endinterface
+endmodule: mkAXI4_BSV_to_RTL_2
+
+// ----------------------------------------------------------------
+// S transactor
+// This version uses crgs and regs instead of FIFOFs.
+// This uses 1/2 the resources, but introduces scheduling dependencies.
+
+module mkAXI4_RTL_to_BSV_2 (AXI4_RTL_to_BSV_IFC #(wd_id, wd_addr, wd_data, wd_user));
+
+ // Each crg_full, rg_data pair below represents a 1-element fifo.
+
+ // These FIFOs are guarded on BSV side, unguarded on AXI side
+ Array #(Reg #(Bool)) crg_AW_full <- mkCReg (3, False);
+ Reg #(AXI4_AW #(wd_id, wd_addr, wd_user)) rg_AW <- mkRegU;
+
+ Array #(Reg #(Bool)) crg_W_full <- mkCReg (3, False);
+ Reg #(AXI4_W #(wd_data, wd_user)) rg_W <- mkRegU;
+
+ Array #(Reg #(Bool)) crg_B_full <- mkCReg (3, False);
+ Reg #(AXI4_B #(wd_id, wd_user)) rg_B <- mkRegU;
+
+ Array #(Reg #(Bool)) crg_AR_full <- mkCReg (3, False);
+ Reg #(AXI4_AR #(wd_id, wd_addr, wd_user)) rg_AR <- mkRegU;
+
+ Array #(Reg #(Bool)) crg_R_full <- mkCReg (3, False);
+ Reg #(AXI4_R #(wd_id, wd_data, wd_user)) rg_R <- mkRegU;
+
+ // The following CReg port indexes specify the relative scheduling of:
+ // {first,deq,notEmpty} {enq,notFull} clear
+ Integer port_deq = 0;
+ Integer port_enq = 1;
+ Integer port_clear = 2;
+
+ // ----------------------------------------------------------------
+ // INTERFACE
+
+ // RTL side
+ interface AXI4_RTL_S_IFC rtl_S;
+ // Wr Addr channel
+ method Action m_awvalid (Bool awvalid,
+ Bit #(wd_id) awid,
+ Bit #(wd_addr) awaddr,
+ Bit #(8) awlen,
+ AXI4_Size awsize,
+ Bit #(2) awburst,
+ Bit #(1) awlock,
+ Bit #(4) awcache,
+ Bit #(3) awprot,
+ Bit #(4) awqos,
+ Bit #(4) awregion,
+ Bit #(wd_user) awuser);
+
+ if (awvalid && (! crg_AW_full [port_enq])) begin
+ crg_AW_full [port_enq] <= True; // enq
+ rg_AW <= AXI4_AW {awid: awid,
+ awaddr: awaddr,
+ awlen: awlen,
+ awsize: awsize,
+ awburst: awburst,
+ awlock: awlock,
+ awcache: awcache,
+ awprot: awprot,
+ awqos: awqos,
+ awregion: awregion,
+ awuser: awuser};
+ end
+ endmethod
+
+ method Bool m_awready;
+ return (! crg_AW_full [port_enq]);
+ endmethod
+
+ // Wr Data channel
+ method Action m_wvalid (Bool wvalid,
+ Bit #(wd_data) wdata,
+ Bit #(TDiv #(wd_data, 8)) wstrb,
+ Bool wlast,
+ Bit #(wd_user) wuser);
+ if (wvalid && (! crg_W_full [port_enq])) begin
+ crg_W_full [port_enq] <= True; // enq
+ rg_W <= AXI4_W {wdata: wdata,
+ wstrb: wstrb,
+ wlast: wlast,
+ wuser: wuser};
+ end
+ endmethod
+
+ method Bool m_wready;
+ return (! crg_W_full [port_enq]);
+ endmethod
+
+ // Wr Response channel
+ method Bool m_bvalid = crg_B_full [port_deq];
+ method Bit #(wd_id) m_bid = rg_B.bid;
+ method Bit #(2) m_bresp = rg_B.bresp;
+ method Bit #(wd_user) m_buser = rg_B.buser;
+ method Action m_bready (Bool bready);
+ if (bready && crg_B_full [port_deq])
+ crg_B_full [port_deq] <= False; // deq
+ endmethod
+
+ // Rd Addr channel
+ method Action m_arvalid (Bool arvalid,
+ Bit #(wd_id) arid,
+ Bit #(wd_addr) araddr,
+ Bit #(8) arlen,
+ AXI4_Size arsize,
+ Bit #(2) arburst,
+ Bit #(1) arlock,
+ Bit #(4) arcache,
+ Bit #(3) arprot,
+ Bit #(4) arqos,
+ Bit #(4) arregion,
+ Bit #(wd_user) aruser);
+ if (arvalid && (! crg_AR_full [port_enq])) begin
+ crg_AR_full [port_enq] <= True; // enq
+ rg_AR <= AXI4_AR {arid: arid,
+ araddr: araddr,
+ arlen: arlen,
+ arsize: arsize,
+ arburst: arburst,
+ arlock: arlock,
+ arcache: arcache,
+ arprot: arprot,
+ arqos: arqos,
+ arregion: arregion,
+ aruser: aruser};
+ end
+ endmethod
+
+ method Bool m_arready;
+ return (! crg_AR_full [port_enq]);
+ endmethod
+
+ // Rd Data channel
+ method Bool m_rvalid = crg_R_full [port_deq];
+ method Bit #(wd_id) m_rid = rg_R.rid;
+ method Bit #(wd_data) m_rdata = rg_R.rdata;
+ method Bit #(2) m_rresp = rg_R.rresp;
+ method Bool m_rlast = rg_R.rlast;
+ method Bit #(wd_user) m_ruser = rg_R.ruser;
+ method Action m_rready (Bool rready);
+ if (rready && crg_R_full [port_deq])
+ crg_R_full [port_deq] <= False; // deq
+ endmethod
+ endinterface
+
+ // BSV side
+ interface AXI4_M_IFC ifc_M;
+ interface o_AW = fn_crg_and_rg_to_FIFOF_O (crg_AW_full [port_deq], rg_AW);
+ interface o_W = fn_crg_and_rg_to_FIFOF_O (crg_W_full [port_deq], rg_W);
+ interface i_B = fn_crg_and_rg_to_FIFOF_I (crg_B_full [port_enq], rg_B);
+
+ interface o_AR = fn_crg_and_rg_to_FIFOF_O (crg_AR_full [port_deq], rg_AR);
+ interface i_R = fn_crg_and_rg_to_FIFOF_I (crg_R_full [port_enq], rg_R);
+ endinterface
+endmodule: mkAXI4_RTL_to_BSV_2
+
+// ****************************************************************
+
+endpackage
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_ClockCrossing.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_ClockCrossing.bsv
deleted file mode 100644
index 1a3ad30..0000000
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_ClockCrossing.bsv
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright (c) 2020 Bluespec, Inc. All Rights Reserved
-//
-// SPDX-License-Identifier: BSD-3-Clause
-
-package AXI4_ClockCrossing;
-
-import Clocks ::*;
-import AXI4_Types ::*;
-import AXI4_Extra_Xactors ::*;
-import Connectable ::*;
-import Semi_FIFOF ::*;
-import GetPut ::*;
-
-// ================================================================
-
-interface AXI4_ClockCrossing_IFC #(numeric type id_,
- numeric type addr_,
- numeric type data_,
- numeric type user_);
- interface AXI4_S_IFC #(id_, addr_, data_, user_) from_M;
- interface AXI4_M_IFC #(id_, addr_, data_, user_) to_S;
-endinterface
-
-// ================================================================
-
-module mkAXI4_ClockCrossing #(Clock clock_M,
- Reset reset_M,
- Clock clock_S,
- Reset reset_S)
- (AXI4_ClockCrossing_IFC #(id_, addr_, data_, user_));
-
- SyncFIFOIfc #(AXI4_Wr_Addr #(id_, addr_, user_))
- f_aw <- mkSyncFIFO (4, clock_M, reset_M, clock_S);
-
- SyncFIFOIfc #(AXI4_Wr_Data #(data_, user_))
- f_w <- mkSyncFIFO (4, clock_M, reset_M, clock_S);
-
- SyncFIFOIfc #(AXI4_Wr_Resp #(id_, user_))
- f_b <- mkSyncFIFO (4, clock_S, reset_S, clock_M);
-
- SyncFIFOIfc #(AXI4_Rd_Addr #(id_, addr_, user_))
- f_ar <- mkSyncFIFO (4, clock_M, reset_M, clock_S);
-
- SyncFIFOIfc #(AXI4_Rd_Data #(id_, data_, user_))
- f_r <- mkSyncFIFO (4, clock_S, reset_S, clock_M);
-
- AXI4_S_IFC #(id_, addr_, data_, user_)
- s_xactor <- mkAXI4_S_Xactor_3 (f_aw, f_w, f_b, f_ar, f_r,
- clocked_by clock_M,
- reset_by reset_M);
-
- AXI4_M_IFC #(id_, addr_, data_, user_)
- m_xactor <- mkAXI4_M_Xactor_3 (f_aw, f_w, f_b, f_ar, f_r,
- clocked_by clock_S,
- reset_by reset_S);
-
- interface AXI4_S_IFC from_M = s_xactor;
- interface AXI4_M_IFC to_S = m_xactor;
-endmodule
-
-// ----------------------------------------------------------------
-// Same as above, with S-side using current-clock
-
-module mkAXI4_ClockCrossingToCC #(Clock clock_M, Reset reset_M)
- (AXI4_ClockCrossing_IFC #(id_, addr_, data_, user_));
- let clock_S <- exposeCurrentClock;
- let reset_S <- exposeCurrentReset;
- let crossing <- mkAXI4_ClockCrossing (clock_M, reset_M, clock_S, reset_S);
-
- return crossing;
-endmodule
-
-endpackage
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_Clock_Crossers.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_Clock_Crossers.bsv
index 31e3d64..0419801 100644
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_Clock_Crossers.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4/AXI4_Clock_Crossers.bsv
@@ -1,7 +1,7 @@
-// Copyright (c) 2022 Bluespec, Inc. All Rights Reserved
+// Copyright (c) 2022-2024 Bluespec, Inc. All Rights Reserved
// Author: Rishiyur S. Nikhil
-// (original code for mkAXI4_Clock_Crossing from Joe Stoy)
-//
+// (adapted and renamed from original code from Joe Stoy)
+
// SPDX-License-Identifier: BSD-3-Clause
package AXI4_Clock_Crossers;
@@ -10,19 +10,19 @@ package AXI4_Clock_Crossers;
// This package defines clock-domain-crossing modules for AXI4 M and S
// interfaces:
-// Clock -> Clock -> AXI4_M_IFC -> Module #(AXI4_M_IFC)
+// Clock -> Clock -> AXI4_RTL_M_IFC -> Module #(AXI4_RTL_M_IFC)
export mkAXI4_M_Clock_Crosser;
-// Clock -> Clock -> AXI4_S_IFC -> Module #(AXI4_S_IFC)
+// Clock -> Clock -> AXI4_RTL_S_IFC -> Module #(AXI4_RTL_S_IFC)
export mkAXI4_S_Clock_Crosser;
-export AXI4_ClockCrossing_IFC (..);
+export AXI4_SyncBuffer_IFC (..);
// Clock1 -> Clock2 -> Module #(AXI4_Clock_Crossing_IFC)
-export mkAXI4_ClockCrossing;
+export mkAXI4_SyncBuffer;
// Clock1 -> Module #(AXI4_Clock_Crossing_IFC)
-export mkAXI4_ClockCrossingToCC;
+export mkAXI4_SyncBufferToCC;
// ================================================================
// Bluespec library imports
@@ -31,7 +31,7 @@ import Clocks :: *;
import Connectable :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Cur_Cycle :: *;
import GetPut_Aux :: *;
@@ -40,178 +40,139 @@ import Semi_FIFOF :: *;
// ================================================================
// Project imports
-import AXI4_Types :: *;
-import AXI_SyncBuffer :: *;
-import AXI4_Xactors :: *;
+import AXI4_Types :: *;
+import AXI4_BSV_RTL :: *;
+import AXIx_SyncBuffer :: *;
// ================================================================
-// Clock1 -> Clock2 -> AXI4_S_IFC_1 -> Module #(AXI4_S_IFC_2)
-// Clock1 should be same clock as axi4_S_1
-// Clock2 is clock of result axi4_S_2
-
-module mkAXI4_S_Clock_Crosser
- #(Integer depth,
- Clock clk1, Reset rst1,
- Clock clk2, Reset rst2,
- AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user) axi4_S_1)
- (AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user));
-
- // Transactor towards ifc1
- AXI4_M_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user)
- axi4_M_xactor <- mkAXI4_M_Xactor (clocked_by clk1, reset_by rst1);
-
- // Syncbuffer between transactors
- AXI_SyncBuffer_IFC #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user),
- AXI4_Wr_Data #(wd_data, wd_user),
- AXI4_Wr_Resp #(wd_id, wd_user),
- AXI4_Rd_Addr #(wd_id, wd_addr, wd_user),
- AXI4_Rd_Data #(wd_id, wd_data, wd_user))
- axi4_syncbuf <- mkAXI_SyncBuffer (depth, clk2, rst2, clk1, rst1);
-
- // Transactor with ifc2
- AXI4_S_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user)
- axi4_S_xactor <- mkAXI4_S_Xactor (clocked_by clk2, reset_by rst2);
+// Function to transform an AXI4_S_IFC with a clock crosser
+// Clock1 -> Clock2 -> AXI4_S_IFC (on clock2) -> Module #(AXI4_S_IFC (on clock 1))
+// Clock1 is the upstream clock
+// Clock2 is the downstream clock
+
+module mkAXI4_S_Clock_Crosser #(Integer depth,
+ Clock clk1, Reset rst1,
+ Clock clk2, Reset rst2,
+ AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user) ifc_S)
+ (AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user));
+
+ AXIx_SyncBuffer_IFC #(AXI4_AW #(wd_id, wd_addr, wd_user),
+ AXI4_W #(wd_data, wd_user),
+ AXI4_B #(wd_id, wd_user),
+ AXI4_AR #(wd_id, wd_addr, wd_user),
+ AXI4_R #(wd_id, wd_data, wd_user))
+ axi4_syncbuf <- mkAXIx_SyncBuffer (depth, clk1, rst1, clk2, rst2);
// ----------------
- mkConnection (axi4_M_xactor.axi_side, axi4_S_1);
-
- mkConnection (axi4_M_xactor.i_wr_addr, axi4_syncbuf.to_S.o_aw);
- mkConnection (axi4_M_xactor.i_wr_data, axi4_syncbuf.to_S.o_w);
- mkConnection (axi4_M_xactor.o_wr_resp, axi4_syncbuf.to_S.i_b);
- mkConnection (axi4_M_xactor.i_rd_addr, axi4_syncbuf.to_S.o_ar);
- mkConnection (axi4_M_xactor.o_rd_data, axi4_syncbuf.to_S.i_r);
-
- mkConnection (axi4_syncbuf.from_M.i_aw, axi4_S_xactor.o_wr_addr);
- mkConnection (axi4_syncbuf.from_M.i_w, axi4_S_xactor.o_wr_data);
- mkConnection (axi4_syncbuf.from_M.o_b, axi4_S_xactor.i_wr_resp);
- mkConnection (axi4_syncbuf.from_M.i_ar, axi4_S_xactor.o_rd_addr);
- mkConnection (axi4_syncbuf.from_M.o_r, axi4_S_xactor.i_rd_data);
+ mkConnection (axi4_syncbuf.to_S.o_aw, ifc_S.i_AW);
+ mkConnection (axi4_syncbuf.to_S.o_w, ifc_S.i_W);
+ mkConnection (axi4_syncbuf.to_S.i_b, ifc_S.o_B);
+ mkConnection (axi4_syncbuf.to_S.o_ar, ifc_S.i_AR);
+ mkConnection (axi4_syncbuf.to_S.i_r, ifc_S.o_R);
// ----------------
// INTERFACE
- let axi4_S_2 = axi4_S_xactor.axi_side;
- return axi4_S_2;
+ interface i_AW = axi4_syncbuf.from_M.i_aw;
+ interface i_W = axi4_syncbuf.from_M.i_w;
+ interface o_B = axi4_syncbuf.from_M.o_b;
+ interface i_AR = axi4_syncbuf.from_M.i_ar;
+ interface o_R = axi4_syncbuf.from_M.o_r;
endmodule
// ================================================================
-// Clock1 -> Clock2 -> AXI4_M_IFC_1 -> Module #(AXI4_M_IFC_2)
-// Clock1 should be same clock as axi4_M_1
-// Clock2 is clock of result axi4_M_2
-
-module mkAXI4_M_Clock_Crosser
- #(Integer depth,
- Clock clk1, Reset rst1,
- Clock clk2, Reset rst2,
- AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user) axi4_M_1)
- (AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user));
+// Function to transform an AXI4_M_IFC with a clock crosser
+// Clock1 -> Clock2 -> AXI4_M_IFC (on clock1) -> Module #(AXI4_M_IFC (on clock 2))
+// Clock1 is the upstream clock
+// Clock2 is the downstream clock
- // Transactor towards ifc1
- AXI4_S_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user)
- axi4_S_xactor <- mkAXI4_S_Xactor (clocked_by clk1, reset_by rst1);
+module mkAXI4_M_Clock_Crosser #(Integer depth,
+ Clock clk1, Reset rst1,
+ Clock clk2, Reset rst2,
+ AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user) ifc_M)
+ (AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user));
// Syncbuffer between transactors
- AXI_SyncBuffer_IFC #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user),
- AXI4_Wr_Data #(wd_data, wd_user),
- AXI4_Wr_Resp #(wd_id, wd_user),
- AXI4_Rd_Addr #(wd_id, wd_addr, wd_user),
- AXI4_Rd_Data #(wd_id, wd_data, wd_user))
- axi4_syncbuf <- mkAXI_SyncBuffer (depth, clk1, rst1, clk2, rst2);
+ AXIx_SyncBuffer_IFC #(AXI4_AW #(wd_id, wd_addr, wd_user),
+ AXI4_W #(wd_data, wd_user),
+ AXI4_B #(wd_id, wd_user),
+ AXI4_AR #(wd_id, wd_addr, wd_user),
+ AXI4_R #(wd_id, wd_data, wd_user))
- // Transactor with ifc2
- AXI4_M_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user)
- axi4_M_xactor <- mkAXI4_M_Xactor (clocked_by clk2, reset_by rst2);
+ axi4_syncbuf <- mkAXIx_SyncBuffer (depth, clk1, rst1, clk2, rst2);
// ----------------
- mkConnection (axi4_M_1, axi4_S_xactor.axi_side);
-
- mkConnection (axi4_S_xactor.o_wr_addr, axi4_syncbuf.from_M.i_aw);
- mkConnection (axi4_S_xactor.o_wr_data, axi4_syncbuf.from_M.i_w);
- mkConnection (axi4_S_xactor.i_wr_resp, axi4_syncbuf.from_M.o_b);
- mkConnection (axi4_S_xactor.o_rd_addr, axi4_syncbuf.from_M.i_ar);
- mkConnection (axi4_S_xactor.i_rd_data, axi4_syncbuf.from_M.o_r);
-
- mkConnection (axi4_syncbuf.to_S.o_aw, axi4_M_xactor.i_wr_addr);
- mkConnection (axi4_syncbuf.to_S.o_w, axi4_M_xactor.i_wr_data);
- mkConnection (axi4_syncbuf.to_S.i_b, axi4_M_xactor.o_wr_resp);
- mkConnection (axi4_syncbuf.to_S.o_ar, axi4_M_xactor.i_rd_addr);
- mkConnection (axi4_syncbuf.to_S.i_r, axi4_M_xactor.o_rd_data);
+ mkConnection (ifc_M.o_AW, axi4_syncbuf.from_M.i_aw);
+ mkConnection (ifc_M.o_W, axi4_syncbuf.from_M.i_w);
+ mkConnection (ifc_M.i_B, axi4_syncbuf.from_M.o_b);
+ mkConnection (ifc_M.o_AR, axi4_syncbuf.from_M.i_ar);
+ mkConnection (ifc_M.i_R, axi4_syncbuf.from_M.o_r);
// ----------------
// INTERFACE
- let axi4_M_2 = axi4_M_xactor.axi_side;
- return axi4_M_2;
+ interface o_AW = axi4_syncbuf.to_S.o_aw;
+ interface o_W = axi4_syncbuf.to_S.o_w;
+ interface i_B = axi4_syncbuf.to_S.i_b;
+ interface o_AR = axi4_syncbuf.to_S.o_ar;
+ interface i_R = axi4_syncbuf.to_S.i_r;
endmodule
// ================================================================
+// Standalone clock-crosser with M and S interfaces
// Clock1 -> Clock2 -> Module #(AXI4_Clock_Crossing_IFC)
-// ----------------
-
-interface AXI4_ClockCrossing_IFC #(numeric type id_,
- numeric type addr_,
- numeric type data_,
- numeric type user_);
- interface AXI4_S_IFC #(id_, addr_, data_, user_) from_M;
+interface AXI4_SyncBuffer_IFC #(numeric type id_,
+ numeric type addr_,
+ numeric type data_,
+ numeric type user_);
+ interface AXI4_S_IFC #(id_, addr_, data_, user_) from_M;
interface AXI4_M_IFC #(id_, addr_, data_, user_) to_S;
endinterface
// ----------------
-module mkAXI4_ClockCrossing
- #(Clock clock_M, Reset reset_M,
- Clock clock_S, Reset reset_S)
- (AXI4_ClockCrossing_IFC #(id_, addr_, data_, user_));
-
- // SyncFIFOs for the 5 channels
-
- SyncFIFOIfc #(AXI4_Wr_Addr #(id_, addr_, user_))
- f_aw <- mkSyncFIFO (4, clock_M, reset_M, clock_S);
-
- SyncFIFOIfc #(AXI4_Wr_Data #(data_, user_))
- f_w <- mkSyncFIFO (4, clock_M, reset_M, clock_S);
-
- SyncFIFOIfc #(AXI4_Wr_Resp #(id_, user_))
- f_b <- mkSyncFIFO (4, clock_S, reset_S, clock_M);
-
- SyncFIFOIfc #(AXI4_Rd_Addr #(id_, addr_, user_))
- f_ar <- mkSyncFIFO (4, clock_M, reset_M, clock_S);
+module mkAXI4_SyncBuffer #(Integer depth,
+ Clock clock_M, Reset reset_M,
+ Clock clock_S, Reset reset_S)
+ (AXI4_SyncBuffer_IFC #(id_, addr_, data_, user_));
- SyncFIFOIfc #(AXI4_Rd_Data #(id_, data_, user_))
- f_r <- mkSyncFIFO (4, clock_S, reset_S, clock_M);
-
- // Transactors for each end
-
- AXI4_S_IFC #(id_, addr_, data_, user_)
- xactor_S <- mkAXI4_Xactor_S_3 (f_aw, f_w, f_b, f_ar, f_r,
- clocked_by clock_M,
- reset_by reset_M);
- AXI4_M_IFC #(id_, addr_, data_, user_)
- xactor_M <- mkAXI4_Xactor_M_3 (f_aw, f_w, f_b, f_ar, f_r,
- clocked_by clock_S,
- reset_by reset_S);
+ let axi4_syncbuf <- mkAXIx_SyncBuffer (depth, clock_M, reset_M, clock_S, reset_S);
// ----------------
- interface AXI4_S_IFC from_M = xactor_S;
- interface AXI4_M_IFC to_S = xactor_M;
+ // INTERFACE
+
+ interface AXI4_S_IFC from_M;
+ interface i_AW = axi4_syncbuf.from_M.i_aw;
+ interface i_W = axi4_syncbuf.from_M.i_w;
+ interface o_B = axi4_syncbuf.from_M.o_b;
+ interface i_AR = axi4_syncbuf.from_M.i_ar;
+ interface o_R = axi4_syncbuf.from_M.o_r;
+ endinterface
+ interface AXI4_M_IFC to_S;
+ interface o_AW = axi4_syncbuf.to_S.o_aw;
+ interface o_W = axi4_syncbuf.to_S.o_w;
+ interface i_B = axi4_syncbuf.to_S.i_b;
+ interface o_AR = axi4_syncbuf.to_S.o_ar;
+ interface i_R = axi4_syncbuf.to_S.i_r;
+ endinterface
endmodule
// ----------------------------------------------------------------
// Same as above, with S-side using current-clock
-module mkAXI4_ClockCrossingToCC
- #(Clock clock_M, Reset reset_M)
- (AXI4_ClockCrossing_IFC #(id_, addr_, data_, user_));
+module mkAXI4_SyncBufferToCC #(Integer depth,
+ Clock clock_M, Reset reset_M)
+ (AXI4_SyncBuffer_IFC #(id_, addr_, data_, user_));
let clock_S <- exposeCurrentClock;
let reset_S <- exposeCurrentReset;
- let crossing <- mkAXI4_ClockCrossing (clock_M, reset_M,
- clock_S, reset_S);
-
+ let crossing <- mkAXI4_SyncBuffer (depth,
+ clock_M, reset_M,
+ clock_S, reset_S);
return crossing;
endmodule
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_DDR_Model.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_DDR_Model.bsv
deleted file mode 100644
index 842c9c7..0000000
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_DDR_Model.bsv
+++ /dev/null
@@ -1,243 +0,0 @@
-// Copyright (c) 2016-2024 Bluespec, Inc. All Rights Reserved.
-//
-// SPDX-License-Identifier: BSD-3-Clause
-
-// A simple memory-model, to be used in simulation, with an AXI4 interface.
-// Can optionally pre-load data with a memhex file.
-// Author: Rishiyur S. Nikhil
-
-package AXI4_DDR_Model;
-
-// ================================================================
-// BSV lib imports
-
-import Vector :: *;
-import RegFile :: *;
-import Connectable :: *;
-
-// ----------------
-// BSV additional libs
-
-import Semi_FIFOF :: *;
-import Cur_Cycle :: *;
-
-// ================================================================
-// Project imports
-
-import AXI4_Types :: *;
-import AXI4_Deburster :: *;
-
-// ================================================================
-
-export mkDDR_A_Model;
-export AXI4_16_64_512_0_S_IFC;
-
-// ================================================================
-// DDR base and limit addresses
-
-Bit #(64) ddr_A_base = 'h_0_0000_0000;
-Bit #(64) ddr_A_lim = 'h_0_8000_0000;
-
-// ================================================================
-
-typedef AXI4_S_IFC #(16, // Id
- 64, // Addr
- 512, // Data
- 0) // User
- AXI4_16_64_512_0_S_IFC;
-
-typedef AXI4_S_Xactor_IFC #(16, // Id
- 64, // Addr
- 512, // Data
- 0) // User
- AXI4_16_64_512_0_S_Xactor_IFC;
-
-// ================================================================
-
-function Bit #(512) fv_new_data (Bit #(512) old_data, Bit #(512) new_data, Bit #(64) strb);
- function Bit #(8) f (Integer j);
- return ((strb [j] == 1'b1) ? 'hFF : 'h00);
- endfunction
- Vector #(64, Bit #(8)) v_mask = genWith (f);
- Bit #(512) mask = pack (v_mask);
- return ((old_data & (~ mask)) | (new_data & mask));
-endfunction
-
-// ================================================================
-// DDR_A
-// Supports bursts
-
-(* synthesize *)
-module mkDDR_A_Model (AXI4_16_64_512_0_S_IFC);
- let ifc <- mkMem_Model (0, // verbosity
- 0, // ddr_num
- False, // init_with_memhex
- "DDR_A.memhex512", // memhex_filename
- ddr_A_base, // byte_addr_base
- ddr_A_lim, // byte_addr_lim
- 'h_1_0000_0000); // bytes_implemented (4 GB)
- AXI4_Deburster_IFC #(16, 64, 512, 0) deburster <- mkAXI4_Deburster;
- mkConnection (deburster.to_S, ifc);
- return deburster.from_M;
-endmodule
-
-// ================================================================
-// Common implementation
-// - ddr_num is unique id for each DDR (A=0, B=1, C=2, D=3)
-// - init_with_memhex and memhex_file are for optional initialization from a memhex512
-// - byte_addr_base and byte_addr_lim are the range of byte-addrs served by this DDR
-// (in AWS: 16GB)
-// - bytes_implemented are the # of bytes implemented (on top of byte_addr_base)
-// which need not cover until addr_last.
-// WARNING: This is a simplified model: does not support AXI4 bursts.
-// Use a deburster in front of this, if needed.
-
-module mkMem_Model #(Integer verbosity,
- Bit #(2) ddr_num,
- Bool init_with_memhex,
- String memhex_filename,
- Bit #(64) byte_addr_base,
- Bit #(64) byte_addr_lim,
- Bit #(64) bytes_implemented_param)
- (AXI4_16_64_512_0_S_IFC);
-
- // Note: each 'word' in the RegFile is 512b = 64B => uses 6 lsbs of address.
- Bit #(64) bytes_implemented = min (bytes_implemented_param, byte_addr_lim - byte_addr_base);
- Bit #(64) words_implemented = (bytes_implemented >> 6);
- Bit #(64) addr_align_mask = (~ 'h3F);
-
- RegFile #(Bit #(64), Bit #(512)) rf <- (init_with_memhex
- ? mkRegFileLoad (memhex_filename,
- 0,
- words_implemented - 1)
- : mkRegFile (0, words_implemented - 1));
-
- AXI4_16_64_512_0_S_Xactor_IFC axi4_xactor <- mkAXI4_S_Xactor;
-
- Bit #(64) implem_addr_lim = byte_addr_base + (bytes_implemented & addr_align_mask);
-
- // ================================================================
- // BEHAVIOR
-
- // ----------------
- // For debugging only
-
- Reg #(Bool) rg_display_info <- mkReg (False); // To get debugging info => True
-
- rule rl_info (rg_display_info);
- rg_display_info <= False;
-
- $display ("INFO: %m");
- $display (" base 0x%16h lim 0x%16h implemented 0x%16h",
- byte_addr_base, byte_addr_lim, bytes_implemented);
- if (init_with_memhex)
- $display (" initialized from: %s", memhex_filename);
- endrule
-
- // ----------------
- // Read requests
-
- rule rl_rd_req;
- let rda <- pop_o (axi4_xactor.o_rd_addr);
-
- Bool ok1 = ((byte_addr_base <= rda.araddr) && (rda.araddr < byte_addr_lim));
- Bool ok2 = (rda.araddr < implem_addr_lim);
- let offset_b = rda.araddr - byte_addr_base;
- let offset_W = (offset_b >> 6);
-
- // Default error response
- let rdd = AXI4_Rd_Data {rid: rda.arid,
- rdata: zeroExtend (rda.araddr), // To help debugging
- rresp: axi4_resp_slverr,
- rlast: True,
- ruser: ?};
-
- if (! ok1) begin
- $display ("%0d: Mem_Model [%0d]: rl_rd_req: addr %0h -> OUT OF BOUNDS",
- cur_cycle, ddr_num, rda.araddr);
- $display (" base %016h lim %016h", byte_addr_base, byte_addr_lim);
- end
- else if (! ok2) begin
- $display ("%0d: Mem_Model [%0d]: rl_rd_req: addr %0h -> OUT OF IMPLEMENTED BOUNDS",
- cur_cycle, ddr_num, rda.araddr);
- $display (" base %016h implementation lim %016h",
- byte_addr_base, implem_addr_lim);
- end
- else begin
- let data = rf.sub (offset_W);
- rdd = AXI4_Rd_Data {rid: rda.arid,
- rdata: data,
- rresp: axi4_resp_okay,
- rlast: True,
- ruser: ?};
- if (verbosity > 0) begin
- $display ("%0d: Mem_Model [%0d]: rl_rd_req: addr %0h",
- cur_cycle, ddr_num, rda.araddr);
- $display (" data_hi %064h", data [511:256]);
- $display (" data_lo %064h", data [255:0]);
- end
- end
-
- axi4_xactor.i_rd_data.enq (rdd);
- endrule
-
- // ----------------
- // Write requests
-
- rule rl_wr_req;
- let wra <- pop_o (axi4_xactor.o_wr_addr);
- let wrd <- pop_o (axi4_xactor.o_wr_data);
-
- Bool ok1 = ((byte_addr_base <= wra.awaddr) && (wra.awaddr < byte_addr_lim));
- Bool ok2 = (wra.awaddr < implem_addr_lim);
- let offset_b = wra.awaddr - byte_addr_base;
- let offset_W = (offset_b >> 6);
-
- // Default error response
- let wrr = AXI4_Wr_Resp {bid: wra.awid, bresp: axi4_resp_slverr, buser: ?};
-
- if (! ok1) begin
- $display ("%0d: Mem_Model [%0d]: rl_wr_req: OUT OF BOUNDS",
- cur_cycle, ddr_num);
- $display (" addr %0h <= %0h strb %0h",
- wra.awaddr, wrd.wdata, wrd.wstrb);
- $display (" base %016h lim %016h", byte_addr_base, byte_addr_lim);
- end
- else if (! ok2) begin
- $display ("%0d: Mem_Model [%0d]: rl_wr_req: OUT OF IMPLEMENTED BOUNDS",
- cur_cycle, ddr_num);
- $display (" addr %0h <= %0h strb %0h",
- wra.awaddr, wrd.wdata, wrd.wstrb);
- $display (" base %016h implementation lim %016h",
- byte_addr_base, implem_addr_lim);
- end
- else begin
- let old_data = rf.sub (offset_W);
- let new_data = fv_new_data (old_data, wrd.wdata, wrd.wstrb);
- rf.upd (offset_W, new_data);
- if (verbosity > 1) begin
- $display (" Old: %h", old_data);
- $display (" New: %h", new_data);
- end
- wrr = AXI4_Wr_Resp {bid: wra.awid, bresp: axi4_resp_okay, buser: ?};
-
- if (verbosity > 0) begin
- $display ("%0d: Mem_Model [%0d]: rl_wr_req: addr %0h strb %0h",
- cur_cycle, ddr_num, wra.awaddr, wrd.wstrb);
- $display (" data_hi %064h", wrd.wdata [511:256]);
- $display (" data_lo %064h", wrd.wdata [255:0]);
- end
- end
-
- axi4_xactor.i_wr_resp.enq (wrr);
- endrule
-
- // ================================================================
- // INTERFACE
-
- return axi4_xactor.axi_side;
-endmodule
-
-// ================================================================
-
-endpackage
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_Deburster.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_Deburster.bsv
index effdd5c..4bef2cc 100644
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_Deburster.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4/AXI4_Deburster.bsv
@@ -1,13 +1,17 @@
-// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved
-//
+// Copyright (c) 2019-2023 Bluespec, Inc. All Rights Reserved
+// Copyright (c) 2024 Rishiyur S. Nikhil.
+
// SPDX-License-Identifier: BSD-3-Clause
package AXI4_Deburster;
// ================================================================
// This package defines a AXI4-S-to-AXI4-S conversion module.
-// The M-side interface is an AXI4-S that carries no burst transactions.
-// The S-side interface is an AXI4-S that carries burst transactions.
+// The upstream interface (AXI4-S) is an AXI4-S that carries burst transactions.
+// The module argument is the downstream interface, also an AXI4-S,
+// which does not have bursts.
+// i.e., a multi-beat burst request from upstream is sent to the
+// downstream as a series of 1-beat requests.
// ================================================================
// Bluespec library imports
@@ -18,125 +22,77 @@ import SpecialFIFOs :: *;
import ConfigReg :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Cur_Cycle :: *;
-
-// ================================================================
-// Project imports
-
import Semi_FIFOF :: *;
-import AXI4_Types :: *;
-// ================================================================
-// The interface for the fabric module
+// ----------------
+// Project imports
-interface AXI4_Deburster_IFC #(numeric type wd_id,
- numeric type wd_addr,
- numeric type wd_data,
- numeric type wd_user);
- method Action reset;
+import AXI4_Types :: *;
- // From M
- interface AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user) from_M;
+// ****************************************************************
+// Verbosity during simulation on stdout (edit this as desired):
+// 0: quiet
+// 1: display start of burst
+// 2: display detail
- // To S
- interface AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user) to_S;
-endinterface
+Integer verbosity = 0;
-// ================================================================
+// ****************************************************************
// The Deburster module
-module mkAXI4_Deburster (AXI4_Deburster_IFC #(wd_id, wd_addr, wd_data, wd_user))
+module mkAXI4_Deburster #(AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user) ifc_S)
+ (AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user))
provisos (Add #(a__, 8, wd_addr));
- // 0 quiet; 1: display start of burst; 2: display all traffic
- Integer verbosity = 0;
+ // Buffer facing M
+ AXI4_Buffer_IFC #(wd_id, wd_addr, wd_data, wd_user) xactor_from_M <- mkAXI4_Buffer;
- Reg #(Bool) rg_reset <- mkReg (True);
-
- // Transactor facing M
- AXI4_S_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user)
- xaxtor_from_M <- mkAXI4_S_Xactor;
-
- // Transactor facing S
- AXI4_M_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user)
- xactor_to_S <- mkAXI4_M_Xactor;
+ // ----------------
+ // Write-transaction book-keeping
- // On a write-transaction, this register is the W-channel burst beat count
- // (0 => start of burst)
+ // This reg is W-channel burst beat count (0 => start of burst)
Reg #(AXI4_Len) rg_w_beat_count <- mkReg (0);
- // On a write-transaction, records awlen for S
- // Size of FIFO should cover S latency
+ // Records awlen.
+ // Size of FIFO should cover S latency (because used on B to
+ // combine B responses).
FIFOF #(AXI4_Len) f_w_awlen <- mkSizedFIFOF (4);
- // On a write-transaction, this register is the B-channel burst
- // beat count which is the number of individual (non-burst)
- // responses from the S to be combined into a single burst response
- // to M.
- // (0 => ready for next burst)
+ // This reg is the B-channel burst beat count which is the number
+ // of individual (non-burst) responses from the S to be combined
+ // into a single burst response to M. (0 => ready for next burst)
Reg #(AXI4_Len) rg_b_beat_count <- mkReg (0);
- // On a burst write-transaction, all the individual S responses may
- // not have the same 'resp' on the B channel. This register
- // remembers the first 'non-okay' resp (if any), to be returned to
- // M in the burst response.
+ // All individual S responses may not have the same 'resp' on the B
+ // channel. This reg remembers first 'non-okay' resp (if any), to
+ // be returned to M in the burst response.
Reg #(AXI4_Resp) rg_b_resp <- mkReg (axi4_resp_okay);
- // On a read-transaction, records arlen for S
- // Size of FIFO should cover S latency
+ // ----------------
+ // Read-transaction book-keeping
+
+ // Records arlen for S.
+ // Size of FIFO should cover S latency (because used on R to
+ // combine R-response into a burst).
FIFOF #(AXI4_Len) f_r_arlen <- mkSizedFIFOF (4);
- // On a read-transaction, this register is the AR-channel burst beat count
- // (0 => start of next burst)
+ // This reg is the AR-channel burst beat count (0 => start of next burst)
Reg #(AXI4_Len) rg_ar_beat_count <- mkReg (0);
- // On a read-transaction, this register is the R-channel burst beat count
- // (0 => ready for next burst)
+ // This reg is the R-channel burst beat count (0 => ready for next burst)
Reg #(AXI4_Len) rg_r_beat_count <- mkReg (0);
// ----------------------------------------------------------------
- // Compute address for beat
-
-// function ActionValue#(Bit #(wd_addr)) fv_addr_for_beat (Bit #(wd_addr) start_addr,
-// AXI4_Size axsize,
-// AXI4_Burst axburst,
-// AXI4_Len axlen,
-// AXI4_Len beat_count);
-//
-// actionvalue
-// // For incrementing bursts this address is the next address
-// Bit #(wd_addr) addr = start_addr;
-// addr = start_addr + (1 << pack (axsize));
-//
-// // The actual length of the burst is one more than indicated by axlen
-// Bit #(wd_addr) burst_len = zeroExtend (axlen) + 1;
-//
-// // find the wrap boundary bit - this becomes the mask - will only work
-// // for burst lengths which are a power of two
-// Bit #(wd_addr) wrap_boundary = (burst_len << pack (axsize));
-//
-// // For wrapping bursts the wrap_mask needs to be applied to check if the
-// // wrapping boundary has been reached
-// if (axburst == axburst_wrap) begin
-// $display ("%0d: %m::AXI4_Deburster: wrapping burst. boundary: (%0x). addr: (%0x)", cur_cycle, wrap_boundary, addr);
-// // The wrapping condition
-// if ((addr % wrap_boundary) == 0) begin
-// // wrap the address - retain all bits except the wrap boundary bit
-// addr = addr & (~wrap_boundary);
-// $display ("%0d: %m::AXI4_Deburster: wrapping burst. Wrapping: addr: (%0x)", cur_cycle, addr);
-// end
-// end
-// return addr;
-// endactionvalue
-// endfunction
-
- function Bit #(wd_addr) fv_addr_for_beat (Bit #(wd_addr) start_addr,
- AXI4_Size axsize,
- AXI4_Burst axburst,
- AXI4_Len axlen,
- AXI4_Len beat_count);
+ // Compute axaddr for beat
+
+ function Bit #(wd_addr) fv_axaddr_for_beat (Bit #(wd_addr) start_addr,
+ AXI4_Size axsize,
+ AXI4_Burst axburst,
+ AXI4_Len axlen,
+ AXI4_Len beat_count);
// For incrementing bursts this address is the next address
Bit #(wd_addr) addr = start_addr;
@@ -157,109 +113,92 @@ module mkAXI4_Deburster (AXI4_Deburster_IFC #(wd_id, wd_addr, wd_data, wd_user))
return addr;
endfunction
- // ----------------------------------------------------------------
- // RESET
-
- rule rl_reset (rg_reset);
- if (verbosity >= 1)
- $display ("%0d: %m::AXI4_Deburster.rl_reset", cur_cycle);
- xaxtor_from_M.reset;
- xactor_to_S.reset;
-
- f_w_awlen.clear;
- rg_w_beat_count <= 0;
- rg_b_beat_count <= 0;
- rg_b_resp <= axi4_resp_okay;
-
- f_r_arlen.clear;
- rg_ar_beat_count <= 0;
- rg_r_beat_count <= 0;
-
- rg_reset <= False;
- endrule
-
- // ----------------------------------------------------------------
+ // ================================================================
// BEHAVIOR
- Reg #(Bit #(wd_addr)) rg_last_beat_waddr <- mkRegU;
// ----------------
- // Wr requests (AW and W channels)
+ // AW and W channels (write requests)
+
+ Reg #(Bit #(wd_addr)) rg_last_beat_waddr <- mkRegU;
- rule rl_wr_xaction_M_to_S;
- AXI4_Wr_Addr #(wd_id, wd_addr, wd_user) a_in = xaxtor_from_M.o_wr_addr.first;
- AXI4_Wr_Data #(wd_data, wd_user) d_in = xaxtor_from_M.o_wr_data.first;
+ rule rl_AW_W;
+ AXI4_AW #(wd_id, wd_addr, wd_user) aw_in = xactor_from_M.ifc_M.o_AW.first;
+ AXI4_W #(wd_data, wd_user) w_in = xactor_from_M.ifc_M.o_W.first;
// Construct output AW item
- let a_out = a_in;
- // For the first beat the address is unchanged from the address in the
- // input request, for the remaining beats we have the update the address
+ let aw_out = aw_in;
+ // For the first beat the address is unchanged from the address
+ // in the input request, for the remaining beats the address is
// based on the previous address used
- if (rg_w_beat_count != 0) begin
- a_out.awaddr = fv_addr_for_beat (rg_last_beat_waddr, a_in.awsize, a_in.awburst, a_in.awlen, rg_w_beat_count);
- end
+ if (rg_w_beat_count != 0)
+ aw_out.awaddr = fv_axaddr_for_beat (rg_last_beat_waddr,
+ aw_in.awsize,
+ aw_in.awburst,
+ aw_in.awlen,
+ rg_w_beat_count);
- a_out.awlen = 0;
- a_out.awburst = axburst_fixed; // Not necessary when awlen=1, but S may be finicky
+ aw_out.awlen = 0;
+ aw_out.awburst = axburst_fixed; // Not necessary when awlen=1, but S may be finicky
// Set WLAST to true since this is always last beat of outgoing xaction (awlen=1)
- let d_out = d_in;
- d_out.wlast = True;
+ let w_out = w_in;
+ w_out.wlast = True;
// Send to S
- xactor_to_S.i_wr_addr.enq (a_out);
- xactor_to_S.i_wr_data.enq (d_out);
+ ifc_S.i_AW.enq (aw_out);
+ ifc_S.i_W.enq (w_out);
- xaxtor_from_M.o_wr_data.deq;
+ xactor_from_M.ifc_M.o_W.deq;
// Remember burst length so that individual responses from S can
// be combined into a single burst response to M.
if (rg_w_beat_count == 0)
- f_w_awlen.enq (a_in.awlen);
+ f_w_awlen.enq (aw_in.awlen);
- if (rg_w_beat_count < a_in.awlen) begin
+ if (rg_w_beat_count < aw_in.awlen) begin
rg_w_beat_count <= rg_w_beat_count + 1;
end
else begin
// Last beat of incoming burst; done with AW item
- xaxtor_from_M.o_wr_addr.deq;
+ xactor_from_M.ifc_M.o_AW.deq;
rg_w_beat_count <= 0;
// Simulation-only assertion-check (no action, just display assertion failure)
// Last incoming beat must have WLAST = 1
- if (! d_in.wlast) begin
- $display ("%0d: ERROR: %m::AXI4_Deburster.rl_wr_xaction_M_to_S: m -> s",
+ if (! w_in.wlast) begin
+ $display ("%0d: ERROR: AXI4_Deburster.rl_AW_W: m -> s",
cur_cycle);
- $display (" WLAST not set on last data beat (awlen = %0d)", a_in.awlen);
- $display (" ", fshow (d_in));
+ $display (" WLAST not set on last data beat (awlen = %0d)", aw_in.awlen);
+ $display (" ", fshow (w_in));
end
end
// Remember this beat's address for calculating the next beat address.
// This is necessary to support wrapping bursts
- rg_last_beat_waddr <= a_out.awaddr;
+ rg_last_beat_waddr <= aw_out.awaddr;
// Debugging
if (verbosity > 0) begin
- $display ("%0d: %m::AXI4_Deburster.rl_wr_xaction_M_to_S: m -> s, beat %0d",
+ $display ("%0d: AXI4_Deburster.rl_AW_W: m -> s, beat %0d",
cur_cycle, rg_w_beat_count);
if (rg_w_beat_count == 0)
- $display (" a_in : ", fshow (a_in));
+ $display (" aw_in : ", fshow (aw_in));
if ((rg_w_beat_count == 0) || (verbosity > 1)) begin
- $display (" d_in : ", fshow (d_in));
- $display (" a_out: ", fshow (a_out));
- $display (" d_out: ", fshow (d_out));
+ $display (" w_in : ", fshow (w_in));
+ $display (" aw_out: ", fshow (aw_out));
+ $display (" w_out: ", fshow (w_out));
end
end
- endrule: rl_wr_xaction_M_to_S
+ endrule: rl_AW_W
// ----------------
- // Wr responses (B channel): consume responses from until the last
- // response for a burst, then respond to M. Remember if any of
- // them was not an 'okay' response.
+ // B channel (write responses): consume responses from until the
+ // last response for a burst, then respond to M. Remember if any
+ // of them was not an 'okay' response.
- rule rl_wr_resp_S_to_M;
- AXI4_Wr_Resp #(wd_id, wd_user) b_in <- pop_o (xactor_to_S.o_wr_resp);
+ rule rl_B_S_to_M;
+ AXI4_B #(wd_id, wd_user) b_in <- pop_o (ifc_S.o_B);
if (rg_b_beat_count < f_w_awlen.first) begin
// Remember first non-okay response (if any) of a burst in rg_b_resp
@@ -270,7 +209,7 @@ module mkAXI4_Deburster (AXI4_Deburster_IFC #(wd_id, wd_addr, wd_data, wd_user))
rg_b_beat_count <= rg_b_beat_count + 1;
if (verbosity > 1) begin
- $display ("%0d: %m::AXI4_Deburster.rl_wr_resp_S_to_M: m <- s, beat %0d",
+ $display ("%0d: AXI4_Deburster.rl_B_S_to_M: m <- s, beat %0d",
cur_cycle, rg_b_beat_count);
$display (" Consuming and discarding beat %0d", rg_b_beat_count);
$display (" ", fshow (b_in));
@@ -281,7 +220,7 @@ module mkAXI4_Deburster (AXI4_Deburster_IFC #(wd_id, wd_addr, wd_data, wd_user))
let b_out = b_in;
if (rg_b_resp != axi4_resp_okay)
b_out.bresp = rg_b_resp;
- xaxtor_from_M.i_wr_resp.enq (b_out);
+ xactor_from_M.ifc_M.i_B.enq (b_out);
f_w_awlen.deq;
@@ -290,7 +229,7 @@ module mkAXI4_Deburster (AXI4_Deburster_IFC #(wd_id, wd_addr, wd_data, wd_user))
rg_b_resp <= axi4_resp_okay;
if (verbosity > 1) begin
- $display ("%0d: %m::AXI4_Deburster.rl_wr_resp_S_to_M: m <- s, beat %0d",
+ $display ("%0d: AXI4_Deburster.rl_B_S_to_M: m <- s, beat %0d",
cur_cycle, rg_b_beat_count);
$display (" b_in: ", fshow (b_in));
$display (" b_out: ", fshow (b_out));
@@ -298,56 +237,56 @@ module mkAXI4_Deburster (AXI4_Deburster_IFC #(wd_id, wd_addr, wd_data, wd_user))
end
endrule
- // ----------------
- // Rd requests (AR channel)
+ // ----------------
+ // AR channel (read requests)
Reg #(Bit #(wd_addr)) rg_last_beat_raddr <- mkRegU;
rule rl_rd_xaction_M_to_S;
- AXI4_Rd_Addr #(wd_id, wd_addr, wd_user) a_in = xaxtor_from_M.o_rd_addr.first;
+ AXI4_AR #(wd_id, wd_addr, wd_user) ar_in = xactor_from_M.ifc_M.o_AR.first;
// Compute forwarded request for each beat, and send
- let a_out = a_in;
+ let ar_out = ar_in;
// For the first beat the address is unchanged from the address in the
// input request, for the remaining beats we have the update the address
// based on the previous address used
if (rg_ar_beat_count != 0) begin
- a_out.araddr = fv_addr_for_beat (rg_last_beat_raddr,
- a_in.arsize,
- a_in.arburst,
- a_in.arlen,
- rg_ar_beat_count);
+ ar_out.araddr = fv_axaddr_for_beat (rg_last_beat_raddr,
+ ar_in.arsize,
+ ar_in.arburst,
+ ar_in.arlen,
+ rg_ar_beat_count);
end
- a_out.arlen = 0;
- a_out.arburst = axburst_fixed; // Not necessary when arlen=1, but S may be finicky
- xactor_to_S.i_rd_addr.enq (a_out);
+ ar_out.arlen = 0;
+ ar_out.arburst = axburst_fixed; // Not necessary when arlen=1, but S may be finicky
+ ifc_S.i_AR.enq (ar_out);
// On first beat, set up the response count
if (rg_ar_beat_count == 0)
- f_r_arlen.enq (a_in.arlen);
+ f_r_arlen.enq (ar_in.arlen);
- if (rg_ar_beat_count < a_in.arlen) begin
+ if (rg_ar_beat_count < ar_in.arlen) begin
rg_ar_beat_count <= rg_ar_beat_count + 1;
end
else begin
// Last beat sent; done with AR item
- xaxtor_from_M.o_rd_addr.deq;
+ xactor_from_M.ifc_M.o_AR.deq;
rg_ar_beat_count <= 0;
end
// Remember this beat's address for calculating the next beat address.
// This is necessary to support wrapping bursts
- rg_last_beat_raddr <= a_out.araddr;
+ rg_last_beat_raddr <= ar_out.araddr;
// Debugging
if (verbosity > 0) begin
- $display ("%0d: %m::AXI4_Deburster.rl_rd_xaction_M_to_S: m -> s, addr %08x beat %0d",
- cur_cycle, a_out.araddr, rg_ar_beat_count);
+ $display ("%0d: AXI4_Deburster.rl_rd_xaction_M_to_S: m -> s, addr %08x beat %0d",
+ cur_cycle, ar_out.araddr, rg_ar_beat_count);
if (rg_ar_beat_count == 0)
- $display (" a_in: ", fshow (a_in));
+ $display (" ar_in: ", fshow (ar_in));
if ((rg_ar_beat_count == 0) || (verbosity > 1))
- $display (" a_out: ", fshow (a_out));
+ $display (" ar_out: ", fshow (ar_out));
end
endrule: rl_rd_xaction_M_to_S
@@ -356,7 +295,7 @@ module mkAXI4_Deburster (AXI4_Deburster_IFC #(wd_id, wd_addr, wd_data, wd_user))
// Rd responses
rule rl_rd_resp_S_to_M;
- AXI4_Rd_Data #(wd_id, wd_data, wd_user) r_in <- pop_o (xactor_to_S.o_rd_data);
+ AXI4_R #(wd_id, wd_data, wd_user) r_in <- pop_o (ifc_S.o_R);
let arlen = f_r_arlen.first;
let r_out = r_in;
@@ -372,11 +311,11 @@ module mkAXI4_Deburster (AXI4_Deburster_IFC #(wd_id, wd_addr, wd_data, wd_user))
f_r_arlen.deq;
end
- xaxtor_from_M.i_rd_data.enq (r_out);
+ xactor_from_M.ifc_M.i_R.enq (r_out);
// Debugging
if (verbosity > 0) begin
- $display ("%0d: %m::AXI4_Deburster.rl_rd_resp_S_to_M: m <- s, beat %0d",
+ $display ("%0d: AXI4_Deburster.rl_rd_resp_S_to_M: m <- s, beat %0d",
cur_cycle, rg_r_beat_count);
if ((rg_r_beat_count == 0) || (verbosity > 1)) begin
$display (" r_in: ", fshow (r_in));
@@ -385,17 +324,12 @@ module mkAXI4_Deburster (AXI4_Deburster_IFC #(wd_id, wd_addr, wd_data, wd_user))
end
endrule: rl_rd_resp_S_to_M
- // ----------------------------------------------------------------
+ // ****************************************************************
// INTERFACE
- method Action reset () if (! rg_reset);
- rg_reset <= True;
- endmethod
-
- interface from_M = xaxtor_from_M.axi_side;
- interface to_S = xactor_to_S .axi_side;
+ return xactor_from_M.ifc_S;
endmodule
-// ================================================================
+// ****************************************************************
endpackage: AXI4_Deburster
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_Extra_Xactors.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_Extra_Xactors.bsv
deleted file mode 100644
index 2d4e5f8..0000000
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_Extra_Xactors.bsv
+++ /dev/null
@@ -1,380 +0,0 @@
-// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved
-//
-// SPDX-License-Identifier: BSD-3-Clause
-
-import FIFOF ::*;
-import Semi_FIFOF::*;
-import AXI4_Types::*;
-
-// This part based on code written in the University of Cambridge Computer Laboratory.
-
-typeclass ToUnguarded #(type a);
- module mkUnguarded #(a x)(a);
-endtypeclass
-
-instance ToUnguarded #(FIFOF_I #(a))
- provisos (Bits#(a, __));
- module mkUnguarded #(FIFOF_I #(a) ifc)(FIFOF_I #(a));
- let enqWire <- mkRWire;
- rule warnDoEnq (isValid(enqWire.wget) && !ifc.notFull);
- $display("WARNING: enqing into an already full FIFOF_I");
- $finish(0);
- endrule
- rule doEnq (isValid(enqWire.wget));
- ifc.enq(enqWire.wget.Valid);
- endrule
- return interface FIFOF_I;
- method notFull = ifc.notFull;
- method enq = enqWire.wset;
- endinterface;
- endmodule
-endinstance
-
-instance ToUnguarded #(FIFOF_O #(a))
- provisos (Bits#(a, _));
- module mkUnguarded#(FIFOF_O #(a) ifc)(FIFOF_O#(a));
- let firstWire <- mkDWire(unpack(0));
- let deqWire <- mkPulseWire;
- rule setFirst; firstWire <= ifc.first; endrule
- rule warnDoDeq (deqWire && !ifc.notEmpty);
- $display("WARNING: deqing from empty FIFOF_O");
- $finish(0);
- endrule
- rule doDeq (deqWire && ifc.notEmpty);
- ifc.deq;
- endrule
- return interface FIFOF_O;
- method notEmpty = ifc.notEmpty;
- method first = firstWire;
- method deq = deqWire.send;
- endinterface;
- endmodule
-endinstance
-
-// --------------------------------------
-
-module mkAXI4_M_Xactor_3 #(aw_t aw, w_t w, b_t b, ar_t ar, r_t r)
- (AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user))
- provisos (To_FIFOF_IO #(aw_t, AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)),
- To_FIFOF_IO #(w_t, AXI4_Wr_Data #(wd_data, wd_user)),
- To_FIFOF_IO #(b_t, AXI4_Wr_Resp #(wd_id, wd_user)),
- To_FIFOF_IO #(ar_t, AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)),
- To_FIFOF_IO #(r_t, AXI4_Rd_Data #(wd_id, wd_data, wd_user)));
-
- FIFOF_O #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) f_wr_addr <- mkUnguarded (to_FIFOF_O (aw));
- FIFOF_O #(AXI4_Wr_Data #(wd_data, wd_user)) f_wr_data <- mkUnguarded (to_FIFOF_O (w));
- FIFOF_I #(AXI4_Wr_Resp #(wd_id, wd_user)) f_wr_resp <- mkUnguarded (to_FIFOF_I (b));
-
- FIFOF_O #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) f_rd_addr <- mkUnguarded (to_FIFOF_O (ar));
- FIFOF_I #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) f_rd_data <- mkUnguarded (to_FIFOF_I (r));
-
- // ----------------------------------------------------------------
- // INTERFACE
-
- return interface AXI4_M_IFC;
- // Wr Addr channel
- method Bool m_awvalid = f_wr_addr.notEmpty;
- method Bit #(wd_id) m_awid = f_wr_addr.first.awid;
- method Bit #(wd_addr) m_awaddr = f_wr_addr.first.awaddr;
- method Bit #(8) m_awlen = f_wr_addr.first.awlen;
- method AXI4_Size m_awsize = f_wr_addr.first.awsize;
- method Bit #(2) m_awburst = f_wr_addr.first.awburst;
- method Bit #(1) m_awlock = f_wr_addr.first.awlock;
- method Bit #(4) m_awcache = f_wr_addr.first.awcache;
- method Bit #(3) m_awprot = f_wr_addr.first.awprot;
- method Bit #(4) m_awqos = f_wr_addr.first.awqos;
- method Bit #(4) m_awregion = f_wr_addr.first.awregion;
- method Bit #(wd_user) m_awuser = f_wr_addr.first.awuser;
- method Action m_awready (Bool awready);
- if (f_wr_addr.notEmpty && awready) f_wr_addr.deq;
- endmethod
-
- // Wr Data channel
- method Bool m_wvalid = f_wr_data.notEmpty;
- method Bit #(wd_data) m_wdata = f_wr_data.first.wdata;
- method Bit #(TDiv #(wd_data, 8)) m_wstrb = f_wr_data.first.wstrb;
- method Bool m_wlast = f_wr_data.first.wlast;
- method Bit #(wd_user) m_wuser = f_wr_data.first.wuser;
- method Action m_wready (Bool wready);
- if (f_wr_data.notEmpty && wready) f_wr_data.deq;
- endmethod
-
- // Wr Response channel
- method Action m_bvalid (Bool bvalid,
- Bit #(wd_id) bid,
- Bit #(2) bresp,
- Bit #(wd_user) buser);
- if (bvalid && f_wr_resp.notFull)
- f_wr_resp.enq (AXI4_Wr_Resp {bid: bid,
- bresp: bresp,
- buser: buser});
- endmethod
-
- method Bool m_bready;
- return f_wr_resp.notFull;
- endmethod
-
- // Rd Addr channel
- method Bool m_arvalid = f_rd_addr.notEmpty;
- method Bit #(wd_id) m_arid = f_rd_addr.first.arid;
- method Bit #(wd_addr) m_araddr = f_rd_addr.first.araddr;
- method Bit #(8) m_arlen = f_rd_addr.first.arlen;
- method AXI4_Size m_arsize = f_rd_addr.first.arsize;
- method Bit #(2) m_arburst = f_rd_addr.first.arburst;
- method Bit #(1) m_arlock = f_rd_addr.first.arlock;
- method Bit #(4) m_arcache = f_rd_addr.first.arcache;
- method Bit #(3) m_arprot = f_rd_addr.first.arprot;
- method Bit #(4) m_arqos = f_rd_addr.first.arqos;
- method Bit #(4) m_arregion = f_rd_addr.first.arregion;
- method Bit #(wd_user) m_aruser = f_rd_addr.first.aruser;
-
- method Action m_arready (Bool arready);
- if (f_rd_addr.notEmpty && arready) f_rd_addr.deq;
- endmethod
-
- // Rd Data channel
- method Action m_rvalid (Bool rvalid, // in
- Bit #(wd_id) rid, // in
- Bit #(wd_data) rdata, // in
- Bit #(2) rresp, // in
- Bool rlast, // in
- Bit #(wd_user) ruser); // in
- if (rvalid && f_rd_data.notFull)
- f_rd_data.enq (AXI4_Rd_Data {rid: rid,
- rdata: rdata,
- rresp: rresp,
- rlast: rlast,
- ruser: ruser});
- endmethod
-
- method Bool m_rready;
- return f_rd_data.notFull;
- endmethod
-
- endinterface;
-endmodule: mkAXI4_M_Xactor_3
-
-module mkAXI4_S_Xactor_3 #(aw_t aw, w_t w, b_t b, ar_t ar, r_t r)
- (AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user))
- provisos (To_FIFOF_IO #(aw_t, AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)),
- To_FIFOF_IO #(w_t, AXI4_Wr_Data #(wd_data, wd_user)),
- To_FIFOF_IO #(b_t, AXI4_Wr_Resp #(wd_id, wd_user)),
- To_FIFOF_IO #(ar_t, AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)),
- To_FIFOF_IO #(r_t, AXI4_Rd_Data #(wd_id, wd_data, wd_user)));
-
- FIFOF_I #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) f_wr_addr <- mkUnguarded (to_FIFOF_I (aw));
- FIFOF_I #(AXI4_Wr_Data #(wd_data, wd_user)) f_wr_data <- mkUnguarded (to_FIFOF_I (w));
- FIFOF_O #(AXI4_Wr_Resp #(wd_id, wd_user)) f_wr_resp <- mkUnguarded (to_FIFOF_O (b));
-
- FIFOF_I #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) f_rd_addr <- mkUnguarded (to_FIFOF_I (ar));
- FIFOF_O #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) f_rd_data <- mkUnguarded (to_FIFOF_O (r));
-
- // ----------------------------------------------------------------
- // INTERFACE
-
- return interface AXI4_S_IFC;
- // Wr Addr channel
- method Action m_awvalid (Bool awvalid,
- Bit #(wd_id) awid,
- Bit #(wd_addr) awaddr,
- Bit #(8) awlen,
- AXI4_Size awsize,
- Bit #(2) awburst,
- Bit #(1) awlock,
- Bit #(4) awcache,
- Bit #(3) awprot,
- Bit #(4) awqos,
- Bit #(4) awregion,
- Bit #(wd_user) awuser);
- if (awvalid && f_wr_addr.notFull)
- f_wr_addr.enq (AXI4_Wr_Addr {awid: awid,
- awaddr: awaddr,
- awlen: awlen,
- awsize: awsize,
- awburst: awburst,
- awlock: awlock,
- awcache: awcache,
- awprot: awprot,
- awqos: awqos,
- awregion: awregion,
- awuser: awuser});
- endmethod
-
- method Bool m_awready;
- return f_wr_addr.notFull;
- endmethod
-
- // Wr Data channel
- method Action m_wvalid (Bool wvalid,
- Bit #(wd_data) wdata,
- Bit #(TDiv #(wd_data, 8)) wstrb,
- Bool wlast,
- Bit #(wd_user) wuser);
- if (wvalid && f_wr_data.notFull)
- f_wr_data.enq (AXI4_Wr_Data {wdata: wdata,
- wstrb: wstrb,
- wlast: wlast,
- wuser: wuser});
- endmethod
-
- method Bool m_wready;
- return f_wr_data.notFull;
- endmethod
-
- // Wr Response channel
- method Bool m_bvalid = f_wr_resp.notEmpty;
- method Bit #(wd_id) m_bid = f_wr_resp.first.bid;
- method Bit #(2) m_bresp = f_wr_resp.first.bresp;
- method Bit #(wd_user) m_buser = f_wr_resp.first.buser;
- method Action m_bready (Bool bready);
- if (bready && f_wr_resp.notEmpty)
- f_wr_resp.deq;
- endmethod
-
- // Rd Addr channel
- method Action m_arvalid (Bool arvalid,
- Bit #(wd_id) arid,
- Bit #(wd_addr) araddr,
- Bit #(8) arlen,
- AXI4_Size arsize,
- Bit #(2) arburst,
- Bit #(1) arlock,
- Bit #(4) arcache,
- Bit #(3) arprot,
- Bit #(4) arqos,
- Bit #(4) arregion,
- Bit #(wd_user) aruser);
- if (arvalid && f_rd_addr.notFull)
- f_rd_addr.enq (AXI4_Rd_Addr {arid: arid,
- araddr: araddr,
- arlen: arlen,
- arsize: arsize,
- arburst: arburst,
- arlock: arlock,
- arcache: arcache,
- arprot: arprot,
- arqos: arqos,
- arregion: arregion,
- aruser: aruser});
- endmethod
-
- method Bool m_arready;
- return f_rd_addr.notFull;
- endmethod
-
- // Rd Data channel
- method Bool m_rvalid = f_rd_data.notEmpty;
- method Bit #(wd_id) m_rid = f_rd_data.first.rid;
- method Bit #(wd_data) m_rdata = f_rd_data.first.rdata;
- method Bit #(2) m_rresp = f_rd_data.first.rresp;
- method Bool m_rlast = f_rd_data.first.rlast;
- method Bit #(wd_user) m_ruser = f_rd_data.first.ruser;
- method Action m_rready (Bool rready);
- if (rready && f_rd_data.notEmpty)
- f_rd_data.deq;
- endmethod
- endinterface;
-endmodule: mkAXI4_S_Xactor_3
-
-// --------------------------------------
-
-typedef union tagged {
- AXI4_Rd_Addr #(wd_id, wd_addr, wd_user) Read;
- AXI4_Wr_Addr #(wd_id, wd_addr, wd_user) Write;
- } AXI4_RdWr_Addr #(numeric type wd_id,
- numeric type wd_addr,
- numeric type wd_user)
-deriving (Bits, FShow);
-
-interface Addr_FIFOF_Pair #(numeric type wd_id,
- numeric type wd_addr,
- numeric type wd_user);
- interface FIFOF #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) ff_read;
- interface FIFOF #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) ff_write;
-endinterface
-
-module mkAddr_FIFOF_Pair (Addr_FIFOF_Pair #(wd_id, wd_addr, wd_user));
- Bool unguarded = True;
- Bool guarded = False;
-
- FIFOF #(AXI4_RdWr_Addr #(wd_id, wd_addr, wd_user)) ff <- mkGFIFOF (guarded, unguarded);
-
- interface FIFOF ff_read;
- method notFull = ff.notFull;
- method Action enq(x);
- ff.enq(tagged Read x);
- endmethod
-
- method notEmpty = (ff.notEmpty && (ff.first matches tagged Read .x ? True : False));
- method first () if (ff.notEmpty &&& ff.first matches tagged Read .x);
- return x;
- endmethod
-
- method Action deq () if (ff.notEmpty &&& ff.first matches tagged Read .x);
- ff.deq;
- endmethod
-
- method Action clear;
- ff.clear;
- endmethod
- endinterface
-
- interface FIFOF ff_write;
- method notFull = ff.notFull;
- method Action enq(x);
- ff.enq(tagged Write x);
- endmethod
-
- method notEmpty = (ff.notEmpty && (ff.first matches tagged Write .x ? True : False));
- method first () if (ff.notEmpty &&& ff.first matches tagged Write .x);
- return x;
- endmethod
-
- method Action deq () if (ff.notEmpty &&& ff.first matches tagged Write .x);
- ff.deq;
- endmethod
-
- method Action clear;
- ff.clear;
- endmethod
- endinterface
-endmodule
-
-module mkAXI4_Serializing_M_Xactor (AXI4_M_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user));
- Addr_FIFOF_Pair #(wd_id, wd_addr, wd_user) f_rdwr_addr <- mkAddr_FIFOF_Pair;
-
- FIFOF #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) f_wr_addr = f_rdwr_addr.ff_write;
- FIFOF #(AXI4_Wr_Data #(wd_data, wd_user)) f_wr_data <- mkFIFOF;
- FIFOF #(AXI4_Wr_Resp #(wd_id, wd_user)) f_wr_resp <- mkFIFOF;
-
- FIFOF #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) f_rd_addr = f_rdwr_addr.ff_read;
- FIFOF #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) f_rd_data <- mkFIFOF;
-
- AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user) m_xactor <- mkAXI4_M_Xactor_3 (f_wr_addr,
- f_wr_data,
- f_wr_resp,
- f_rd_addr,
- f_rd_data);
-
- // ----------------------------------------------------------------
- // INTERFACE
-
- method Action reset;
- f_wr_addr.clear;
- f_wr_data.clear;
- f_wr_resp.clear;
- //f_rd_addr.clear;
- f_rd_data.clear;
- endmethod
-
- // AXI side
- interface axi_side = m_xactor;
-
- // FIFOF side
- interface i_wr_addr = to_FIFOF_I (f_wr_addr);
- interface i_wr_data = to_FIFOF_I (f_wr_data);
- interface o_wr_resp = to_FIFOF_O (f_wr_resp);
-
- interface i_rd_addr = to_FIFOF_I (f_rd_addr);
- interface o_rd_data = to_FIFOF_O (f_rd_data);
-endmodule
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_Fabric.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_Fabric.bsv
index 9f972a9..3d1b015 100644
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_Fabric.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4/AXI4_Fabric.bsv
@@ -1,470 +1,402 @@
// Copyright (c) 2013-2023 Bluespec, Inc. All Rights Reserved
-//
+// Copyright (c) 2024 Rishiyur S. Nikhil.
+
// SPDX-License-Identifier: BSD-3-Clause
package AXI4_Fabric;
-// ================================================================
-// This package defines a fabric connecting CPUs, Memories and DMAs
-// and other IP blocks.
+// ****************************************************************
+// This package defines a module mkAXI4_Fabric with an Empty interface.
+// It is a crossbar connecting a vector of Ms to a vector of Ss.
-// ================================================================
+// It is parameterized by:
+// * number of Ms
+// * number of Ss
+// * widths of the various AXI4 buses.
+// * a "routing function" address -> S num that specifies which S
+// (or none) services a request.
+
+// Note that M-side ID fields (ARID, AWID) are narrower than S-side ID
+// fields (RID, BID). The extra S-side ID bits encode, for each AXI4
+// transaction, which M it came from, so that the response can be
+// routed back appropriately.
+
+// Handles bursts (read and write).
+
+// ****************************************************************
// Bluespec library imports
import Vector :: *;
import FIFOF :: *;
import SpecialFIFOs :: *;
-import ConfigReg :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
-import Cur_Cycle :: *;
+import Semi_FIFOF :: *;
-// ================================================================
+// ----------------
// Project imports
-import Semi_FIFOF :: *;
import AXI4_Types :: *;
// ================================================================
-// The interface for the fabric module
-
-interface AXI4_Fabric_IFC #(numeric type tn_num_M,
- numeric type tn_num_S,
- numeric type wd_id,
- numeric type wd_addr,
- numeric type wd_data,
- numeric type wd_user);
- method Action reset;
- method Action set_verbosity (Bit #(4) verbosity);
-
- // From Ms
- interface Vector #(tn_num_M,
- AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user)) v_from_Ms;
-
- // To Ss
- interface Vector #(tn_num_S,
- AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user)) v_to_Ss;
-endinterface
+// Project exports
-// ================================================================
+export mkAXI4_Fabric;
+
+// ****************************************************************
// The Fabric module
// The function parameter is an address-decode function, which
-// returns (True, S-port-num) if address is mapped to S-port-num
-// (False, ?) if address is unmapped to any S port
-
-module mkAXI4_Fabric #(function Tuple2 #(Bool, Bit #(TLog #(tn_num_S)))
- fn_addr_to_S_num (Bit #(wd_addr) addr))
- (AXI4_Fabric_IFC #(tn_num_M, tn_num_S,
- wd_id, wd_addr, wd_data, wd_user))
-
- provisos (Log #(tn_num_M, log_nm),
- Log #(tn_num_S, log_ns),
- Log #(TAdd #(tn_num_S, 1), log_ns_plus_1),
- Log #(TAdd #(tn_num_M, 1), log_nm_plus_1));
-
- Integer num_M = valueOf (tn_num_M);
- Integer num_S = valueOf (tn_num_S);
+// returns (True, j) if address maps to Sj
+// (False, ?) if address is wild (does not map to any Sj)
+
+module mkAXI4_Fabric #(// Routing function
+ function Tuple2 #(Bool, Bit #(TLog #(tn_num_S)))
+ fn_addr_to_S_num (Bit #(wd_addr) addr),
+ // From Ms
+ Vector #(tn_num_M,
+ AXI4_M_IFC #(wd_id_M, wd_addr, wd_data, wd_user)) v_ifc_M,
+ // To Ss
+ Vector #(tn_num_S,
+ AXI4_S_IFC #(wd_id_S, wd_addr, wd_data, wd_user)) v_ifc_S)
+ (Empty)
+
+ provisos (Log #(tn_num_M, log_nm), // define log_nm
+ Log #(tn_num_S, log_ns), // define log_ns
+ Add #(wd_id_M, log_nm, wd_id_S)); // assert
// 0: quiet; 1: show transactions
- Reg #(Bit #(4)) cfg_verbosity <- mkConfigReg (0);
+ Integer verbosity = 0;
- Reg #(Bool) rg_reset <- mkReg (True);
-
- // Transactors facing Ms
- Vector #(tn_num_M, AXI4_S_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user))
- xactors_from_Ms <- replicateM (mkAXI4_S_Xactor);
-
- // Transactors facing Ss
- Vector #(tn_num_S, AXI4_M_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user))
- xactors_to_Ss <- replicateM (mkAXI4_M_Xactor);
+ Integer num_M = valueOf (tn_num_M);
+ Integer num_S = valueOf (tn_num_S);
// ----------------------------------------------------------------
- // Book-keeping FIFOs and regs
- // - to keep track of which M originated a transaction, in order
- // to route corresponding responses back to that M
- // - to manage wdata channel based on burst info in awaddr channel
- // - to manage requests that do not map to any of the Ss
- // Legal Ss are 0..(num_S-1)
- // The "illegal" value of 'num_S' is used for decode errors (no such S).
- // num_M could be 1 => Bit #(0) to identify a M, but
- // equality on Bit #(0) is dicey, so we always use num_M+1.
- // Size of SizedFIFOs is estimated: should cover round-trip latency to S and back.
-
- // ----------------
- // Write-transaction book-keeping
-
- // On an mi->sj write-transaction, this fifo records sj for M mi
- Vector #(tn_num_M, FIFOF #(Bit #(log_ns_plus_1))) v_f_wr_sjs <- replicateM (mkSizedFIFOF (8));
+ // Write-transaction control:
- // On an mi->sj write-transaction, this fifo records mi for S sj
- Vector #(tn_num_S, FIFOF #(Bit #(log_nm_plus_1))) v_f_wr_mis <- replicateM (mkSizedFIFOF (8));
+ // The AW and W buses are separate and not synchronized, but the
+ // ordering is the same, i.e., in any AXI4 interface, the sequence
+ // of W bursts (W0, W1, ...) is assumed to correspond to the
+ // sequence of AW requests (AW0, AW1, ...).
- // On an mi->sj write-transaction, this fifo records a task (sj, awlen) for W channel
- Vector #(tn_num_M,
- FIFOF #(Tuple2 #(Bit #(log_ns_plus_1),
- AXI4_Len))) v_f_wd_tasks <- replicateM (mkFIFOF);
- // On an mi->sj write-transaction, this register is the W-channel burst beat_count
- // (0 => ready for next burst)
- Vector #(tn_num_M, Reg #(AXI4_Len)) v_rg_wd_beat_count <- replicateM (mkReg (0));
+ // In a fabric, two write-transaction scenarios where the ordering could go wrong:
+ // A. Two M's to one S:
+ // From Mi and Mj, if we send AWi and AWj to Sk, in that order,
+ // then Wi should precede Wj.
+ // Also: beats from the Wi and Wj bursts should not be interleaved.
+ // B. One M to two S's:
+ // From Mi, if we send AWi1 and AWi2 to Sj and Sk, in that order,
+ // then Wi1 should go to Sj and Wi2 should go to Sk
+ //
- // On a write-transaction to non-existent S, record id and user for error response
- Vector #(tn_num_M,
- FIFOF #(Tuple2 #(Bit #(wd_id),
- Bit #(wd_user)))) v_f_wr_err_info <- replicateM (mkSizedFIFOF (8));
+ // For scenario A, we have a FIFO per-Sj which records order of M's
+ // from which it should take Ws.
- // ----------------
- // Read-transaction book-keeping
-
- // On an mi->sj read-transaction, records sj for M mi
- Vector #(tn_num_M, FIFOF #(Bit #(log_ns_plus_1))) v_f_rd_sjs <- replicateM (mkSizedFIFOF (8));
- // On an mi->sj read-transaction, records (mi,arlen) for S sj
- Vector #(tn_num_S,
- FIFOF #(Tuple2 #(Bit #(log_nm_plus_1),
- AXI4_Len))) v_f_rd_mis <- replicateM (mkSizedFIFOF (8));
- // On an mi->sj read-transaction, this register is the R-channel burst beat_count
- // (0 => ready for next burst)
- Vector #(tn_num_S, Reg #(AXI4_Len)) v_rg_r_beat_count <- replicateM (mkReg (0));
-
- // On a read-transaction to non-exisitent S, record id and user for error response
- Vector #(tn_num_M,
- FIFOF #(Tuple3 #(AXI4_Len,
- Bit #(wd_id),
- Bit #(wd_user)))) v_f_rd_err_info <- replicateM (mkSizedFIFOF (8));
-
- // On an mi->non-existent-S read-transaction,
- // this register is the R-channel burst beat_count
- // (0 => ready for next burst)
- Vector #(tn_num_M, Reg #(AXI4_Len)) v_rg_r_err_beat_count <- replicateM (mkReg (0));
+ Vector #(tn_num_S, FIFOF #(Bit #(log_nm))) // FIFO of Mi
+ v_f_W_Mi <- replicateM (mkFIFOF);
- // ----------------------------------------------------------------
- // RESET
+ // For scenario B, we have a FIFO per-Mi which records order of S's
+ // to which it should send Ws.
- rule rl_reset (rg_reset);
- if (cfg_verbosity > 0) begin
- $display ("%0d: rl_reset", cur_cycle);
- $display (" %m");
- end
- for (Integer mi = 0; mi < num_M; mi = mi + 1) begin
- xactors_from_Ms [mi].reset;
+ Vector #(tn_num_M, FIFOF #(Tuple2 #(Bool, Bit #(log_ns)))) // FIFO of Sj
+ v_f_W_Sj <- replicateM (mkFIFOF);
- v_f_wr_sjs [mi].clear;
- v_f_wd_tasks [mi].clear;
- v_rg_wd_beat_count [mi] <= 0;
+ // For wild writes (addr does not map to any Sj), this FIFO records
+ // info to consume the write-burst and then respond with error.
+ // TODO: per-Mi FIFOs would add concurrency.
- v_f_wr_err_info [mi].clear;
+ FIFOF #(Tuple3 #(Bit #(log_nm), // Mi of current AWCHAN req
+ Bit #(wd_id_M), // AWID to reflect into BID
+ Bit #(wd_user))) // AWUSER to reflect into BUSER
+ f_W_wild <- mkFIFOF;
- v_f_rd_sjs [mi].clear;
+ // ----------------
+ // Read-respose merge control
- v_f_rd_err_info [mi].clear;
- end
+ // For "simultaneous" RCHAN responses from Sj1 and Sj2 to the same
+ // Mi, the two bursts must not interleave. Each Sj must "own" Mi
+ // for its full burst.
- for (Integer sj = 0; sj < num_S; sj = sj + 1) begin
- xactors_to_Ss [sj].reset;
- v_f_wr_mis [sj].clear;
- v_f_rd_mis [sj].clear;
- v_rg_r_beat_count [sj] <= 0;
- end
- rg_reset <= False;
- endrule
+ Vector #(tn_num_M, Reg #(Maybe #(Bit #(log_ns))))
+ v_rg_M_RCHAN_owners <- replicateM (mkReg (tagged Invalid));
// ----------------------------------------------------------------
- // BEHAVIOR
+ // Predicates to check if Mi has transaction for Sj
+ // The expression (s_num == fromInteger (sj)) is dodgy when num_S == 1
+ // because it's a Bit#(0) comparision; so special case 'num_S == 1'
- // ----------------------------------------------------------------
- // Predicates to check if M I has transaction for S J
function Bool fv_mi_has_wr_for_sj (Integer mi, Integer sj);
- let addr = xactors_from_Ms [mi].o_wr_addr.first.awaddr;
+ let addr = v_ifc_M [mi].o_AW.first.awaddr;
match { .legal, .s_num } = fn_addr_to_S_num (addr);
return (legal
&& ( (num_S == 1)
|| (s_num == fromInteger (sj))));
endfunction
- function Bool fv_mi_has_wr_for_none (Integer mi);
- let addr = xactors_from_Ms [mi].o_wr_addr.first.awaddr;
- match { .legal, ._ } = fn_addr_to_S_num (addr);
- return (! legal);
- endfunction
-
function Bool fv_mi_has_rd_for_sj (Integer mi, Integer sj);
- let addr = xactors_from_Ms [mi].o_rd_addr.first.araddr;
+ let addr = v_ifc_M [mi].o_AR.first.araddr;
match { .legal, .s_num } = fn_addr_to_S_num (addr);
return (legal
&& ( (num_S == 1)
|| (s_num == fromInteger (sj))));
endfunction
+ function Bool fv_mi_has_wr_for_none (Integer mi);
+ let addr = v_ifc_M [mi].o_AW.first.awaddr;
+ match { .legal, ._ } = fn_addr_to_S_num (addr);
+ return (! legal);
+ endfunction
+
function Bool fv_mi_has_rd_for_none (Integer mi);
- let addr = xactors_from_Ms [mi].o_rd_addr.first.araddr;
+ let addr = v_ifc_M [mi].o_AR.first.araddr;
match { .legal, ._ } = fn_addr_to_S_num (addr);
return (! legal);
endfunction
// ================================================================
- // Wr requests (AW, W and B channels)
+ // BEHAVIOR: AWCHAN (write-requests)
- // Wr requests to legal Ss (AW channel)
- for (Integer mi = 0; mi < num_M; mi = mi + 1)
- for (Integer sj = 0; sj < num_S; sj = sj + 1)
+ Rules all_rules = emptyRules;
- rule rl_wr_xaction_M_to_S (fv_mi_has_wr_for_sj (mi, sj));
- // Move the AW transaction
- AXI4_Wr_Addr #(wd_id, wd_addr, wd_user) a <- pop_o (xactors_from_Ms [mi].o_wr_addr);
- xactors_to_Ss [sj].i_wr_addr.enq (a);
-
- // Enqueue a task for the W channel
- v_f_wd_tasks [mi].enq (tuple2 (fromInteger (sj), a.awlen));
-
- // Book-keeping
- v_f_wr_mis [sj].enq (fromInteger (mi));
- v_f_wr_sjs [mi].enq (fromInteger (sj));
-
- if (cfg_verbosity > 0) begin
- $display ("%0d: rl_wr_xaction_M_to_S: m%0d -> s%0d", cur_cycle, mi, sj);
- $display (" %m");
- $display (" ", fshow (a));
- end
- endrule
-
- // Wr requests to non-existent S (AW channel)
- for (Integer mi = 0; mi < num_M; mi = mi + 1)
- rule rl_wr_xaction_no_such_S (fv_mi_has_wr_for_none (mi));
- AXI4_Wr_Addr #(wd_id, wd_addr, wd_user) a <- pop_o (xactors_from_Ms [mi].o_wr_addr);
-
- // Special value 'num_S' (not a legal sj) means "no such S"
- v_f_wr_sjs [mi].enq (fromInteger (num_S));
- v_f_wr_err_info [mi].enq (tuple2 (a.awid, a.awuser));
-
- // Enqueue a task for the W channel (must consume the write-data burst)
- v_f_wd_tasks [mi].enq (tuple2 (fromInteger (num_S), a.awlen));
-
- $display ("%0d: ERROR: rl_wr_xaction_no_such_S: m%0d -> ?", cur_cycle, mi);
- $display (" %m");
- $display (" ", fshow (a));
- endrule
-
- // Wr data (W channel)
- for (Integer mi = 0; mi < num_M; mi = mi + 1)
-
- // Handle W channel burst
- // Invariant: v_rg_wd_beat_count == 0 between bursts
- // Note: awlen is encoded as 0..255 for burst lengths of 1..256
- rule rl_wr_xaction_M_to_S_data (v_f_wd_tasks [mi].first matches {.sj, .awlen});
- AXI4_Wr_Data #(wd_data, wd_user) d <- pop_o (xactors_from_Ms [mi].o_wr_data);
-
- // If sj is a legal S, send it the data beat, else drop it.
- if (sj < fromInteger (num_S))
- xactors_to_Ss [sj].i_wr_data.enq (d);
-
- if (cfg_verbosity > 0) begin
- $display ("%0d: rl_wr_xaction_M_to_S_data: m%0d -> s%0d, beat %0d/%0d",
- cur_cycle, mi, sj, v_rg_wd_beat_count [mi], awlen);
- $display (" %m");
- $display (" ", fshow (d));
- end
-
- if (v_rg_wd_beat_count [mi] == awlen) begin
- // End of burst
- v_f_wd_tasks [mi].deq;
- v_rg_wd_beat_count [mi] <= 0;
-
- // Simulation-only assertion-check (no action, just display assertion failure)
- // Final beat must have WLAST = 1
- // Rely on S (which should also see this error) to return error response
- if (! (d.wlast)) begin
- $display ("%0d: ERROR: rl_wr_xaction_M_to_S_data: m%0d -> s%0d",
- cur_cycle, mi, sj);
- $display (" WLAST not set on final data beat (awlen = %0d)", awlen);
- $display (" %m");
- $display (" ", fshow (d));
- end
- end
- else
- v_rg_wd_beat_count [mi] <= v_rg_wd_beat_count [mi] + 1;
- endrule
-
- // Wr responses from Ss to Ms (B channel)
-
- for (Integer mi = 0; mi < num_M; mi = mi + 1)
+ // AW legal addrs
+ for (Integer mi = 0; mi < num_M; mi = mi + 1) begin
for (Integer sj = 0; sj < num_S; sj = sj + 1)
-
- rule rl_wr_resp_S_to_M ( (v_f_wr_mis [sj].first == fromInteger (mi))
- && (v_f_wr_sjs [mi].first == fromInteger (sj)));
- v_f_wr_mis [sj].deq;
- v_f_wr_sjs [mi].deq;
- AXI4_Wr_Resp #(wd_id, wd_user) b <- pop_o (xactors_to_Ss [sj].o_wr_resp);
-
- xactors_from_Ms [mi].i_wr_resp.enq (b);
-
- if (cfg_verbosity > 0) begin
- $display ("%0d: rl_wr_resp_S_to_M: m%0d <- s%0d",
- cur_cycle, mi, sj);
- $display (" %m");
- $display (" ", fshow (b));
- end
- endrule
-
- // Wr error responses to Ms (B channel)
- // v_f_wr_sjs [mi].first has value num_S (illegal value)
- // v_f_wr_err_info [mi].first contains request fields 'awid' and 'awuser'
-
- for (Integer mi = 0; mi < num_M; mi = mi + 1)
-
- rule rl_wr_resp_err_to_M (v_f_wr_sjs [mi].first == fromInteger (num_S));
- v_f_wr_sjs [mi].deq;
- v_f_wr_err_info [mi].deq;
-
- match { .awid, .awuser } = v_f_wr_err_info [mi].first;
-
- let b = AXI4_Wr_Resp {bid: awid,
- bresp: axi4_resp_decerr,
- buser: awuser};
-
- xactors_from_Ms [mi].i_wr_resp.enq (b);
-
- if (cfg_verbosity > 0) begin
- $display ("%0d: rl_wr_resp_err_to_M: m%0d <- err", cur_cycle, mi);
- $display (" %m");
- $display (" ", fshow (b));
- end
- endrule
+ all_rules =
+ rJoinDescendingUrgency (
+ all_rules,
+ rules
+ rule rl_AW (fv_mi_has_wr_for_sj (mi, sj));
+ // Forward the AW transaction
+ let aw_in <- pop_o (v_ifc_M [mi].o_AW);
+ let awid_S = { aw_in.awid, fromInteger (mi) };
+ let aw_out = fn_change_AW_id (aw_in, awid_S);
+ v_ifc_S [sj].i_AW.enq (aw_out);
+
+ // Enqueue mi->sj control info for W channel
+ v_f_W_Sj [mi].enq (tuple2 (True, fromInteger (sj)));
+ v_f_W_Mi [sj].enq (fromInteger (mi));
+
+ if (verbosity > 0) begin
+ $display ("AXI4_Fabric: AW m%0d -> s%0d", mi, sj);
+ $display (" ", fshow (aw_in));
+ end
+ endrule
+ endrules);
+
+ // AW wild addrs (awaddr does not map to any Sj)
+ all_rules =
+ rJoinDescendingUrgency (
+ all_rules,
+ rules
+ rule rl_AW_wild (fv_mi_has_wr_for_none (mi));
+ let aw_in <- pop_o (v_ifc_M [mi].o_AW);
+
+ // Enqueue mi->sj control info for W channel
+ v_f_W_Sj [mi].enq (tuple2 (False, ?));
+ f_W_wild.enq (tuple3 (fromInteger (mi), aw_in.awid, aw_in.awuser));
+
+ if (verbosity > 0) begin
+ $display ("ERROR: AXI4_Fabric: AW m%0d -> wild", mi);
+ $display (" ", fshow (aw_in));
+ end
+ endrule
+ endrules);
+ end
// ================================================================
- // Rd requests (AR and R channels)
+ // BEHAVIOR: WCHAN (write-data)
- // Rd requests to legal Ss (AR channel)
- for (Integer mi = 0; mi < num_M; mi = mi + 1)
+ // W normal
+ for (Integer mi = 0; mi < num_M; mi = mi + 1) begin
for (Integer sj = 0; sj < num_S; sj = sj + 1)
+ all_rules =
+ rJoinDescendingUrgency (
+ all_rules,
+ rules
+
+ // W channel (with bursts)
+ // Invariant: v_rg_wd_beat_count == 0 between bursts
+ // Note: awlen encodes burst lengths of 1..256 as 0..255
+ rule rl_W ((v_f_W_Mi [sj].first == fromInteger (mi))
+ && tpl_1 (v_f_W_Sj [mi].first)
+ && (tpl_2 (v_f_W_Sj [mi].first) == fromInteger (sj)));
+
+ // Forward the W
+ let w <- pop_o (v_ifc_M [mi].o_W);
+ v_ifc_S [sj].i_W.enq (w);
+
+ if (verbosity > 0) begin
+ $display ("AXI4_Fabric: W m%0d -> s%0d", mi, sj);
+ $display (" ", fshow (w));
+ end
+
+ if (w.wlast) begin
+ // End of burst; dequeue the control info
+ v_f_W_Mi [sj].deq;
+ v_f_W_Sj [mi].deq;
+ end
+ endrule
+ endrules);
+
+ // W for wild addrs
+ all_rules =
+ rJoinDescendingUrgency (
+ all_rules,
+ rules
+ rule rl_W_wild (tpl_1 (f_W_wild.first) == fromInteger (mi)
+ && (! tpl_1 (v_f_W_Sj [mi].first)));
+
+ match { .mi, .bid, .buser } = f_W_wild.first;
+
+ // Consume the W and drop it
+ let w <- pop_o (v_ifc_M [mi].o_W);
+
+ if (verbosity > 0) begin
+ $display ("AXI4_Fabric: W m%0d -> WILD", mi);
+ $display (" ", fshow (w));
+ end
- rule rl_rd_xaction_M_to_S (fv_mi_has_rd_for_sj (mi, sj));
- AXI4_Rd_Addr #(wd_id, wd_addr, wd_user) a <- pop_o (xactors_from_Ms [mi].o_rd_addr);
-
- xactors_to_Ss [sj].i_rd_addr.enq (a);
-
- v_f_rd_mis [sj].enq (tuple2 (fromInteger (mi), a.arlen));
- v_f_rd_sjs [mi].enq (fromInteger (sj));
-
- if (cfg_verbosity > 0) begin
- $display ("%0d: rl_rd_xaction_M_to_S: m%0d -> s%0d",
- cur_cycle, mi, sj);
- $display (" %m");
- $display (" ", fshow (a));
- end
- endrule
-
- // Rd requests to non-existent S (AR channel)
- for (Integer mi = 0; mi < num_M; mi = mi + 1)
- rule rl_rd_xaction_no_such_S (fv_mi_has_rd_for_none (mi));
- AXI4_Rd_Addr #(wd_id, wd_addr, wd_user) a <- pop_o (xactors_from_Ms [mi].o_rd_addr);
+ if (w.wlast) begin
+ // End of burst; dequeue the control info
+ f_W_wild.deq;
+ v_f_W_Sj [mi].deq;
- v_f_rd_sjs [mi].enq (fromInteger (num_S));
- v_f_rd_err_info [mi].enq (tuple3 (a.arlen, a.arid, a.aruser));
+ // Send error response to Mi
+ let b = AXI4_B {bid: bid,
+ bresp: axi4_resp_decerr,
+ buser: buser};
+ v_ifc_M [mi].i_B.enq (b);
+ end
+ endrule
+ endrules);
+ end
- $display ("%0d: ERROR: rl_rd_xaction_no_such_S: m%0d -> ?", cur_cycle, mi);
- $display (" %m");
- $display (" ", fshow (a));
- endrule
+ // ================================================================
+ // BEHAVIOR: BCHAN (write-responses)
+
+ // Wr responses from Ss to Ms
+ for (Integer sj = 0; sj < num_S; sj = sj + 1)
+ all_rules =
+ rJoinDescendingUrgency (
+ all_rules,
+ rules
+ rule rl_B;
+ // Incoming BCHAN response
+ AXI4_B #(wd_id_S, wd_user) b_in <- pop_o (v_ifc_S [sj].o_B);
+ // Extract mi and bid_M from incoming bid_S
+ Bit #(wd_id_S) bid_S = b_in.bid;
+ Bit #(log_nm) mi = truncate (bid_S);
+ Bit #(wd_id_M) bid_M = truncateLSB (bid_S);
+ // Replace bid_S with bid_M in BCHAN response, send to mi
+ AXI4_B #(wd_id_M, wd_user) b_out = fn_change_B_id (b_in, bid_M);
+ v_ifc_M [mi].i_B.enq (b_out);
+
+ if (verbosity > 0) begin
+ $display ("AXI4_Fabric: B m%0d <- s%0d", mi, sj);
+ $display (" ", fshow (b_out));
+ end
+ endrule
+ endrules);
- // Rd responses from Ss to Ms (R channel)
+ // ================================================================
+ // ARCHAN (read requests)
- for (Integer mi = 0; mi < num_M; mi = mi + 1)
+ // Legal addrs
+ for (Integer mi = 0; mi < num_M; mi = mi + 1) begin
for (Integer sj = 0; sj < num_S; sj = sj + 1)
-
- rule rl_rd_resp_S_to_M (v_f_rd_mis [sj].first matches { .mi2, .arlen }
- &&& (mi2 == fromInteger (mi))
- &&& (v_f_rd_sjs [mi].first == fromInteger (sj)));
-
- AXI4_Rd_Data #(wd_id, wd_data, wd_user) r <- pop_o (xactors_to_Ss [sj].o_rd_data);
-
- if (v_rg_r_beat_count [sj] == arlen) begin
- // Final beat of burst
- v_f_rd_mis [sj].deq;
- v_f_rd_sjs [mi].deq;
- v_rg_r_beat_count [sj] <= 0;
-
- // Assertion-check
- // Final beat must have RLAST = 1
- // If not, and if RRESP is OK, set RRESP to AXI4_RESP_SLVERR
- if ((r.rresp == axi4_resp_okay) && (! (r.rlast))) begin
- r.rresp = axi4_resp_slverr;
- $display ("%0d: ERROR: rl_rd_resp_S_to_M: m%0d <- s%0d",
- cur_cycle, mi, sj);
- $display (" RLAST not set on final data beat (arlen = %0d)", arlen);
- $display (" %m");
- $display (" ", fshow (r));
+ all_rules =
+ rJoinDescendingUrgency (
+ all_rules,
+ rules
+ rule rl_AR (fv_mi_has_rd_for_sj (mi, sj));
+ let ar_in <- pop_o (v_ifc_M [mi].o_AR);
+ let arid_S = { ar_in.arid, fromInteger (mi) };
+ let ar_out = fn_change_AR_id (ar_in, arid_S);
+ v_ifc_S [sj].i_AR.enq (ar_out);
+
+ if (verbosity > 0) begin
+ $display ("AXI4_Fabric: AR m%0d -> s%0d", mi, sj);
+ $display (" ", fshow (ar_in));
+ end
+ endrule
+ endrules);
+
+ all_rules =
+ rJoinDescendingUrgency (
+ all_rules,
+ rules
+ // Wild addr (araddr does not map to any Sj)
+ rule rl_AR_wild (fv_mi_has_rd_for_none (mi));
+ let ar <- pop_o (v_ifc_M [mi].o_AR);
+ let r = AXI4_R {rid: ar.arid,
+ rdata: ?,
+ rresp: axi4_resp_decerr,
+ rlast: True,
+ ruser: ar.aruser};
+ v_ifc_M [mi].i_R.enq (r);
+
+ if (verbosity > 0) begin
+ $display ("ERROR: AR m%0d -> WILD", mi);
+ $display (" ", fshow (ar));
end
- end
- else
- v_rg_r_beat_count [sj] <= v_rg_r_beat_count [sj] + 1;
-
- xactors_from_Ms [mi].i_rd_data.enq (r);
-
- if (cfg_verbosity > 0) begin
- $display ("%0d: rl_rd_resp_S_to_M: m%0d <- s%0d",
- cur_cycle, mi, sj);
- $display (" %m");
- $display (" r: ", fshow (r));
- end
- endrule
-
- // Rd error responses to Ms (R channel)
- // v_f_rd_sjs [mi].first has value num_S (illegal value)
- // v_f_rd_err_info [mi].first contains request fields: 'arlen', 'arid', 'aruser'
-
- for (Integer mi = 0; mi < num_M; mi = mi + 1)
-
- rule rl_rd_resp_err_to_M (v_f_rd_sjs [mi].first == fromInteger (num_S));
- match { .arlen, .arid, .aruser } = v_f_rd_err_info [mi].first;
-
- Bit #(wd_data) data = 0;
- let r = AXI4_Rd_Data {rid: arid,
- rdata: data,
- rresp: axi4_resp_decerr,
- rlast: (v_rg_r_err_beat_count [mi] == arlen),
- ruser: aruser};
-
- xactors_from_Ms [mi].i_rd_data.enq (r);
-
- if (v_rg_r_err_beat_count [mi] == arlen) begin
- // Last beat of burst
- v_f_rd_sjs [mi].deq;
- v_f_rd_err_info [mi].deq;
- v_rg_r_err_beat_count [mi] <= 0;
- end
- else
- v_rg_r_err_beat_count [mi] <= v_rg_r_err_beat_count [mi] + 1;
-
- if (cfg_verbosity > 0) begin
- $display ("%0d: rl_rd_resp_err_to_M: m%0d <- err",
- cur_cycle, mi);
- $display (" %m");
- $display (" r: ", fshow (r));
- end
- endrule
+ endrule
+ endrules);
+ end
// ================================================================
- // INTERFACE
-
- function AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user) f1 (Integer j)
- = xactors_from_Ms [j].axi_side;
- function AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user) f2 (Integer j)
- = xactors_to_Ss [j].axi_side;
+ // RCHAN (read responses)
+
+ for (Integer sj = 0; sj < num_S; sj = sj + 1)
+ all_rules =
+ rJoinDescendingUrgency (
+ all_rules,
+ rules
+ rule rl_R;
+ AXI4_R #(wd_id_S, wd_data, wd_user)
+ r_in = v_ifc_S [sj].o_R.first;
+
+ // Check if we already own Mi or if Mi is free (no owner)
+ Bit #(log_nm) mi = truncate (r_in.rid);
+ Bool we_own = False;
+ if (v_rg_M_RCHAN_owners [mi] matches tagged Invalid)
+ we_own = True;
+ else if (v_rg_M_RCHAN_owners [mi] matches tagged Valid .sj2
+ &&& (sj2 == fromInteger (sj)))
+ we_own = True;
+
+ if (we_own) begin
+ // Forward the R response
+ v_ifc_S [sj].o_R.deq;
+ Bit #(wd_id_S) rid_S = r_in.rid;
+ Bit #(wd_id_M) rid_M = truncateLSB (rid_S);
+ let r_M = fn_change_R_id (r_in, rid_M);
+ v_ifc_M [mi].i_R.enq (r_M);
+
+ // Release ownership of Mi RCHAN on last beat
+ if (r_in.rlast)
+ v_rg_M_RCHAN_owners [mi] <= tagged Invalid;
+ else
+ // Record ownership for rest of beats
+ v_rg_M_RCHAN_owners [mi] <= tagged Valid (fromInteger (sj));
+
+ if (verbosity > 0) begin
+ $display ("AXI4_Fabric: R m%0d <- s%0d", mi, sj);
+ $display (" ", fshow (r_M));
+ end
+ end
+ endrule
+ endrules);
- method Action reset () if (! rg_reset);
- rg_reset <= True;
- endmethod
+ addRules (all_rules);
- method Action set_verbosity (Bit #(4) verbosity);
- cfg_verbosity <= verbosity;
- endmethod
+ // ****************************************************************
+ // INTERFACE
- interface v_from_Ms = genWith (f1);
- interface v_to_Ss = genWith (f2);
+ // Empty
endmodule
-// ================================================================
+// ****************************************************************
endpackage: AXI4_Fabric
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_Gate.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_Gate.bsv
index 27b38c9..dc199a0 100644
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_Gate.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4/AXI4_Gate.bsv
@@ -1,23 +1,25 @@
-// Copyright (c) 2021-2023 Bluespec, Inc. All Rights Reserved
+// Copyright (c) 2021-2024 Bluespec, Inc. All Rights Reserved
// Author: Rishiyur S. Nikhil
-//
+
// SPDX-License-Identifier: BSD-3-Clause
package AXI4_Gate;
// ================================================================
-// This package defines an AXI4-M-to-AXI4-S 'gate' module,
-// that either allows or blocks the 5 AXI4 buses,
-// depending on a Bool 'enable' input.
+// This package defines a 'gate' module connecting an ifc_M to an ifc_S.
+// When driving method 'm_enable(True)' it passes AXI4 traffic through.
+// When driving method 'm_enable(False)' it blocks AXI4 traffic.
+
+// Can be used to control authorized access to an AXI4 connection.
// ================================================================
// Bluespec library imports
-import Vector :: *;
-import FIFOF :: *;
+import Vector :: *;
+import FIFOF :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Cur_Cycle :: *;
import GetPut_Aux :: *;
@@ -29,17 +31,16 @@ import Semi_FIFOF :: *;
import AXI4_Types :: *;
// ================================================================
-// The interface for the gate module
-interface AXI4_Gate_IFC #(numeric type wd_id_t,
- numeric type wd_addr_t,
- numeric type wd_data_t,
- numeric type wd_user_t);
- // From M
- interface AXI4_S_IFC #(wd_id_t, wd_addr_t, wd_data_t, wd_user_t) axi4_S;
- // To S
- interface AXI4_M_IFC #(wd_id_t, wd_addr_t, wd_data_t, wd_user_t) axi4_M;
+Integer verbosity = 0;
+
+// ================================================================
+// The interface for the gate module
+interface AXI4_Gate_IFC #(numeric type wd_id,
+ numeric type wd_addr,
+ numeric type wd_data,
+ numeric type wd_user);
// Enable control signal. Continuously driven with Bool arg.
(* always_ready, always_enabled *)
method Action m_enable (Bool enabled);
@@ -47,139 +48,123 @@ endinterface
// ================================================================
// The Gate module
+// The Bool parameter: False: just block traffic; True: gen AXI4 err response
-Integer verbosity = 0;
-
-module mkAXI4_Gate
- #(Bool respond_with_err) // False: block traffic; True: respond with err
- (AXI4_Gate_IFC #(wd_id_t, wd_addr_t, wd_data_t, wd_user_t));
-
- // ----------------
- // Transactor facing M
- AXI4_S_Xactor_IFC #(wd_id_t, wd_addr_t, wd_data_t, wd_user_t)
- xactor_from_M <- mkAXI4_S_Xactor;
-
- // Transactor facing S
- AXI4_M_Xactor_IFC #(wd_id_t, wd_addr_t, wd_data_t, wd_user_t)
- xactor_to_S <- mkAXI4_M_Xactor;
+module mkAXI4_Gated_Buffer #(Bool respond_with_err,
+ AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user) ifc_M,
+ AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user) ifc_S)
+ (AXI4_Gate_IFC #(wd_id, wd_addr, wd_data, wd_user));
Reg #(Bool) rg_enabled <- mkReg (False);
Reg #(Bool) rg_enabled_prev <- mkReg (False);
- // ----------------------------------------------------------------
+ // ================================================================
// BEHAVIOR
// ----------------
// When gate is enabled: pass-through everything M-to-S and S-to-M
- rule rl_wr_addr (rg_enabled);
- let wra <- pop_o (xactor_from_M.o_wr_addr);
- xactor_to_S.i_wr_addr.enq (wra);
+ rule rl_AW (rg_enabled);
+ let wra <- pop_o (ifc_M.o_AW);
+ ifc_S.i_AW.enq (wra);
endrule
- rule rl_wr_data (rg_enabled);
- let wrd <- pop_o (xactor_from_M.o_wr_data);
- xactor_to_S.i_wr_data.enq (wrd);
+ rule rl_W (rg_enabled);
+ let wrd <- pop_o (ifc_M.o_W);
+ ifc_S.i_W.enq (wrd);
endrule
- rule rl_wr_resp (rg_enabled);
- let wrr <- pop_o (xactor_to_S.o_wr_resp);
- xactor_from_M.i_wr_resp.enq (wrr);
+ rule rl_B (rg_enabled);
+ let wrr <- pop_o (ifc_S.o_B);
+ ifc_M.i_B.enq (wrr);
endrule
- rule rl_rd_addr (rg_enabled);
- let rda <- pop_o (xactor_from_M.o_rd_addr);
- xactor_to_S.i_rd_addr.enq (rda);
+ rule rl_AR (rg_enabled);
+ let rda <- pop_o (ifc_M.o_AR);
+ ifc_S.i_AR.enq (rda);
endrule
- rule rl_rd_data (rg_enabled);
- let rdd <- pop_o (xactor_to_S.o_rd_data);
- xactor_from_M.i_rd_data.enq (rdd);
+ rule rl_R (rg_enabled);
+ let rdd <- pop_o (ifc_S.o_R);
+ ifc_M.i_R.enq (rdd);
endrule
// ----------------
// When gate is disabled: return error responses to M;
// don't send anything to S or expect anything from S.
- rule rl_wr_addr_disabled (respond_with_err && (! rg_enabled));
- let wra <- pop_o (xactor_from_M.o_wr_addr);
- let wrr = AXI4_Wr_Resp {bid: wra.awid,
- bresp: axi4_resp_slverr,
- buser: wra.awuser};
- xactor_from_M.i_wr_resp.enq (wrr);
-
- $display ("WARNING: rl_wr_addr_disabled: rec'd wr request from M when gate disabled.");
- $display (" ", fshow (wra));
- $display (" Returning error response.");
- $display (" %0d: %m", cur_cycle);
+ rule rl_AW_disabled (respond_with_err && (! rg_enabled));
+ let aw <- pop_o (ifc_M.o_AW);
+ let b = AXI4_B {bid: aw.awid,
+ bresp: axi4_resp_slverr,
+ buser: aw.awuser};
+ ifc_M.i_B.enq (b);
+
+ $display ("WARNING: rl_AW_disabled: rec'd wr request from M when gate disabled.");
+ $display (" ", fshow (aw));
+ $display (" %0d: Returning error response.", cur_cycle);
endrule
- rule rl_wr_data_disabled (respond_with_err && (! rg_enabled));
- let wrd <- pop_o (xactor_from_M.o_wr_data);
+ rule rl_W_disabled (respond_with_err && (! rg_enabled));
+ let w <- pop_o (ifc_M.o_W);
// Discard the data
endrule
- rule rl_wr_resp_disabled_drain_S (respond_with_err && (! rg_enabled));
- let wrr <- pop_o (xactor_to_S.o_wr_resp);
- $display ("WARNING: rl_wr_resp_disabled: rec'd wr resp from S when gate disabled; ignoring");
- $display (" (there couldn't have been a request)");
- $display (" %0d: %m", cur_cycle);
+ rule rl_B_disabled_drain_S (respond_with_err && (! rg_enabled));
+ let b <- pop_o (ifc_S.o_B);
+ $display ("WARNING: rl_B_disabled: rec'd wr resp from S when gate disabled; ignoring");
+ $display (" %0d: (there couldn't have been a request)", cur_cycle);
endrule
Reg #(Bit #(9)) rg_rd_burst_len <- mkRegU;
- rule rl_rd_addr_disabled (respond_with_err && (! rg_enabled));
- let rda = xactor_from_M.o_rd_addr.first;
+ rule rl_AR_disabled (respond_with_err && (! rg_enabled));
+ let ar = ifc_M.o_AR.first;
// Pop this request only after sending burst responses
// Note: AXI4 decodes burst len = arlen + 1
- rg_rd_burst_len <= zeroExtend (rda.arlen) + 1;
+ rg_rd_burst_len <= zeroExtend (ar.arlen) + 1;
$display ("WARNING: rl_rd_addr_disabled: rec'd rd request from M when gate disabled.");
- $display (" ", fshow (rda));
- $display (" Returning error response.");
- $display (" %0d: %m", cur_cycle);
+ $display (" ", fshow (ar));
+ $display (" %0d: Returning error response.", cur_cycle);
endrule
// Send burst of responses
- rule rl_rd_data_disabled_burst_resps (respond_with_err
- && (! rg_enabled)
- && (rg_rd_burst_len != 0));
- let rda = xactor_from_M.o_rd_addr.first;
- Bit #(wd_data_t) rdata = ?;
- let rdd = AXI4_Rd_Data {rid: rda.arid,
- rresp: axi4_resp_slverr,
- rdata: rdata,
- rlast: (rg_rd_burst_len == 1),
- ruser: rda.aruser};
- xactor_from_M.i_rd_data.enq (rdd);
-
- if (rdd.rlast)
+ rule rl_R_disabled_burst_resps (respond_with_err
+ && (! rg_enabled)
+ && (rg_rd_burst_len != 0));
+ let ar = ifc_M.o_AR.first;
+ Bit #(wd_data) rdata = ?;
+ let r = AXI4_R {rid: ar.arid,
+ rresp: axi4_resp_slverr,
+ rdata: rdata,
+ rlast: (rg_rd_burst_len == 1),
+ ruser: ar.aruser};
+ ifc_M.i_R.enq (r);
+
+ if (r.rlast)
// Consume the request
- xactor_from_M.o_rd_addr.deq;
+ ifc_M.o_AR.deq;
else
rg_rd_burst_len <= rg_rd_burst_len - 1;
endrule
- rule rl_rd_data_disabled_drain_S (respond_with_err && (! rg_enabled));
- let rdd <- pop_o (xactor_to_S.o_rd_data);
- $display ("WARNING: rl_rd_data_disabled: rec'd rd resp from S when gate disabled; ignoring");
- $display (" (there couldn't have been a request)");
- $display (" %0d: %m", cur_cycle);
+ rule rl_R_disabled_drain_S (respond_with_err && (! rg_enabled));
+ let r <- pop_o (ifc_S.o_R);
+ $display ("WARNING: rl_R_disabled: rec'd rd resp from S when gate disabled; ignoring");
+ $display (" %0d: (there couldn't have been a request)", cur_cycle);
endrule
- // ----------------------------------------------------------------
+ // ================================================================
// INTERFACE
- interface axi4_S = xactor_from_M.axi_side;
- interface axi4_M = xactor_to_S .axi_side;
-
method Action m_enable (Bool enabled);
if (enabled && (! rg_enabled) && (verbosity != 0))
- $display ("%0d: %m: AXI4 ENABLING", cur_cycle);
+ $display ("%0d: AXI4 ENABLING", cur_cycle);
else if ((! enabled) && rg_enabled && (verbosity != 0))
- $display ("%0d: %m: AXI4 DISABLING", cur_cycle);
+ $display ("%0d: AXI4 DISABLING", cur_cycle);
rg_enabled <= enabled;
endmethod
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_Mem_Model.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_Mem_Model.bsv
index 43c0914..6630d35 100644
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_Mem_Model.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4/AXI4_Mem_Model.bsv
@@ -1,13 +1,13 @@
-// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved.
+// Copyright (c) 2019-2024 Bluespec, Inc. All Rights Reserved.
// Author: Rishiyur S. Nikhil
-//
+
// SPDX-License-Identifier: BSD-3-Clause
package AXI4_Mem_Model;
-// ================================================================
+// ****************************************************************
// A memory-model to be used as an S on an AXI4 bus.
-// Only partical functionality; will be gradually improved over time.
+// Only partial functionality; to be gradually improved over time.
// Current status:
// Address and Data bus widths: 64b
// Bursts: 'fixed' and 'incr' only
@@ -15,10 +15,9 @@ package AXI4_Mem_Model;
// Strobes: Not yet handled
// memory size: See 'mem_size_word64' definition below
-// ================================================================
+// ****************************************************************
// Exports
-export AXI4_Mem_Model_IFC (..);
export mkAXI4_Mem_Model;
// ================================================================
@@ -30,184 +29,296 @@ import GetPut :: *;
import ClientServer :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
-import Cur_Cycle :: *;
import GetPut_Aux :: *;
import Semi_FIFOF :: *;
// ================================================================
// Project imports
-import AXI4_Types :: *;
-
-// ================================================================
-// INTERFACE
+import AXI4_Types :: *;
-interface AXI4_Mem_Model_IFC #(numeric type wd_id,
- numeric type wd_addr,
- numeric type wd_data,
- numeric type wd_user);
+// ****************************************************************
+// Simulation verbosity during simulation on stdout for this package (edit as desired)
+// 0: quiet
+// 1: show transactions, brief
+// 2: show transactions, full AXI4 structs
- method Action init (Bit #(wd_addr) addr_map_base, Bit #(wd_addr) addr_map_lim);
+Integer verbosity = 0;
- interface AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user) s_ifc;
+// ****************************************************************
-endinterface
+typedef enum { STATE_INIT_0, STATE_INIT_1, STATE_RUNNING } State
+deriving (Bits, Eq, FShow);
-// ================================================================
+// ****************************************************************
// IMPLEMENTATION
-Integer mem_size_word64 = 'h100_0000; // 16M x 64b words = 128MiB
-
-function Bool fn_addr_ok (Bit #(64) base, Bit #(64) lim, Bit #(64) addr, AXI4_Size size);
- let aligned = fn_addr_is_aligned (addr, size);
- let in_range = ((base <= addr) && (addr < lim));
- return (aligned && in_range);
-endfunction
-
-// ----------------
-
-module mkAXI4_Mem_Model (AXI4_Mem_Model_IFC #(wd_id, wd_addr, wd_data, wd_user))
- provisos (NumAlias #(wd_addr, 64),
- NumAlias #(wd_data, 64));
+// "Memory words" (MW) are same bitwidth as AXI4 data bus (wd_data)
+
+module mkAXI4_Mem_Model #(Integer id, // Use unique ids for each instance
+ Bit #(wd_addr) addr_base, // byte addr
+ Bit #(wd_addr) addr_lim, // byte addr
+ Bool init_zero,
+ Bool init_with_memhex,
+ String memhex_filename,
+ AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user) ifc_M)
+ (Empty)
+ provisos (Div #(wd_data, 8, wd_data_B), // see comments on provisos below
+ Log #(wd_data_B, wd_ix_B_in_MW),
+ Add #(wd_addrMW, wd_ix_B_in_MW, wd_addr),
+ Add #(_, 8, wd_addrMW),
+ Mul #(wd_data_B, 8, wd_data));
- // 0 = quiet; 1 = show mem transactions
- Integer verbosity = 1;
+ // ================================================================
+ // Derived constants (some are computed in provisos above)
+
+ // See provisos above for computation of these numeric types:
+ // wd_data_B: data width in bytes
+ // wd_ix_B_in_MW: bitwidth of index of a byte in a memword
+ // wd_addrMW: bitwidth of address of a memword
+
+ // Integer values thereof
+ Integer i_wd_data_B = valueOf (wd_data_B);
+ Integer i_wd_ix_B_in_MW = valueOf (wd_ix_B_in_MW);
+
+ // memword addr of first memword
+ Bit #(wd_addrMW) addrMW_base = truncate (addr_base >> i_wd_ix_B_in_MW);
+
+ // Byte address of byte 0 in first memword
+ Bit #(wd_addr) addr_base_0 = zeroExtend (addrMW_base) << i_wd_ix_B_in_MW;
+
+ // Number of mem words
+ Bit #(wd_addrMW) num_MW = truncate ((addr_lim - addr_base_0 - 1 + fromInteger (i_wd_data_B))
+ >> i_wd_ix_B_in_MW);
+ // memword addr just beyond the last memword
+ Bit #(wd_addrMW) addrMW_lim = addrMW_base + num_MW;
+
+ // Memory is modeled as a RegFile where each word is full AXI4 data width (wd_data)
+ // and indexed by memword addrs
+ RegFile #(Bit #(wd_addrMW), Bit #(wd_data))
+ regfile <- (init_with_memhex
+ ? mkRegFileLoad (memhex_filename, addrMW_base, addrMW_lim - 1)
+ : mkRegFile ( addrMW_base, addrMW_lim - 1));
+
+ Reg #(State) rg_state <- mkReg (STATE_INIT_0);
+
+ // ----------------
+ // Check well-formedness of an AXI4 request
+
+ function ActionValue #(Bool) fav_is_well_formed (Bit #(wd_addr) addr,
+ Bit #(wd_addrMW) addrMW,
+ AXI4_Len axlen,
+ AXI4_Size axsize,
+ AXI4_Burst axburst);
+ actionvalue
+ // Check axsize legal for data bus width
+ Bool ok = True;
+ Bit #(11) size_b = { fv_AXI4_Size_to_num_bytes (axsize), 3'h0 };
+ if (size_b > fromInteger (valueOf (wd_data))) begin
+ $display ("AXI4_Mem_Model[%0d]: ERROR: axsize > wd_data", id);
+ $display (" axsize: %0h (= %d bits)", axsize, size_b);
+ $display (" wd_data: %0d", valueOf (wd_data));
+ ok = False;
+ end
+
+ // Check address is not below addr_base
+ if (addr < addr_base) begin
+ $display ("AXI4_Mem_Model[%0d]: ERROR: addr < addr_base", id);
+ $display (" addr: 0x%0h", addr);
+ $display (" addr_base: 0x%0h", addr_base);
+ ok = False;
+ end
+
+ // Check address is not beyond last memory word
+ if (addrMW >= addrMW_lim) begin
+ $display ("AXI4_Mem_Model[%0d]: ERROR: access beyond mem limit", id);
+ $display (" addr_lim: 0x%0h", addr_lim);
+ ok = False;
+ end
+
+ // Check that burst mode is supported
+ if (axburst == axburst_wrap) begin
+ $display ("AXI4_Mem_Model[%0d]: ERROR: axburst = wrap; not supported yet.", id);
+ ok = False;
+ end
+ return ok;
+ endactionvalue
+ endfunction
+
+ // ****************************************************************
+ // BEHAVIOR
+
+ rule rl_init (rg_state == STATE_INIT_0);
+ $display ("================================");
+ $display ("AXI4_Mem_Model[%0d]: initialization", id);
+
+ if (addr_base >= addr_lim) begin
+ $display (" ERROR: init: addr_base >= addr_lim", id);
+ $display (" addr_base 0x%0h", addr_base);
+ $display (" addr_lim 0x%0h", addr_lim);
+ $finish (1);
+ end
- Reg #(Bool) rg_initialized <- mkReg (False);
+ // Check legal wd_data (8, 16, 32, 64, 128, 256, 512, or 1024 bits)
+ // i.e., exactly one bit should be set in wd[10:3]
+ Bit #(11) wd = fromInteger (valueOf (wd_data)); // checks wd_data <= 11'h7FF
+ if ((countOnes (wd) != 1) || ((wd & 'b111) != 0)) begin
+ $display (" ERROR: wd_addr should be 8,16,32,...,1024", id);
+ $display (" addr_base 0x%0h", addr_base);
+ $display (" addr_lim 0x%0h", addr_lim);
+ $finish (1);
+ end
- Reg #(Bit #(wd_addr)) rg_addr_map_base <- mkRegU;
- Reg #(Bit #(wd_addr)) rg_addr_map_lim <- mkRegU;
+ $display (" addr_base: 0x%0h addr_lim: 0x%0h (byte addrs)",
+ addr_base, addr_lim);
+ $display (" addrMW_base:0x%0h addrMW_lim:0x%0h (word addrs)",
+ addrMW_base, addrMW_lim);
+ $display (" AXI4 params: wd_id:%0d wd_addr:%0d wd_data:%0d wd_user:%0d",
+ valueOf (wd_id), valueOf (wd_addr),
+ valueOf (wd_data), valueOf (wd_user));
+ $display (" Memory contains %0d words, each wd_data bits (%0d bytes) wide",
+ num_MW, i_wd_data_B);
+
+ if (init_zero) begin
+ $display (" Zeroing memory");
+ rg_state <= STATE_INIT_1;
+ end
+ else begin
+ if (init_with_memhex)
+ $display (" Loading from memhex file %s: ", memhex_filename);
+ else
+ $display (" Memory contents not initialized");
+ rg_state <= STATE_RUNNING;
+ end
+ $display ("================================");
+ endrule
- AXI4_S_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user) xactor <- mkAXI4_S_Xactor;
+ // Iterate through memory, writing zeroes
+ Reg #(Bit #(wd_addrMW)) rg_addrMW <- mkReg (addrMW_base);
- RegFile #(Bit #(wd_addr), Bit #(wd_data)) rf <- mkRegFile (0, fromInteger (mem_size_word64));
+ rule rl_init_mem (rg_state == STATE_INIT_1);
+ regfile.upd (rg_addrMW, 0);
+ if (rg_addrMW != (addrMW_lim - 1))
+ rg_addrMW <= rg_addrMW + 1;
+ else begin
+ $display ("AXI4_Mem_Model[%0d]: zero'd memory", id);
+ rg_state <= STATE_RUNNING;
+ end
+ endrule
// ================================================================
// Read requests
- // TODO: does a bad addr return 'burst-len' err responses or just 1?
+ // TODO: on a bad addr (or other error), does AXI4 specs say to return 'burst-len'
+ // err responses or just one?
- Reg #(Bit #(8)) rg_rd_beat <- mkReg (0);
+ Reg #(Bit #(8)) rg_R_beat <- mkReg (0);
// Recv request on RD_ADDR bus
// Send burst responses on RD_DATA bus
- rule rl_read (rg_initialized);
- let rd_addr = xactor.o_rd_addr.first;
- let rf_index = ((rd_addr.araddr - rg_addr_map_base) >> 3);
- if (rd_addr.arburst == axburst_incr)
- rf_index = rf_index + zeroExtend (rg_rd_beat);
- let last = (rg_rd_beat == rd_addr.arlen);
+ rule rl_AR (rg_state == STATE_RUNNING);
+ let ar = ifc_M.o_AR.first;
+
+ Bit #(wd_addrMW) addrMW = truncateLSB (ar.araddr);
+ if (ar.arburst == axburst_incr)
+ addrMW = addrMW + zeroExtend (rg_R_beat);
+
+ Bool ok <- fav_is_well_formed (ar.araddr, addrMW, ar.arlen, ar.arsize, ar.arburst);
+
+ if (! ok) begin
+ $display ("AXI4_Mem_Model[%0d]: ERROR: AR is not well-formed", id);
+ $display (" ", fshow_AR (ar));
+ end
- let addr_ok = fn_addr_ok (rg_addr_map_base, rg_addr_map_lim, rd_addr.araddr, rd_addr.arsize);
+ let last = (rg_R_beat == ar.arlen);
- let data = (addr_ok ? rf.sub (rf_index) : 0);
+ let data = (ok ? regfile.sub (addrMW) : 0);
- AXI4_Rd_Data #(wd_id, wd_data, wd_user)
- rd_data = AXI4_Rd_Data {rid: rd_addr.arid,
- rdata: data,
- rresp: (addr_ok ? axi4_resp_okay : axi4_resp_slverr),
- rlast: last,
- ruser: rd_addr.aruser};
- xactor.i_rd_data.enq (rd_data);
+ AXI4_R #(wd_id, wd_data, wd_user)
+ r = AXI4_R {rid: ar.arid,
+ rdata: data,
+ rresp: (ok ? axi4_resp_okay : axi4_resp_slverr),
+ rlast: last,
+ ruser: ar.aruser};
+ ifc_M.i_R.enq (r);
if (last) begin
- xactor.o_rd_addr.deq;
- rg_rd_beat <= 0;
+ ifc_M.o_AR.deq;
+ rg_R_beat <= 0;
end
else
- rg_rd_beat <= rg_rd_beat + 1;
+ rg_R_beat <= rg_R_beat + 1;
if (verbosity != 0) begin
- $write ("%0d: %m.rl_read: ", cur_cycle);
- $write (fshow_Rd_Addr (rd_addr));
- $write (fshow_Rd_Data (rd_data));
- if (addr_ok)
- $display (" beat %0d rf_index 0x%0h", rg_rd_beat, rf_index);
- else
- $display (" beat 0x%0h BAD ADDR", rg_rd_beat);
+ $display ("AXI4_Mem_Model[%0d]: rl_AR", id);
+ $display (" ", fshow_AR (ar));
+ $display (" ", fshow_R (r));
+ $display (" memword addr 0x%0h beat %0d ", addrMW, rg_R_beat);
end
endrule
// ================================================================
// Write requests
- Reg #(Bit #(8)) rg_wr_beat <- mkReg (0);
+ Reg #(Bit #(8)) rg_W_beat <- mkReg (0);
- // Recv request on WR_ADDR bus and burst data on WR_DATA bus,
- // send final response on WR_RESP bus
- rule rl_write (rg_initialized);
- let wr_addr = xactor.o_wr_addr.first;
- let wr_data <- pop_o (xactor.o_wr_data);
- let rf_index = ((wr_addr.awaddr - rg_addr_map_base) >> 3);
- if (wr_addr.awburst == axburst_incr)
- rf_index = rf_index + zeroExtend (rg_wr_beat);
- let last = (rg_wr_beat == wr_addr.awlen);
+ // Recv request on AW bus and burst data on W bus,
+ // send final response on B bus
+ rule rl_AW_W (rg_state == STATE_RUNNING);
+ let aw = ifc_M.o_AW.first;
+ let w <- pop_o (ifc_M.o_W);
- let addr_ok = fn_addr_ok (rg_addr_map_base, rg_addr_map_lim, wr_addr.awaddr, wr_addr.awsize);
+ Bit #(wd_addrMW) addrMW = truncateLSB (aw.awaddr);
+ if (aw.awburst == axburst_incr)
+ addrMW = addrMW + zeroExtend (rg_W_beat);
- if (addr_ok)
- rf.upd (rf_index, wr_data.wdata);
+ Bool ok <- fav_is_well_formed (aw.awaddr, addrMW, aw.awlen, aw.awsize, aw.awburst);
- if (verbosity != 0) begin
- $write ("%0d: %m.rl_write: ", cur_cycle);
- $write (fshow_Wr_Data (wr_data));
- $write (" ", fshow_Wr_Addr (wr_addr));
- if (addr_ok)
- $display (" beat %0d rf_index %0h", rg_wr_beat, rf_index);
- else
- $display (" beat %0d BAD ADDR", rg_wr_beat);
+ if (! ok) begin
+ $display ("AXI4_Mem_Model[%0d]: ERROR: AW is not well-formed", id);
+ $display (" ", fshow_AW (aw));
+ end
+
+ let last = (rg_W_beat == aw.awlen);
+
+ Bit #(wd_data) mask = fn_strb_to_bitmask (w.wstrb);
+
+ // Read-modify-write the memword using AXI4 memword and strobe
+ if (ok) begin
+ let old_mw = regfile.sub (addrMW);
+ let new_mw = (old_mw & (~ mask)) | (w.wdata & mask);
+ regfile.upd (addrMW, new_mw);
end
if (last) begin
- AXI4_Wr_Resp #(wd_id, wd_user) wr_resp = ?;
- wr_resp = AXI4_Wr_Resp {bid: wr_addr.awid,
- bresp: (addr_ok ? axi4_resp_okay : axi4_resp_slverr),
- buser: wr_addr.awuser};
- xactor.i_wr_resp.enq (wr_resp);
- xactor.o_wr_addr.deq;
- rg_wr_beat <= 0;
+ AXI4_B #(wd_id, wd_user) b = AXI4_B {bid: aw.awid,
+ bresp: (ok ? axi4_resp_okay
+ : axi4_resp_slverr),
+ buser: aw.awuser};
+ ifc_M.i_B.enq (b);
+ ifc_M.o_AW.deq;
+ rg_W_beat <= 0;
if (verbosity != 0)
- $display (" ", fshow_Wr_Resp (wr_resp));
+ $display (" ", fshow_B (b));
end
else
- rg_wr_beat <= rg_wr_beat + 1;
+ rg_W_beat <= rg_W_beat + 1;
+
+ if (verbosity != 0) begin
+ $write ("AXI4_Mem_Model[%0d]: rl_AW_W", id);
+ $display (" ", fshow_AW (aw));
+ $display (" ", fshow_W (w));
+ $display (" memword addr 0x%0h beat %0d ", addrMW, rg_W_beat);
+ end
endrule
- // ================================================================
+ // ****************************************************************
// INTERFACE
- method Action init (Bit #(wd_addr) addr_map_base, Bit #(wd_addr) addr_map_lim);
- if (addr_map_base [2:0] != 3'b0)
- $display ("%0d: %m.init: ERROR: unaligned addr_map_base 0x%0h", cur_cycle, addr_map_base);
- else if (addr_map_lim [2:0] != 3'b0)
- $display ("%0d: %m.init: ERROR: unaligned addr_map_lim 0x%0h", cur_cycle, addr_map_lim);
- else if (addr_map_lim <= addr_map_base)
- $display ("%0d: %m.init: ERROR: addr_map_base 0x%0h > addr_map_lim 0x%0h",
- cur_cycle,
- addr_map_base,
- addr_map_lim);
- else if ((addr_map_lim - addr_map_base) > fromInteger (mem_size_word64 * 8))
- $display ("%0d: %m.init: ERROR: mem size (base 0x%0h, lim 0x%0h) > max (0x%0h)",
- cur_cycle,
- addr_map_base,
- addr_map_lim,
- fromInteger (mem_size_word64 * 8));
- else begin
- xactor.reset;
- rg_addr_map_base <= addr_map_base;
- rg_addr_map_lim <= addr_map_lim;
- rg_initialized <= True;
- $display ("%0d: %m.init: addr_map_base 0x%0h, addr_map_lim 0x%0h",
- cur_cycle,
- addr_map_base,
- addr_map_lim);
- end
- endmethod
-
- interface s_ifc = xactor.axi_side;
+ // Empty
endmodule
-// ================================================================
+// ****************************************************************
endpackage
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_Types.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_Types.bsv
index f9b2ca3..536c6a3 100644
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_Types.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4/AXI4_Types.bsv
@@ -1,12 +1,14 @@
-// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved
-//
+// Copyright (c) 2019-2023 Bluespec, Inc. All Rights Reserved
+// Copyright (c) 2024 Rishiyur S. Nikhil.
+
// SPDX-License-Identifier: BSD-3-Clause
package AXI4_Types;
// ================================================================
// Facilities for ARM AXI4, consisting of 5 independent channels:
-// Write Address, Write Data, Write Response, Read Address and Read Data
+// AW (write address), W (write data), B (write response)
+// AR (read address), R (read data)
// Ref: ARM document:
// AMBA AXI and ACE Protocol Specification
@@ -15,27 +17,25 @@ package AXI4_Types;
// ARM IHI 0022E (ID022613)
// Issue E, 22 Feb 2013
-// ================================================================
+// ****************************************************************
// BSV library imports
import FIFOF :: *;
import Connectable :: *;
+import Vector :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Semi_FIFOF :: *;
import EdgeFIFOFs :: *;
// ****************************************************************
// ****************************************************************
-// Section: RTL-level interfaces
+// Section: Basic bus and bus-field types
// ****************************************************************
// ****************************************************************
-// ================================================================
-// Fixed-width AXI4 buses
-
// ----------------
// AxLen: burst length (# of transfers in a transaction)
// Burst_Length = AxLEN[7:0] + 1 (1..256)
@@ -58,7 +58,17 @@ AXI4_Size axsize_64 = 3'b_110;
AXI4_Size axsize_128 = 3'b_111;
function Bit #(8) fv_AXI4_Size_to_num_bytes (AXI4_Size axi4_size);
- return (1 << axi4_size);
+ return (case (axi4_size)
+ axsize_1: 1;
+ axsize_2: 2;
+ axsize_4: 4;
+ axsize_8: 8;
+ axsize_16: 16;
+ axsize_32: 32;
+ axsize_64: 64;
+ axsize_128: 128;
+ default: 0; // Bogus
+ endcase);
endfunction
function AXI4_Size fv_num_bytes_to_AXI4_Size (Bit #(8) num_bytes);
@@ -75,6 +85,17 @@ function AXI4_Size fv_num_bytes_to_AXI4_Size (Bit #(8) num_bytes);
endcase);
endfunction
+function Bool fn_addr_is_aligned (Bit #(wd_addr) addr, AXI4_Size size);
+ return ( (size == axsize_1)
+ || ((size == axsize_2) && (addr [0] == 1'b0))
+ || ((size == axsize_4) && (addr [1:0] == 2'b0))
+ || ((size == axsize_8) && (addr [2:0] == 3'b0))
+ || ((size == axsize_16) && (addr [3:0] == 4'b0))
+ || ((size == axsize_32) && (addr [4:0] == 5'b0))
+ || ((size == axsize_64) && (addr [5:0] == 6'b0))
+ || ((size == axsize_128) && (addr [6:0] == 7'b0)));
+endfunction
+
// ----------------
// AxBURST Burst type
@@ -154,467 +175,26 @@ AXI4_Resp axi4_resp_exokay = 2'b_01;
AXI4_Resp axi4_resp_slverr = 2'b_10;
AXI4_Resp axi4_resp_decerr = 2'b_11;
-// ================================================================
-// Function to check address-alignment
-
-function Bool fn_addr_is_aligned (Bit #(wd_addr) addr, AXI4_Size size);
- return ( (size == axsize_1)
- || ((size == axsize_2) && (addr [0] == 1'b0))
- || ((size == axsize_4) && (addr [1:0] == 2'b0))
- || ((size == axsize_8) && (addr [2:0] == 3'b0))
- || ((size == axsize_16) && (addr [3:0] == 4'b0))
- || ((size == axsize_32) && (addr [4:0] == 5'b0))
- || ((size == axsize_64) && (addr [5:0] == 6'b0))
- || ((size == axsize_128) && (addr [6:0] == 7'b0)));
-endfunction
-
-// ================================================================
-// These are the signal-level interfaces for an AXI4 M.
-// The (*..*) attributes ensure that when bsc compiles this to Verilog,
-// we get exactly the signals specified in the ARM spec.
-
-interface AXI4_M_IFC #(numeric type wd_id,
- numeric type wd_addr,
- numeric type wd_data,
- numeric type wd_user);
- // ----------------
- // Wr Addr channel
- (* always_ready, result="awvalid" *) method Bool m_awvalid; // out
-
- (* always_ready, result="awid" *) method Bit #(wd_id) m_awid; // out
- (* always_ready, result="awaddr" *) method Bit #(wd_addr) m_awaddr; // out
- (* always_ready, result="awlen" *) method Bit #(8) m_awlen; // out
- (* always_ready, result="awsize" *) method AXI4_Size m_awsize; // out
- (* always_ready, result="awburst" *) method Bit #(2) m_awburst; // out
- (* always_ready, result="awlock" *) method Bit #(1) m_awlock; // out
- (* always_ready, result="awcache" *) method Bit #(4) m_awcache; // out
- (* always_ready, result="awprot" *) method Bit #(3) m_awprot; // out
- (* always_ready, result="awqos" *) method Bit #(4) m_awqos; // out
- (* always_ready, result="awregion" *) method Bit #(4) m_awregion; // out
- (* always_ready, result="awuser" *) method Bit #(wd_user) m_awuser; // out
-
- (* always_ready, always_enabled, prefix="" *)
- method Action m_awready ((* port="awready" *) Bool awready); // in
-
- // ----------------
- // Wr Data channel
- (* always_ready, result="wvalid" *) method Bool m_wvalid; // out
-
- (* always_ready, result="wdata" *) method Bit #(wd_data) m_wdata; // out
- (* always_ready, result="wstrb" *) method Bit #(TDiv #(wd_data, 8)) m_wstrb; // out
- (* always_ready, result="wlast" *) method Bool m_wlast; // out
- (* always_ready, result="wuser" *) method Bit #(wd_user) m_wuser; // out
-
- (* always_ready, always_enabled, prefix = "" *)
- method Action m_wready ((* port="wready" *) Bool wready); // in
-
- // ----------------
- // Wr Response channel
- (* always_ready, always_enabled, prefix = "" *)
- method Action m_bvalid ((* port="bvalid" *) Bool bvalid, // in
- (* port="bid" *) Bit #(wd_id) bid, // in
- (* port="bresp" *) Bit #(2) bresp, // in
- (* port="buser" *) Bit #(wd_user) buser); // in
-
- (* always_ready, prefix = "", result="bready" *)
- method Bool m_bready; // out
-
- // ----------------
- // Rd Addr channel
- (* always_ready, result="arvalid" *) method Bool m_arvalid; // out
-
- (* always_ready, result="arid" *) method Bit #(wd_id) m_arid; // out
- (* always_ready, result="araddr" *) method Bit #(wd_addr) m_araddr; // out
- (* always_ready, result="arlen" *) method Bit #(8) m_arlen; // out
- (* always_ready, result="arsize" *) method AXI4_Size m_arsize; // out
- (* always_ready, result="arburst" *) method Bit #(2) m_arburst; // out
- (* always_ready, result="arlock" *) method Bit #(1) m_arlock; // out
- (* always_ready, result="arcache" *) method Bit #(4) m_arcache; // out
- (* always_ready, result="arprot" *) method Bit #(3) m_arprot; // out
- (* always_ready, result="arqos" *) method Bit #(4) m_arqos; // out
- (* always_ready, result="arregion" *) method Bit #(4) m_arregion; // out
- (* always_ready, result="aruser" *) method Bit #(wd_user) m_aruser; // out
-
- (* always_ready, always_enabled, prefix="" *)
- method Action m_arready ((* port="arready" *) Bool arready); // in
-
- // ----------------
- // Rd Data channel
- (* always_ready, always_enabled, prefix = "" *)
- method Action m_rvalid ((* port="rvalid" *) Bool rvalid, // in
- (* port="rid" *) Bit #(wd_id) rid, // in
- (* port="rdata" *) Bit #(wd_data) rdata, // in
- (* port="rresp" *) Bit #(2) rresp, // in
- (* port="rlast" *) Bool rlast, // in
- (* port="ruser" *) Bit #(wd_user) ruser); // in
-
- (* always_ready, result="rready" *)
- method Bool m_rready; // out
-endinterface: AXI4_M_IFC
-
-// ================================================================
-// These are the signal-level interfaces for an AXI4-Lite S.
-// The (*..*) attributes ensure that when bsc compiles this to Verilog,
-// we get exactly the signals specified in the ARM spec.
-
-interface AXI4_S_IFC #(numeric type wd_id,
- numeric type wd_addr,
- numeric type wd_data,
- numeric type wd_user);
- // Wr Addr channel
- (* always_ready, always_enabled, prefix = "" *)
- method Action m_awvalid ((* port="awvalid" *) Bool awvalid, // in
- (* port="awid" *) Bit #(wd_id) awid, // in
- (* port="awaddr" *) Bit #(wd_addr) awaddr, // in
- (* port="awlen" *) Bit #(8) awlen, // in
- (* port="awsize" *) AXI4_Size awsize, // in
- (* port="awburst" *) Bit #(2) awburst, // in
- (* port="awlock" *) Bit #(1) awlock, // in
- (* port="awcache" *) Bit #(4) awcache, // in
- (* port="awprot" *) Bit #(3) awprot, // in
- (* port="awqos" *) Bit #(4) awqos, // in
- (* port="awregion" *) Bit #(4) awregion, // in
- (* port="awuser" *) Bit #(wd_user) awuser); // in
- (* always_ready, result="awready" *)
- method Bool m_awready; // out
-
- // Wr Data channel
- (* always_ready, always_enabled, prefix = "" *)
- method Action m_wvalid ((* port="wvalid" *) Bool wvalid, // in
- (* port="wdata" *) Bit #(wd_data) wdata, // in
- (* port="wstrb" *) Bit #(TDiv #(wd_data,8)) wstrb, // in
- (* port="wlast" *) Bool wlast, // in
- (* port="wuser" *) Bit #(wd_user) wuser); // in
- (* always_ready, result="wready" *)
- method Bool m_wready; // out
-
- // Wr Response channel
- (* always_ready, result="bvalid" *) method Bool m_bvalid; // out
- (* always_ready, result="bid" *) method Bit #(wd_id) m_bid; // out
- (* always_ready, result="bresp" *) method Bit #(2) m_bresp; // out
- (* always_ready, result="buser" *) method Bit #(wd_user) m_buser; // out
- (* always_ready, always_enabled, prefix="" *)
- method Action m_bready ((* port="bready" *) Bool bready); // in
-
- // Rd Addr channel
- (* always_ready, always_enabled, prefix = "" *)
- method Action m_arvalid ((* port="arvalid" *) Bool arvalid, // in
- (* port="arid" *) Bit #(wd_id) arid, // in
- (* port="araddr" *) Bit #(wd_addr) araddr, // in
- (* port="arlen" *) Bit #(8) arlen, // in
- (* port="arsize" *) AXI4_Size arsize, // in
- (* port="arburst" *) Bit #(2) arburst, // in
- (* port="arlock" *) Bit #(1) arlock, // in
- (* port="arcache" *) Bit #(4) arcache, // in
- (* port="arprot" *) Bit #(3) arprot, // in
- (* port="arqos" *) Bit #(4) arqos, // in
- (* port="arregion" *) Bit #(4) arregion, // in
- (* port="aruser" *) Bit #(wd_user) aruser); // in
- (* always_ready, result="arready" *)
- method Bool m_arready; // out
-
- // Rd Data channel
- (* always_ready, result="rvalid" *) method Bool m_rvalid; // out
- (* always_ready, result="rid" *) method Bit #(wd_id) m_rid; // out
- (* always_ready, result="rdata" *) method Bit #(wd_data) m_rdata; // out
- (* always_ready, result="rresp" *) method Bit #(2) m_rresp; // out
- (* always_ready, result="rlast" *) method Bool m_rlast; // out
- (* always_ready, result="ruser" *) method Bit #(wd_user) m_ruser; // out
- (* always_ready, always_enabled, prefix="" *)
- method Action m_rready ((* port="rready" *) Bool rready); // in
-endinterface: AXI4_S_IFC
-
-// ================================================================
-// Connecting signal-level interfaces
-
-instance Connectable #(AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user),
- AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user));
-
- module mkConnection #(AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user) axim,
- AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user) axis)
- (Empty);
-
- (* fire_when_enabled, no_implicit_conditions *)
- rule rl_wr_addr_channel;
- axis.m_awvalid (axim.m_awvalid,
- axim.m_awid,
- axim.m_awaddr,
- axim.m_awlen,
- axim.m_awsize,
- axim.m_awburst,
- axim.m_awlock,
- axim.m_awcache,
- axim.m_awprot,
- axim.m_awqos,
- axim.m_awregion,
- axim.m_awuser);
- axim.m_awready (axis.m_awready);
- endrule
-
- (* fire_when_enabled, no_implicit_conditions *)
- rule rl_wr_data_channel;
- axis.m_wvalid (axim.m_wvalid,
- axim.m_wdata,
- axim.m_wstrb,
- axim.m_wlast,
- axim.m_wuser);
- axim.m_wready (axis.m_wready);
- endrule
-
- (* fire_when_enabled, no_implicit_conditions *)
- rule rl_wr_response_channel;
- axim.m_bvalid (axis.m_bvalid,
- axis.m_bid,
- axis.m_bresp,
- axis.m_buser);
- axis.m_bready (axim.m_bready);
- endrule
-
- (* fire_when_enabled, no_implicit_conditions *)
- rule rl_rd_addr_channel;
- axis.m_arvalid (axim.m_arvalid,
- axim.m_arid,
- axim.m_araddr,
- axim.m_arlen,
- axim.m_arsize,
- axim.m_arburst,
- axim.m_arlock,
- axim.m_arcache,
- axim.m_arprot,
- axim.m_arqos,
- axim.m_arregion,
- axim.m_aruser);
- axim.m_arready (axis.m_arready);
- endrule
-
- (* fire_when_enabled, no_implicit_conditions *)
- rule rl_rd_data_channel;
- axim.m_rvalid (axis.m_rvalid,
- axis.m_rid,
- axis.m_rdata,
- axis.m_rresp,
- axis.m_rlast,
- axis.m_ruser);
- axis.m_rready (axim.m_rready);
- endrule
- endmodule
-endinstance
-
-// ================================================================
-// AXI4 dummy M: never produces requests, never accepts responses
-
-AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user)
- dummy_AXI4_M_ifc = interface AXI4_M_IFC
- // Wr Addr channel
- method Bool m_awvalid = False; // out
- method Bit #(wd_id) m_awid = ?; // out
- method Bit #(wd_addr) m_awaddr = ?; // out
- method Bit #(8) m_awlen = ?; // out
- method AXI4_Size m_awsize = ?; // out
- method Bit #(2) m_awburst = ?; // out
- method Bit #(1) m_awlock = ?; // out
- method Bit #(4) m_awcache = ?; // out
- method Bit #(3) m_awprot = ?; // out
- method Bit #(4) m_awqos = ?; // out
- method Bit #(4) m_awregion = ?; // out
- method Bit #(wd_user) m_awuser = ?; // out
- method Action m_awready (Bool awready) = noAction; // in
-
- // Wr Data channel
- method Bool m_wvalid = False; // out
- method Bit #(wd_data) m_wdata = ?; // out
- method Bit #(TDiv #(wd_data, 8)) m_wstrb = ?; // out
- method Bool m_wlast = ?; // out
- method Bit #(wd_user) m_wuser = ?; // out
-
- method Action m_wready (Bool wready) = noAction; // in
-
- // Wr Response channel
- method Action m_bvalid (Bool bvalid, // in
- Bit #(wd_id) bid, // in
- Bit #(2) bresp, // in
- Bit #(wd_user) buser); // in
- noAction;
- endmethod
- method Bool m_bready = False; // out
-
- // Rd Addr channel
- method Bool m_arvalid = False; // out
- method Bit #(wd_id) m_arid = ?; // out
- method Bit #(wd_addr) m_araddr = ?; // out
- method Bit #(8) m_arlen = ?; // out
- method AXI4_Size m_arsize = ?; // out
- method Bit #(2) m_arburst = ?; // out
- method Bit #(1) m_arlock = ?; // out
- method Bit #(4) m_arcache = ?; // out
- method Bit #(3) m_arprot = ?; // out
- method Bit #(4) m_arqos = ?; // out
- method Bit #(4) m_arregion = ?; // out
- method Bit #(wd_user) m_aruser = ?; // out
- method Action m_arready (Bool arready) = noAction; // in
-
- // Rd Data channel
- method Action m_rvalid (Bool rvalid, // in
- Bit #(wd_id) rid, // in
- Bit #(wd_data) rdata, // in
- Bit #(2) rresp, // in
- Bool rlast, // in
- Bit #(wd_user) ruser); // in
- noAction;
- endmethod
- method Bool m_rready = False; // out
- endinterface;
+// ----------------
+// Expand the AXI4 'wstrb' field into a bit-mask
-// ================================================================
-// AXI4 dummy S: never accepts requests, never produces responses
-
-AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user)
- dummy_AXI4_S_ifc = interface AXI4_S_IFC
- // Wr Addr channel
- method Action m_awvalid (Bool awvalid,
- Bit #(wd_id) awid,
- Bit #(wd_addr) awaddr,
- Bit #(8) awlen,
- AXI4_Size awsize,
- Bit #(2) awburst,
- Bit #(1) awlock,
- Bit #(4) awcache,
- Bit #(3) awprot,
- Bit #(4) awqos,
- Bit #(4) awregion,
- Bit #(wd_user) awuser);
- noAction;
- endmethod
-
- method Bool m_awready;
- return False;
- endmethod
-
- // Wr Data channel
- method Action m_wvalid (Bool wvalid,
- Bit #(wd_data) wdata,
- Bit #(TDiv #(wd_data, 8)) wstrb,
- Bool wlast,
- Bit #(wd_user) wuser);
- noAction;
- endmethod
-
- method Bool m_wready;
- return False;
- endmethod
-
- // Wr Response channel
- method Bool m_bvalid;
- return False;
- endmethod
-
- method Bit #(wd_id) m_bid;
- return ?;
- endmethod
-
- method Bit #(2) m_bresp;
- return 0;
- endmethod
-
- method Bit #(wd_user) m_buser;
- return ?;
- endmethod
-
- method Action m_bready (Bool bready);
- noAction;
- endmethod
-
- // Rd Addr channel
- method Action m_arvalid (Bool arvalid,
- Bit #(wd_id) arid,
- Bit #(wd_addr) araddr,
- Bit #(8) arlen,
- AXI4_Size arsize,
- Bit #(2) arburst,
- Bit #(1) arlock,
- Bit #(4) arcache,
- Bit #(3) arprot,
- Bit #(4) arqos,
- Bit #(4) arregion,
- Bit #(wd_user) aruser);
- noAction;
- endmethod
-
- method Bool m_arready;
- return False;
- endmethod
-
- // Rd Data channel
- method Bool m_rvalid;
- return False;
- endmethod
-
- method Bit #(wd_id) m_rid;
- return 0;
- endmethod
-
- method Bit #(wd_data) m_rdata;
- return 0;
- endmethod
-
- method Bit #(2) m_rresp;
- return 0;
- endmethod
-
- method Bool m_rlast;
- return True;
- endmethod
-
- method Bit #(wd_user) m_ruser;
- return ?;
- endmethod
-
- method Action m_rready (Bool rready);
- noAction;
- endmethod
- endinterface;
+function Bit #(wd_data) fn_strb_to_bitmask (Bit #(wd_data_B) strb)
+ provisos (Mul #(wd_data_B, 8, wd_data));
-// ****************************************************************
-// ****************************************************************
-// Section: Higher-level FIFO-like interfaces and transactors
-// ****************************************************************
-// ****************************************************************
-
-// ================================================================
-// Help function: fn_crg_and_rg_to_FIFOF_I
-// In the modules below, we use a crg_full and a rg_data to represent a fifo.
-// These functions convert these to FIFOF_I and FIFOF_O interfaces.
-
-function FIFOF_I #(t) fn_crg_and_rg_to_FIFOF_I (Reg #(Bool) rg_full, Reg #(t) rg_data);
- return interface FIFOF_I;
- method Action enq (t x) if (! rg_full);
- rg_full <= True;
- rg_data <= x;
- endmethod
- method Bool notFull;
- return (! rg_full);
- endmethod
- endinterface;
-endfunction
+ function Bit #(8) fn_bit_to_byte (Integer j);
+ return ((strb [j] == 1'b0) ? 0 : 'hFF);
+ endfunction
-function FIFOF_O #(t) fn_crg_and_rg_to_FIFOF_O (Reg #(Bool) rg_full, Reg #(t) rg_data);
- return interface FIFOF_O;
- method t first () if (rg_full);
- return rg_data;
- endmethod
- method Action deq () if (rg_full);
- rg_full <= False;
- endmethod
- method notEmpty;
- return rg_full;
- endmethod
- endinterface;
+ begin
+ Vector #(wd_Data_B, Bit #(8)) v_bytes = genWith (fn_bit_to_byte);
+ return pack (v_bytes);
+ end
endfunction
// ================================================================
-// Higher-level types for payloads (rather than just bits)
+// AR,R,AW,W,B struct types
-// Write Address channel
+// AW channel (Write Address)
typedef struct {
Bit #(wd_id) awid;
@@ -628,33 +208,33 @@ typedef struct {
Bit #(4) awqos;
Bit #(4) awregion;
Bit #(wd_user) awuser;
- } AXI4_Wr_Addr #(numeric type wd_id,
- numeric type wd_addr,
- numeric type wd_user)
+ } AXI4_AW #(numeric type wd_id,
+ numeric type wd_addr,
+ numeric type wd_user)
deriving (Bits, FShow);
-// Write Data channel
+// W channel (Write Data)
typedef struct {
Bit #(wd_data) wdata;
Bit #(TDiv #(wd_data, 8)) wstrb;
Bool wlast;
Bit #(wd_user) wuser;
- } AXI4_Wr_Data #(numeric type wd_data,
- numeric type wd_user)
+ } AXI4_W #(numeric type wd_data,
+ numeric type wd_user)
deriving (Bits, FShow);
-// Write Response channel
+// B channel (Write Response)
typedef struct {
Bit #(wd_id) bid;
Bit #(2) bresp;
Bit #(wd_user) buser;
- } AXI4_Wr_Resp #(numeric type wd_id,
- numeric type wd_user)
+ } AXI4_B #(numeric type wd_id,
+ numeric type wd_user)
deriving (Bits, FShow);
-// Read Address channel
+// AR channel (Read Address)
typedef struct {
Bit #(wd_id) arid;
@@ -668,12 +248,12 @@ typedef struct {
Bit #(4) arqos;
Bit #(4) arregion;
Bit #(wd_user) aruser;
- } AXI4_Rd_Addr #(numeric type wd_id,
- numeric type wd_addr,
- numeric type wd_user)
+ } AXI4_AR #(numeric type wd_id,
+ numeric type wd_addr,
+ numeric type wd_user)
deriving (Bits, FShow);
-// Read Data channel
+// R channel (Read Data))
typedef struct {
Bit #(wd_id) rid;
@@ -681,11 +261,71 @@ typedef struct {
Bit #(2) rresp;
Bool rlast;
Bit #(wd_user) ruser;
- } AXI4_Rd_Data #(numeric type wd_id,
- numeric type wd_data,
- numeric type wd_user)
+ } AXI4_R #(numeric type wd_id,
+ numeric type wd_data,
+ numeric type wd_user)
deriving (Bits, FShow);
+// ================================================================
+// The following functions change ID (possibly to different width).
+// These are used in interconnect fabrics to 'push' extra id bits on
+// M->S request traffic and 'pop' those bits in S->M response traffic.
+// The extra bits specify to which M a response should be sent.
+
+function AXI4_AW #(wd_id_out, wd_addr, wd_user)
+ fn_change_AW_id (AXI4_AW #(wd_id_in, wd_addr, wd_user) aw_in,
+ Bit #(wd_id_out) awid_out);
+ let aw_out = AXI4_AW {awid: awid_out,
+ awaddr: aw_in.awaddr,
+ awlen: aw_in.awlen,
+ awsize: aw_in.awsize,
+ awburst: aw_in.awburst,
+ awlock: aw_in.awlock,
+ awcache: aw_in.awcache,
+ awprot: aw_in.awprot,
+ awqos: aw_in.awqos,
+ awregion: aw_in.awregion,
+ awuser: aw_in.awuser};
+ return aw_out;
+endfunction
+
+function AXI4_B #(wd_id_out, wd_user)
+ fn_change_B_id (AXI4_B #(wd_id_in, wd_user) b_in,
+ Bit #(wd_id_out) bid_out);
+ let b_out = AXI4_B {bid: bid_out,
+ bresp: b_in.bresp,
+ buser: b_in.buser};
+ return b_out;
+endfunction
+
+function AXI4_AR #(wd_id_out, wd_addr, wd_user)
+ fn_change_AR_id (AXI4_AR #(wd_id_in, wd_addr, wd_user) ar_in,
+ Bit #(wd_id_out) arid_out);
+ let ar_out = AXI4_AR {arid: arid_out,
+ araddr: ar_in.araddr,
+ arlen: ar_in.arlen,
+ arsize: ar_in.arsize,
+ arburst: ar_in.arburst,
+ arlock: ar_in.arlock,
+ arcache: ar_in.arcache,
+ arprot: ar_in.arprot,
+ arqos: ar_in.arqos,
+ arregion: ar_in.arregion,
+ aruser: ar_in.aruser};
+ return ar_out;
+endfunction
+
+function AXI4_R #(wd_id_out, wd_data, wd_user)
+ fn_change_R_id (AXI4_R #(wd_id_in, wd_data, wd_user) r_in,
+ Bit #(wd_id_out) rid_out);
+ let r_out = AXI4_R {rid: rid_out,
+ rdata: r_in.rdata,
+ rresp: r_in.rresp,
+ rlast: r_in.rlast,
+ ruser: r_in.ruser};
+ return r_out;
+endfunction
+
// ================================================================
// The following are specialized 'fshow' functions for AXI4 bus
// payloads: the most common fields, and more compact.
@@ -723,781 +363,184 @@ endfunction
// ----------------
-function Fmt fshow_Wr_Addr (AXI4_Wr_Addr #(wd_id, wd_addr, wd_user) x);
- Fmt result = ($format ("{awaddr:%0h,", x.awaddr)
- + $format ("awlen:%0d", x.awlen)
- + $format (",")
+function Fmt fshow_AW (AXI4_AW #(wd_id, wd_addr, wd_user) x);
+ Fmt result = ($format ("AW{id:%0h addr:%0h", x.awid, x.awaddr)
+ + $format (" len:%0d", x.awlen)
+ + $format (" ")
+ fshow_AXI4_Size (x.awsize)
- + $format (",")
+ + $format (" ")
+ fshow_AXI4_Burst (x.awburst)
- + $format ("}"));
+ + $format (" user:%0h ..}", x.awuser));
return result;
endfunction
-function Fmt fshow_Wr_Data (AXI4_Wr_Data #(wd_data, wd_user) x);
- let result = ($format ("{wdata:%0h,wstrb:%0h", x.wdata, x.wstrb)
- + (x.wlast ? $format (",wlast") : $format (",.."))
- + $format ("}"));
+function Fmt fshow_W (AXI4_W #(wd_data, wd_user) x);
+ let result = ($format ("W{data:%0h strb:%0h", x.wdata, x.wstrb)
+ + (x.wlast ? $format (" last") : $format (""))
+ + $format (" user:%0h ..}", x.wuser));
return result;
endfunction
-function Fmt fshow_Wr_Resp (AXI4_Wr_Resp #(wd_id, wd_user) x);
- Fmt result = ($format ("{bresp:")
+function Fmt fshow_B (AXI4_B #(wd_id, wd_user) x);
+ Fmt result = ($format ("B{id:%0h resp:", x.bid)
+ fshow_AXI4_Resp (x.bresp)
- + $format ("}"));
+ + $format (" user:%0h ..}", x.buser));
return result;
endfunction
-function Fmt fshow_Rd_Addr (AXI4_Rd_Addr #(wd_id, wd_addr, wd_user) x);
- Fmt result = ($format ("{araddr:%0h", x.araddr)
- + $format (",arlen:%0d", x.arlen)
- + $format (",")
+function Fmt fshow_AR (AXI4_AR #(wd_id, wd_addr, wd_user) x);
+ Fmt result = ($format ("AR{id:%0h addr:%0h", x.arid, x.araddr)
+ + $format (" len:%0d", x.arlen)
+ + $format (" ")
+ fshow_AXI4_Size (x.arsize)
- + $format (",")
+ + $format (" ")
+ fshow_AXI4_Burst (x.arburst)
- + $format ("}"));
+ + $format (" user:%0h ..}", x.aruser));
return result;
endfunction
-function Fmt fshow_Rd_Data (AXI4_Rd_Data #(wd_id, wd_data, wd_user) x);
- Fmt result = ($format ("{rresp:")
+function Fmt fshow_R (AXI4_R #(wd_id, wd_data, wd_user) x);
+ Fmt result = ($format ("R{id%0h resp:", x.rid)
+ fshow_AXI4_Resp (x.rresp)
- + $format (",rdata:%0h", x.rdata)
- + (x.rlast ? $format (",rlast") : $format (",.."))
- + $format ("}"));
+ + $format (" data:%0h", x.rdata)
+ + (x.rlast ? $format (" last") : $format (""))
+ + $format (" user:%0h ..}", x.ruser));
return result;
endfunction
+// ****************************************************************
+// ****************************************************************
+// Section: Higher-level FIFO-like interfaces and transactors
+// ****************************************************************
+// ****************************************************************
+
// ================================================================
-// AXI4 buffer
+// AXI4 interfaces with BSV FIFO sub-interfaces for each channel
+// (instead of RTL ready/valid signaling)
// ----------------
-// Server-side interface accepts requests and yields responses
+// M interface with FIFOs
-interface AXI4_Server_IFC #(numeric type wd_id,
- numeric type wd_addr,
- numeric type wd_data,
- numeric type wd_user);
+interface AXI4_M_IFC #(numeric type wd_id,
+ numeric type wd_addr,
+ numeric type wd_data,
+ numeric type wd_user);
- interface FIFOF_I #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) i_wr_addr;
- interface FIFOF_I #(AXI4_Wr_Data #(wd_data, wd_user)) i_wr_data;
- interface FIFOF_O #(AXI4_Wr_Resp #(wd_id, wd_user)) o_wr_resp;
+ interface FIFOF_O #(AXI4_AW #(wd_id, wd_addr, wd_user)) o_AW;
+ interface FIFOF_O #(AXI4_W #(wd_data, wd_user)) o_W;
+ interface FIFOF_I #(AXI4_B #(wd_id, wd_user)) i_B;
- interface FIFOF_I #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) i_rd_addr;
- interface FIFOF_O #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) o_rd_data;
+ interface FIFOF_O #(AXI4_AR #(wd_id, wd_addr, wd_user)) o_AR;
+ interface FIFOF_I #(AXI4_R #(wd_id, wd_data, wd_user)) i_R;
endinterface
// ----------------
-// Client-side interface yields requests and accepts responses
+// S interface with FIFOs
-interface AXI4_Client_IFC #(numeric type wd_id,
- numeric type wd_addr,
- numeric type wd_data,
- numeric type wd_user);
+interface AXI4_S_IFC #(numeric type wd_id,
+ numeric type wd_addr,
+ numeric type wd_data,
+ numeric type wd_user);
- interface FIFOF_O #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) o_wr_addr;
- interface FIFOF_O #(AXI4_Wr_Data #(wd_data, wd_user)) o_wr_data;
- interface FIFOF_I #(AXI4_Wr_Resp #(wd_id, wd_user)) i_wr_resp;
+ interface FIFOF_I #(AXI4_AW #(wd_id, wd_addr, wd_user)) i_AW;
+ interface FIFOF_I #(AXI4_W #(wd_data, wd_user)) i_W;
+ interface FIFOF_O #(AXI4_B #(wd_id, wd_user)) o_B;
- interface FIFOF_O #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) o_rd_addr;
- interface FIFOF_I #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) i_rd_data;
+ interface FIFOF_I #(AXI4_AR #(wd_id, wd_addr, wd_user)) i_AR;
+ interface FIFOF_O #(AXI4_R #(wd_id, wd_data, wd_user)) o_R;
endinterface
// ----------------
-// A Buffer has a server-side and a client-side, and a reset
+// Connecting AXI4_M_IFC and AXI4_S_IFC
+
+instance Connectable #(AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user),
+ AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user));
+
+ module mkConnection #(AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user) m,
+ AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user) s) (Empty);
+ mkConnection (m.o_AW, s.i_AW);
+ mkConnection (m.o_W, s.i_W);
+ mkConnection (m.i_B, s.o_B);
+ mkConnection (m.o_AR, s.i_AR);
+ mkConnection (m.i_R, s.o_R);
+ endmodule
+endinstance
+
+// ================================================================
+// Interface of an AXI4 buffer with FIFO-like interfaces on both sides
interface AXI4_Buffer_IFC #(numeric type wd_id,
numeric type wd_addr,
numeric type wd_data,
numeric type wd_user);
- method Action reset;
- interface AXI4_Server_IFC #(wd_id, wd_addr, wd_data, wd_user) server_side;
- interface AXI4_Client_IFC #(wd_id, wd_addr, wd_data, wd_user) client_side;
+ // Facing upstream
+ interface AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user) ifc_S;
+ // Facing downstream
+ interface AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user) ifc_M;
endinterface
// ----------------------------------------------------------------
+// The following two modules differ only in using mkFIFOF or
+// mkM_EdgeFIFOF internally.
+// Note: we can't write a single module parameterized by the internal
+// FIFOs because mkFIFOF is instantiated at different types.
module mkAXI4_Buffer (AXI4_Buffer_IFC #(wd_id, wd_addr, wd_data, wd_user));
- FIFOF #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) f_wr_addr <- mkFIFOF;
- FIFOF #(AXI4_Wr_Data #(wd_data, wd_user)) f_wr_data <- mkFIFOF;
- FIFOF #(AXI4_Wr_Resp #(wd_id, wd_user)) f_wr_resp <- mkFIFOF;
+ FIFOF #(AXI4_AW #(wd_id, wd_addr, wd_user)) f_AW <- mkFIFOF;
+ FIFOF #(AXI4_W #(wd_data, wd_user)) f_W <- mkFIFOF;
+ FIFOF #(AXI4_B #(wd_id, wd_user)) f_B <- mkFIFOF;
- FIFOF #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) f_rd_addr <- mkFIFOF;
- FIFOF #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) f_rd_data <- mkFIFOF;
+ FIFOF #(AXI4_AR #(wd_id, wd_addr, wd_user)) f_AR <- mkFIFOF;
+ FIFOF #(AXI4_R #(wd_id, wd_data, wd_user)) f_R <- mkFIFOF;
- method Action reset;
- f_wr_addr.clear;
- f_wr_data.clear;
- f_wr_resp.clear;
+ interface AXI4_M_IFC ifc_M;
+ interface o_AW = to_FIFOF_O (f_AW);
+ interface o_W = to_FIFOF_O (f_W);
+ interface i_B = to_FIFOF_I (f_B);
- f_rd_addr.clear;
- f_rd_data.clear;
- endmethod
-
- interface AXI4_Server_IFC server_side;
- interface i_wr_addr = to_FIFOF_I (f_wr_addr);
- interface i_wr_data = to_FIFOF_I (f_wr_data);
- interface o_wr_resp = to_FIFOF_O (f_wr_resp);
-
- interface i_rd_addr = to_FIFOF_I (f_rd_addr);
- interface o_rd_data = to_FIFOF_O (f_rd_data);
+ interface o_AR = to_FIFOF_O (f_AR);
+ interface i_R = to_FIFOF_I (f_R);
endinterface
- interface AXI4_Client_IFC client_side;
- interface o_wr_addr = to_FIFOF_O (f_wr_addr);
- interface o_wr_data = to_FIFOF_O (f_wr_data);
- interface i_wr_resp = to_FIFOF_I (f_wr_resp);
+ interface AXI4_S_IFC ifc_S;
+ interface i_AW = to_FIFOF_I (f_AW);
+ interface i_W = to_FIFOF_I (f_W);
+ interface o_B = to_FIFOF_O (f_B);
- interface o_rd_addr = to_FIFOF_O (f_rd_addr);
- interface i_rd_data = to_FIFOF_I (f_rd_data);
+ interface i_AR = to_FIFOF_I (f_AR);
+ interface o_R = to_FIFOF_O (f_R);
endinterface
endmodule
module mkAXI4_Buffer_2 (AXI4_Buffer_IFC #(wd_id, wd_addr, wd_data, wd_user));
- FIFOF #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) f_wr_addr <- mkM_EdgeFIFOF;
- FIFOF #(AXI4_Wr_Data #(wd_data, wd_user)) f_wr_data <- mkM_EdgeFIFOF;
- FIFOF #(AXI4_Wr_Resp #(wd_id, wd_user)) f_wr_resp <- mkS_EdgeFIFOF;
-
- FIFOF #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) f_rd_addr <- mkM_EdgeFIFOF;
- FIFOF #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) f_rd_data <- mkS_EdgeFIFOF;
-
- method Action reset;
- f_wr_addr.clear;
- f_wr_data.clear;
- f_wr_resp.clear;
+ FIFOF #(AXI4_AW #(wd_id, wd_addr, wd_user)) f_AW <- mkM_EdgeFIFOF;
+ FIFOF #(AXI4_W #(wd_data, wd_user)) f_W <- mkM_EdgeFIFOF;
+ FIFOF #(AXI4_B #(wd_id, wd_user)) f_B <- mkS_EdgeFIFOF;
- f_rd_addr.clear;
- f_rd_data.clear;
- endmethod
+ FIFOF #(AXI4_AR #(wd_id, wd_addr, wd_user)) f_AR <- mkM_EdgeFIFOF;
+ FIFOF #(AXI4_R #(wd_id, wd_data, wd_user)) f_R <- mkS_EdgeFIFOF;
- interface AXI4_Server_IFC server_side;
- interface i_wr_addr = to_FIFOF_I (f_wr_addr);
- interface i_wr_data = to_FIFOF_I (f_wr_data);
- interface o_wr_resp = to_FIFOF_O (f_wr_resp);
+ interface AXI4_M_IFC ifc_M;
+ interface o_AW = to_FIFOF_O (f_AW);
+ interface o_W = to_FIFOF_O (f_W);
+ interface i_B = to_FIFOF_I (f_B);
- interface i_rd_addr = to_FIFOF_I (f_rd_addr);
- interface o_rd_data = to_FIFOF_O (f_rd_data);
+ interface o_AR = to_FIFOF_O (f_AR);
+ interface i_R = to_FIFOF_I (f_R);
endinterface
- interface AXI4_Client_IFC client_side;
- interface o_wr_addr = to_FIFOF_O (f_wr_addr);
- interface o_wr_data = to_FIFOF_O (f_wr_data);
- interface i_wr_resp = to_FIFOF_I (f_wr_resp);
+ interface AXI4_S_IFC ifc_S;
+ interface i_AW = to_FIFOF_I (f_AW);
+ interface i_W = to_FIFOF_I (f_W);
+ interface o_B = to_FIFOF_O (f_B);
- interface o_rd_addr = to_FIFOF_O (f_rd_addr);
- interface i_rd_data = to_FIFOF_I (f_rd_data);
+ interface i_AR = to_FIFOF_I (f_AR);
+ interface o_R = to_FIFOF_O (f_R);
endinterface
endmodule
-// ================================================================
-// M transactor interface
-
-interface AXI4_M_Xactor_IFC #(numeric type wd_id,
- numeric type wd_addr,
- numeric type wd_data,
- numeric type wd_user);
- method Action reset;
-
- // AXI side
- interface AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user) axi_side;
-
- // FIFOF side
- interface FIFOF_I #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) i_wr_addr;
- interface FIFOF_I #(AXI4_Wr_Data #(wd_data, wd_user)) i_wr_data;
- interface FIFOF_O #(AXI4_Wr_Resp #(wd_id, wd_user)) o_wr_resp;
-
- interface FIFOF_I #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) i_rd_addr;
- interface FIFOF_O #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) o_rd_data;
-endinterface: AXI4_M_Xactor_IFC
-
-// ----------------------------------------------------------------
-// M transactor
-// This version uses FIFOFs for total decoupling.
-
-module mkAXI4_M_Xactor (AXI4_M_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user));
-
- Bool unguarded = True;
- Bool guarded = False;
-
- // These FIFOs are guarded on BSV side, unguarded on AXI side
- FIFOF #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) f_wr_addr <- mkGFIFOF (guarded, unguarded);
- FIFOF #(AXI4_Wr_Data #(wd_data, wd_user)) f_wr_data <- mkGFIFOF (guarded, unguarded);
- FIFOF #(AXI4_Wr_Resp #(wd_id, wd_user)) f_wr_resp <- mkGFIFOF (unguarded, guarded);
-
- FIFOF #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) f_rd_addr <- mkGFIFOF (guarded, unguarded);
- FIFOF #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) f_rd_data <- mkGFIFOF (unguarded, guarded);
-
- // ----------------------------------------------------------------
- // INTERFACE
-
- method Action reset;
- f_wr_addr.clear;
- f_wr_data.clear;
- f_wr_resp.clear;
- f_rd_addr.clear;
- f_rd_data.clear;
- endmethod
-
- // AXI side
- interface axi_side = interface AXI4_M_IFC;
- // Wr Addr channel
- method Bool m_awvalid = f_wr_addr.notEmpty;
- method Bit #(wd_id) m_awid = f_wr_addr.first.awid;
- method Bit #(wd_addr) m_awaddr = f_wr_addr.first.awaddr;
- method Bit #(8) m_awlen = f_wr_addr.first.awlen;
- method AXI4_Size m_awsize = f_wr_addr.first.awsize;
- method Bit #(2) m_awburst = f_wr_addr.first.awburst;
- method Bit #(1) m_awlock = f_wr_addr.first.awlock;
- method Bit #(4) m_awcache = f_wr_addr.first.awcache;
- method Bit #(3) m_awprot = f_wr_addr.first.awprot;
- method Bit #(4) m_awqos = f_wr_addr.first.awqos;
- method Bit #(4) m_awregion = f_wr_addr.first.awregion;
- method Bit #(wd_user) m_awuser = f_wr_addr.first.awuser;
- method Action m_awready (Bool awready);
- if (f_wr_addr.notEmpty && awready) f_wr_addr.deq;
- endmethod
-
- // Wr Data channel
- method Bool m_wvalid = f_wr_data.notEmpty;
- method Bit #(wd_data) m_wdata = f_wr_data.first.wdata;
- method Bit #(TDiv #(wd_data, 8)) m_wstrb = f_wr_data.first.wstrb;
- method Bool m_wlast = f_wr_data.first.wlast;
- method Bit #(wd_user) m_wuser = f_wr_data.first.wuser;
- method Action m_wready (Bool wready);
- if (f_wr_data.notEmpty && wready) f_wr_data.deq;
- endmethod
-
- // Wr Response channel
- method Action m_bvalid (Bool bvalid,
- Bit #(wd_id) bid,
- Bit #(2) bresp,
- Bit #(wd_user) buser);
- if (bvalid && f_wr_resp.notFull)
- f_wr_resp.enq (AXI4_Wr_Resp {bid: bid,
- bresp: bresp,
- buser: buser});
- endmethod
-
- method Bool m_bready;
- return f_wr_resp.notFull;
- endmethod
-
- // Rd Addr channel
- method Bool m_arvalid = f_rd_addr.notEmpty;
- method Bit #(wd_id) m_arid = f_rd_addr.first.arid;
- method Bit #(wd_addr) m_araddr = f_rd_addr.first.araddr;
- method Bit #(8) m_arlen = f_rd_addr.first.arlen;
- method AXI4_Size m_arsize = f_rd_addr.first.arsize;
- method Bit #(2) m_arburst = f_rd_addr.first.arburst;
- method Bit #(1) m_arlock = f_rd_addr.first.arlock;
- method Bit #(4) m_arcache = f_rd_addr.first.arcache;
- method Bit #(3) m_arprot = f_rd_addr.first.arprot;
- method Bit #(4) m_arqos = f_rd_addr.first.arqos;
- method Bit #(4) m_arregion = f_rd_addr.first.arregion;
- method Bit #(wd_user) m_aruser = f_rd_addr.first.aruser;
-
- method Action m_arready (Bool arready);
- if (f_rd_addr.notEmpty && arready) f_rd_addr.deq;
- endmethod
-
- // Rd Data channel
- method Action m_rvalid (Bool rvalid, // in
- Bit #(wd_id) rid, // in
- Bit #(wd_data) rdata, // in
- Bit #(2) rresp, // in
- Bool rlast, // in
- Bit #(wd_user) ruser); // in
- if (rvalid && f_rd_data.notFull)
- f_rd_data.enq (AXI4_Rd_Data {rid: rid,
- rdata: rdata,
- rresp: rresp,
- rlast: rlast,
- ruser: ruser});
- endmethod
-
- method Bool m_rready;
- return f_rd_data.notFull;
- endmethod
-
- endinterface;
-
- // FIFOF side
- interface i_wr_addr = to_FIFOF_I (f_wr_addr);
- interface i_wr_data = to_FIFOF_I (f_wr_data);
- interface o_wr_resp = to_FIFOF_O (f_wr_resp);
-
- interface i_rd_addr = to_FIFOF_I (f_rd_addr);
- interface o_rd_data = to_FIFOF_O (f_rd_data);
-endmodule: mkAXI4_M_Xactor
-
-// ----------------------------------------------------------------
-// M transactor
-// This version uses crgs and regs instead of FIFOFs.
-// This uses 1/2 the resources, but introduces scheduling dependencies.
-
-module mkAXI4_M_Xactor_2 (AXI4_M_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user));
-
- // Each crg_full, rg_data pair below represents a 1-element fifo.
-
- Array #(Reg #(Bool)) crg_wr_addr_full <- mkCReg (3, False);
- Reg #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) rg_wr_addr <- mkRegU;
-
- Array #(Reg #(Bool)) crg_wr_data_full <- mkCReg (3, False);
- Reg #(AXI4_Wr_Data #(wd_data, wd_user)) rg_wr_data <- mkRegU;
-
- Array #(Reg #(Bool)) crg_wr_resp_full <- mkCReg (3, False);
- Reg #(AXI4_Wr_Resp #(wd_id, wd_user)) rg_wr_resp <- mkRegU;
-
- Array #(Reg #(Bool)) crg_rd_addr_full <- mkCReg (3, False);
- Reg #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) rg_rd_addr <- mkRegU;
-
- Array #(Reg #(Bool)) crg_rd_data_full <- mkCReg (3, False);
- Reg #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) rg_rd_data <- mkRegU;
-
- // The following CReg port indexes specify the relative scheduling of:
- // {first,deq,notEmpty} {enq,notFull} clear
-
- // TODO: 'deq/enq/clear = 1/2/0' is unusual, but eliminates a
- // scheduling cycle in Piccolo's DCache. Normally should be 0/1/2.
-
- Integer port_deq = 1;
- Integer port_enq = 2;
- Integer port_clear = 0;
-
- // ----------------------------------------------------------------
- // INTERFACE
-
- method Action reset;
- crg_wr_addr_full [port_clear] <= False;
- crg_wr_data_full [port_clear] <= False;
- crg_wr_resp_full [port_clear] <= False;
- crg_rd_addr_full [port_clear] <= False;
- crg_rd_data_full [port_clear] <= False;
- endmethod
-
- // AXI side
- interface axi_side = interface AXI4_M_IFC;
- // Wr Addr channel
- method Bool m_awvalid = crg_wr_addr_full [port_deq];
- method Bit #(wd_id) m_awid = rg_wr_addr.awid;
- method Bit #(wd_addr) m_awaddr = rg_wr_addr.awaddr;
- method Bit #(8) m_awlen = rg_wr_addr.awlen;
- method AXI4_Size m_awsize = rg_wr_addr.awsize;
- method Bit #(2) m_awburst = rg_wr_addr.awburst;
- method Bit #(1) m_awlock = rg_wr_addr.awlock;
- method Bit #(4) m_awcache = rg_wr_addr.awcache;
- method Bit #(3) m_awprot = rg_wr_addr.awprot;
- method Bit #(4) m_awqos = rg_wr_addr.awqos;
- method Bit #(4) m_awregion = rg_wr_addr.awregion;
- method Bit #(wd_user) m_awuser = rg_wr_addr.awuser;
- method Action m_awready (Bool awready);
- if (crg_wr_addr_full [port_deq] && awready)
- crg_wr_addr_full [port_deq] <= False; // deq
- endmethod
-
- // Wr Data channel
- method Bool m_wvalid = crg_wr_data_full [port_deq];
- method Bit #(wd_data) m_wdata = rg_wr_data.wdata;
- method Bit #(TDiv #(wd_data, 8)) m_wstrb = rg_wr_data.wstrb;
- method Bool m_wlast = rg_wr_data.wlast;
- method Bit #(wd_user) m_wuser = rg_wr_data.wuser;
- method Action m_wready (Bool wready);
- if (crg_wr_data_full [port_deq] && wready)
- crg_wr_data_full [port_deq] <= False;
- endmethod
-
- // Wr Response channel
- method Action m_bvalid (Bool bvalid,
- Bit #(wd_id) bid,
- Bit #(2) bresp,
- Bit #(wd_user) buser);
- if (bvalid && (! (crg_wr_resp_full [port_enq]))) begin
- crg_wr_resp_full [port_enq] <= True;
- rg_wr_resp <= AXI4_Wr_Resp {bid: bid,
- bresp: bresp,
- buser: buser};
- end
- endmethod
-
- method Bool m_bready;
- return (! (crg_wr_resp_full [port_enq]));
- endmethod
-
- // Rd Addr channel
- method Bool m_arvalid = crg_rd_addr_full [port_deq];
- method Bit #(wd_id) m_arid = rg_rd_addr.arid;
- method Bit #(wd_addr) m_araddr = rg_rd_addr.araddr;
- method Bit #(8) m_arlen = rg_rd_addr.arlen;
- method AXI4_Size m_arsize = rg_rd_addr.arsize;
- method Bit #(2) m_arburst = rg_rd_addr.arburst;
- method Bit #(1) m_arlock = rg_rd_addr.arlock;
- method Bit #(4) m_arcache = rg_rd_addr.arcache;
- method Bit #(3) m_arprot = rg_rd_addr.arprot;
- method Bit #(4) m_arqos = rg_rd_addr.arqos;
- method Bit #(4) m_arregion = rg_rd_addr.arregion;
- method Bit #(wd_user) m_aruser = rg_rd_addr.aruser;
- method Action m_arready (Bool arready);
- if (crg_rd_addr_full [port_deq] && arready)
- crg_rd_addr_full [port_deq] <= False; // deq
- endmethod
-
- // Rd Data channel
- method Action m_rvalid (Bool rvalid,
- Bit #(wd_id) rid,
- Bit #(wd_data) rdata,
- Bit #(2) rresp,
- Bool rlast,
- Bit #(wd_user) ruser);
- if (rvalid && (! (crg_rd_data_full [port_enq])))
- crg_rd_data_full [port_enq] <= True;
- rg_rd_data <= (AXI4_Rd_Data {rid: rid,
- rdata: rdata,
- rresp: rresp,
- rlast: rlast,
- ruser: ruser});
- endmethod
-
- method Bool m_rready;
- return (! (crg_rd_data_full [port_enq]));
- endmethod
-
- endinterface;
-
- // FIFOF side
- interface i_wr_addr = fn_crg_and_rg_to_FIFOF_I (crg_wr_addr_full [port_enq], rg_wr_addr);
- interface i_wr_data = fn_crg_and_rg_to_FIFOF_I (crg_wr_data_full [port_enq], rg_wr_data);
- interface o_wr_resp = fn_crg_and_rg_to_FIFOF_O (crg_wr_resp_full [port_deq], rg_wr_resp);
-
- interface i_rd_addr = fn_crg_and_rg_to_FIFOF_I (crg_rd_addr_full [port_enq], rg_rd_addr);
- interface o_rd_data = fn_crg_and_rg_to_FIFOF_O (crg_rd_data_full [port_deq], rg_rd_data);
-endmodule: mkAXI4_M_Xactor_2
-
-// ================================================================
-// S transactor interface
-
-interface AXI4_S_Xactor_IFC #(numeric type wd_id,
- numeric type wd_addr,
- numeric type wd_data,
- numeric type wd_user);
- method Action reset;
-
- // AXI side
- interface AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user) axi_side;
-
- // FIFOF side
- interface FIFOF_O #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) o_wr_addr;
- interface FIFOF_O #(AXI4_Wr_Data #(wd_data, wd_user)) o_wr_data;
- interface FIFOF_I #(AXI4_Wr_Resp #(wd_id, wd_user)) i_wr_resp;
-
- interface FIFOF_O #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) o_rd_addr;
- interface FIFOF_I #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) i_rd_data;
-endinterface: AXI4_S_Xactor_IFC
-
-// ----------------------------------------------------------------
-// S transactor
-// This version uses FIFOFs for total decoupling.
-
-module mkAXI4_S_Xactor (AXI4_S_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user));
-
- Bool unguarded = True;
- Bool guarded = False;
-
- // These FIFOs are guarded on BSV side, unguarded on AXI side
- FIFOF #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) f_wr_addr <- mkGFIFOF (unguarded, guarded);
- FIFOF #(AXI4_Wr_Data #(wd_data, wd_user)) f_wr_data <- mkGFIFOF (unguarded, guarded);
- FIFOF #(AXI4_Wr_Resp #(wd_id, wd_user)) f_wr_resp <- mkGFIFOF (guarded, unguarded);
-
- FIFOF #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) f_rd_addr <- mkGFIFOF (unguarded, guarded);
- FIFOF #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) f_rd_data <- mkGFIFOF (guarded, unguarded);
-
- // ----------------------------------------------------------------
- // INTERFACE
-
- method Action reset;
- f_wr_addr.clear;
- f_wr_data.clear;
- f_wr_resp.clear;
- f_rd_addr.clear;
- f_rd_data.clear;
- endmethod
-
- // AXI side
- interface axi_side = interface AXI4_S_IFC;
- // Wr Addr channel
- method Action m_awvalid (Bool awvalid,
- Bit #(wd_id) awid,
- Bit #(wd_addr) awaddr,
- Bit #(8) awlen,
- AXI4_Size awsize,
- Bit #(2) awburst,
- Bit #(1) awlock,
- Bit #(4) awcache,
- Bit #(3) awprot,
- Bit #(4) awqos,
- Bit #(4) awregion,
- Bit #(wd_user) awuser);
- if (awvalid && f_wr_addr.notFull)
- f_wr_addr.enq (AXI4_Wr_Addr {awid: awid,
- awaddr: awaddr,
- awlen: awlen,
- awsize: awsize,
- awburst: awburst,
- awlock: awlock,
- awcache: awcache,
- awprot: awprot,
- awqos: awqos,
- awregion: awregion,
- awuser: awuser});
- endmethod
-
- method Bool m_awready;
- return f_wr_addr.notFull;
- endmethod
-
- // Wr Data channel
- method Action m_wvalid (Bool wvalid,
- Bit #(wd_data) wdata,
- Bit #(TDiv #(wd_data, 8)) wstrb,
- Bool wlast,
- Bit #(wd_user) wuser);
- if (wvalid && f_wr_data.notFull)
- f_wr_data.enq (AXI4_Wr_Data {wdata: wdata,
- wstrb: wstrb,
- wlast: wlast,
- wuser: wuser});
- endmethod
-
- method Bool m_wready;
- return f_wr_data.notFull;
- endmethod
-
- // Wr Response channel
- method Bool m_bvalid = f_wr_resp.notEmpty;
- method Bit #(wd_id) m_bid = f_wr_resp.first.bid;
- method Bit #(2) m_bresp = f_wr_resp.first.bresp;
- method Bit #(wd_user) m_buser = f_wr_resp.first.buser;
- method Action m_bready (Bool bready);
- if (bready && f_wr_resp.notEmpty)
- f_wr_resp.deq;
- endmethod
-
- // Rd Addr channel
- method Action m_arvalid (Bool arvalid,
- Bit #(wd_id) arid,
- Bit #(wd_addr) araddr,
- Bit #(8) arlen,
- AXI4_Size arsize,
- Bit #(2) arburst,
- Bit #(1) arlock,
- Bit #(4) arcache,
- Bit #(3) arprot,
- Bit #(4) arqos,
- Bit #(4) arregion,
- Bit #(wd_user) aruser);
- if (arvalid && f_rd_addr.notFull)
- f_rd_addr.enq (AXI4_Rd_Addr {arid: arid,
- araddr: araddr,
- arlen: arlen,
- arsize: arsize,
- arburst: arburst,
- arlock: arlock,
- arcache: arcache,
- arprot: arprot,
- arqos: arqos,
- arregion: arregion,
- aruser: aruser});
- endmethod
-
- method Bool m_arready;
- return f_rd_addr.notFull;
- endmethod
-
- // Rd Data channel
- method Bool m_rvalid = f_rd_data.notEmpty;
- method Bit #(wd_id) m_rid = f_rd_data.first.rid;
- method Bit #(wd_data) m_rdata = f_rd_data.first.rdata;
- method Bit #(2) m_rresp = f_rd_data.first.rresp;
- method Bool m_rlast = f_rd_data.first.rlast;
- method Bit #(wd_user) m_ruser = f_rd_data.first.ruser;
- method Action m_rready (Bool rready);
- if (rready && f_rd_data.notEmpty)
- f_rd_data.deq;
- endmethod
- endinterface;
-
- // FIFOF side
- interface o_wr_addr = to_FIFOF_O (f_wr_addr);
- interface o_wr_data = to_FIFOF_O (f_wr_data);
- interface i_wr_resp = to_FIFOF_I (f_wr_resp);
-
- interface o_rd_addr = to_FIFOF_O (f_rd_addr);
- interface i_rd_data = to_FIFOF_I (f_rd_data);
-endmodule: mkAXI4_S_Xactor
-
-// ----------------------------------------------------------------
-// S transactor
-// This version uses crgs and regs instead of FIFOFs.
-// This uses 1/2 the resources, but introduces scheduling dependencies.
-
-module mkAXI4_S_Xactor_2 (AXI4_S_Xactor_IFC #(wd_id, wd_addr, wd_data, wd_user));
-
- // Each crg_full, rg_data pair below represents a 1-element fifo.
-
- // These FIFOs are guarded on BSV side, unguarded on AXI side
- Array #(Reg #(Bool)) crg_wr_addr_full <- mkCReg (3, False);
- Reg #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)) rg_wr_addr <- mkRegU;
-
- Array #(Reg #(Bool)) crg_wr_data_full <- mkCReg (3, False);
- Reg #(AXI4_Wr_Data #(wd_data, wd_user)) rg_wr_data <- mkRegU;
-
- Array #(Reg #(Bool)) crg_wr_resp_full <- mkCReg (3, False);
- Reg #(AXI4_Wr_Resp #(wd_id, wd_user)) rg_wr_resp <- mkRegU;
-
- Array #(Reg #(Bool)) crg_rd_addr_full <- mkCReg (3, False);
- Reg #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)) rg_rd_addr <- mkRegU;
-
- Array #(Reg #(Bool)) crg_rd_data_full <- mkCReg (3, False);
- Reg #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) rg_rd_data <- mkRegU;
-
- // The following CReg port indexes specify the relative scheduling of:
- // {first,deq,notEmpty} {enq,notFull} clear
- Integer port_deq = 0;
- Integer port_enq = 1;
- Integer port_clear = 2;
-
- // ----------------------------------------------------------------
- // INTERFACE
-
- method Action reset;
- crg_wr_addr_full [port_clear] <= False;
- crg_wr_data_full [port_clear] <= False;
- crg_wr_resp_full [port_clear] <= False;
- crg_rd_addr_full [port_clear] <= False;
- crg_rd_data_full [port_clear] <= False;
- endmethod
-
- // AXI side
- interface axi_side = interface AXI4_S_IFC;
- // Wr Addr channel
- method Action m_awvalid (Bool awvalid,
- Bit #(wd_id) awid,
- Bit #(wd_addr) awaddr,
- Bit #(8) awlen,
- AXI4_Size awsize,
- Bit #(2) awburst,
- Bit #(1) awlock,
- Bit #(4) awcache,
- Bit #(3) awprot,
- Bit #(4) awqos,
- Bit #(4) awregion,
- Bit #(wd_user) awuser);
-
- if (awvalid && (! crg_wr_addr_full [port_enq])) begin
- crg_wr_addr_full [port_enq] <= True; // enq
- rg_wr_addr <= AXI4_Wr_Addr {awid: awid,
- awaddr: awaddr,
- awlen: awlen,
- awsize: awsize,
- awburst: awburst,
- awlock: awlock,
- awcache: awcache,
- awprot: awprot,
- awqos: awqos,
- awregion: awregion,
- awuser: awuser};
- end
- endmethod
-
- method Bool m_awready;
- return (! crg_wr_addr_full [port_enq]);
- endmethod
-
- // Wr Data channel
- method Action m_wvalid (Bool wvalid,
- Bit #(wd_data) wdata,
- Bit #(TDiv #(wd_data, 8)) wstrb,
- Bool wlast,
- Bit #(wd_user) wuser);
- if (wvalid && (! crg_wr_data_full [port_enq])) begin
- crg_wr_data_full [port_enq] <= True; // enq
- rg_wr_data <= AXI4_Wr_Data {wdata: wdata,
- wstrb: wstrb,
- wlast: wlast,
- wuser: wuser};
- end
- endmethod
-
- method Bool m_wready;
- return (! crg_wr_data_full [port_enq]);
- endmethod
-
- // Wr Response channel
- method Bool m_bvalid = crg_wr_resp_full [port_deq];
- method Bit #(wd_id) m_bid = rg_wr_resp.bid;
- method Bit #(2) m_bresp = rg_wr_resp.bresp;
- method Bit #(wd_user) m_buser = rg_wr_resp.buser;
- method Action m_bready (Bool bready);
- if (bready && crg_wr_resp_full [port_deq])
- crg_wr_resp_full [port_deq] <= False; // deq
- endmethod
-
- // Rd Addr channel
- method Action m_arvalid (Bool arvalid,
- Bit #(wd_id) arid,
- Bit #(wd_addr) araddr,
- Bit #(8) arlen,
- AXI4_Size arsize,
- Bit #(2) arburst,
- Bit #(1) arlock,
- Bit #(4) arcache,
- Bit #(3) arprot,
- Bit #(4) arqos,
- Bit #(4) arregion,
- Bit #(wd_user) aruser);
- if (arvalid && (! crg_rd_addr_full [port_enq])) begin
- crg_rd_addr_full [port_enq] <= True; // enq
- rg_rd_addr <= AXI4_Rd_Addr {arid: arid,
- araddr: araddr,
- arlen: arlen,
- arsize: arsize,
- arburst: arburst,
- arlock: arlock,
- arcache: arcache,
- arprot: arprot,
- arqos: arqos,
- arregion: arregion,
- aruser: aruser};
- end
- endmethod
-
- method Bool m_arready;
- return (! crg_rd_addr_full [port_enq]);
- endmethod
-
- // Rd Data channel
- method Bool m_rvalid = crg_rd_data_full [port_deq];
- method Bit #(wd_id) m_rid = rg_rd_data.rid;
- method Bit #(wd_data) m_rdata = rg_rd_data.rdata;
- method Bit #(2) m_rresp = rg_rd_data.rresp;
- method Bool m_rlast = rg_rd_data.rlast;
- method Bit #(wd_user) m_ruser = rg_rd_data.ruser;
- method Action m_rready (Bool rready);
- if (rready && crg_rd_data_full [port_deq])
- crg_rd_data_full [port_deq] <= False; // deq
- endmethod
- endinterface;
-
- // FIFOF side
- interface o_wr_addr = fn_crg_and_rg_to_FIFOF_O (crg_wr_addr_full [port_deq], rg_wr_addr);
- interface o_wr_data = fn_crg_and_rg_to_FIFOF_O (crg_wr_data_full [port_deq], rg_wr_data);
- interface i_wr_resp = fn_crg_and_rg_to_FIFOF_I (crg_wr_resp_full [port_enq], rg_wr_resp);
-
- interface o_rd_addr = fn_crg_and_rg_to_FIFOF_O (crg_rd_addr_full [port_deq], rg_rd_addr);
- interface i_rd_data = fn_crg_and_rg_to_FIFOF_I (crg_rd_data_full [port_enq], rg_rd_data);
-endmodule: mkAXI4_S_Xactor_2
-
-// ================================================================
+// ****************************************************************
endpackage
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_Widener.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_Widener.bsv
index bd51bbe..e189ed4 100644
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_Widener.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4/AXI4_Widener.bsv
@@ -1,20 +1,28 @@
-// Copyright (c) 2020-2021 Bluespec, Inc. All Rights Reserved
-//
+// Copyright (c) 2020-2023 Bluespec, Inc. All Rights Reserved
+// Copyright (c) 2024 Rishiyur S. Nikhil.
+
// SPDX-License-Identifier: BSD-3-Clause
package AXI4_Widener;
-// ================================================================
-// This package defines an AXI4-S-to-AXI4-M 'widener' module.
+// ****************************************************************
+// This package defines an AXI4-S-to-AXI4-M 'data widener' module.
+// The module arguments are an M interface from upstream and an S
+// interface to downstream.
// The interfaces facing S and M differ in data-bus width
// The S-side data bus is wider than the M-side by some multiple.
-// The primary function is data-bus re-alignment due to widening.
+// The primary function here is data-bus re-alignment due to widening.
// NOTE: Does not support bursts yet (which would need reshaping the
-// data beats, strobes, burst lengh, etc.)
+// data beats, strobes, burst length, etc.)
+// Use AXI4_Deburster in front, if needed.
+
+// ****************************************************************
+
+export mkAXI4_Widener;
-// ================================================================
+// ****************************************************************
// Bluespec library imports
import Vector :: *;
@@ -23,60 +31,43 @@ import SpecialFIFOs :: *;
import ConfigReg :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Cur_Cycle :: *;
import GetPut_Aux :: *;
import Semi_FIFOF :: *;
-// ================================================================
+// ----------------
// Project imports
-import AXI4_Types :: *;
+import AXI4_Types :: *;
-// ================================================================
-// The interface for the widener module
+// ****************************************************************
+// Simulation verbosity during simulation on stdout for this package (edit as desired)
+// 0: quiet
+// 1: display rules
-interface AXI4_Widener_IFC #(numeric type wd_id_t,
- numeric type wd_addr_t,
- numeric type m_wd_data_t, // narrower
- numeric type s_wd_data_t, // wider
- numeric type wd_user_t);
- // From M
- interface AXI4_S_IFC #(wd_id_t, wd_addr_t, m_wd_data_t, wd_user_t) from_M;
- // To S
- interface AXI4_M_IFC #(wd_id_t, wd_addr_t, s_wd_data_t, wd_user_t) to_S;
-endinterface
+Integer verbosity = 0;
-// ================================================================
+// ****************************************************************
// The Widener module
-module mkAXI4_Widener (AXI4_Widener_IFC #(wd_id_t, wd_addr_t, m_wd_data_t, s_wd_data_t, wd_user_t))
+module mkAXI4_Widener #(AXI4_M_IFC #(wd_id_t, wd_addr_t, m_wd_data_t, wd_user_t) ifc_M,
+ AXI4_S_IFC #(wd_id_t, wd_addr_t, s_wd_data_t, wd_user_t) ifc_S)
+ (Empty)
provisos (Mul #(8, m_wd_bytes_t, m_wd_data_t),
Div #(m_wd_data_t, 8, m_wd_bytes_t),
Mul #(8, s_wd_bytes_t, s_wd_data_t),
Div #(s_wd_data_t, 8, s_wd_bytes_t),
- Add #(m_wd_data_t, __a, s_wd_data_t), // m_wd_data <= s_wd_data ("widening")
- Add #(m_wd_bytes_t, __b, s_wd_bytes_t), // m_wd_bytes <= s_wd_bytes ("widening")
+ Add #(m_wd_data_t, __a, s_wd_data_t), // m_wd_data <= s_wd_data ("widening")
+ Add #(m_wd_bytes_t, __b, s_wd_bytes_t), // m_wd_bytes <= s_wd_bytes ("widening")
Log #(m_wd_bytes_t, log2_m_wd_bytes_t),
Log #(s_wd_bytes_t, log2_s_wd_bytes_t),
NumAlias #(word_index_t, TSub #(s_wd_bytes_t, m_wd_bytes_t)));
- // 0 quiet; 1: display rules
- Integer verbosity = 0;
-
Integer log2_m_wd_bytes = valueOf (log2_m_wd_bytes_t);
Integer log2_s_wd_bytes = valueOf (log2_s_wd_bytes_t);
- // ----------------
- // Transactor facing M
- AXI4_S_Xactor_IFC #(wd_id_t, wd_addr_t, m_wd_data_t, wd_user_t)
- xactor_from_M <- mkAXI4_S_Xactor;
-
- // Transactor facing S
- AXI4_M_Xactor_IFC #(wd_id_t, wd_addr_t, s_wd_data_t, wd_user_t)
- xactor_to_S <- mkAXI4_M_Xactor;
-
// size covers latency to mem read response
FIFOF #(Bit #(wd_addr_t)) f_araddrs <- mkSizedFIFOF (8);
@@ -111,96 +102,95 @@ module mkAXI4_Widener (AXI4_Widener_IFC #(wd_id_t, wd_addr_t, m_wd_data_t, s_wd_
endfunction
// ----------------
- // Wr requests (AW and W channels)
+ // AW and W channels (write requests)
- rule rl_wr_xaction_M_to_S;
- AXI4_Wr_Addr #(wd_id_t, wd_addr_t, wd_user_t) m_wra <- pop_o (xactor_from_M.o_wr_addr);
- AXI4_Wr_Data #(m_wd_data_t, wd_user_t) m_wrd <- pop_o (xactor_from_M.o_wr_data);
+ rule rl_AW_W;
+ AXI4_AW #(wd_id_t, wd_addr_t, wd_user_t) m_aw <- pop_o (ifc_M.o_AW);
+ AXI4_W #(m_wd_data_t, wd_user_t) m_w <- pop_o (ifc_M.o_W);
- let s_wra = m_wra;
+ let s_aw = m_aw;
- match { .s_wdata, .s_wstrb} = fv_align_to_wider (m_wra.awaddr, m_wrd.wdata, m_wrd.wstrb);
- AXI4_Wr_Data #(s_wd_data_t, wd_user_t) s_wrd = AXI4_Wr_Data {wdata: s_wdata,
- wstrb: s_wstrb,
- wlast: m_wrd.wlast,
- wuser: m_wrd.wuser};
+ match { .s_wdata, .s_wstrb} = fv_align_to_wider (m_aw.awaddr, m_w.wdata, m_w.wstrb);
+ AXI4_W #(s_wd_data_t, wd_user_t) s_w = AXI4_W {wdata: s_wdata,
+ wstrb: s_wstrb,
+ wlast: m_w.wlast,
+ wuser: m_w.wuser};
// Send to S
- xactor_to_S.i_wr_addr.enq (s_wra);
- xactor_to_S.i_wr_data.enq (s_wrd);
+ ifc_S.i_AW.enq (s_aw);
+ ifc_S.i_W.enq (s_w);
// Debugging
if (verbosity > 0) begin
- $display ("%0d: %m:AXI4_Widener.rl_wr_xaction_M_to_S: m -> s", cur_cycle);
- $display (" m_wra : ", fshow (m_wra));
- $display (" m_wrd: ", fshow (m_wrd));
- $display (" s_wrd: ", fshow (s_wrd));
+ $display ("%0d: AXI4_Widener.rl_AW_W: m -> s", cur_cycle);
+ $display (" m_aw : ", fshow (m_aw));
+ $display (" m_w: ", fshow (m_w));
+ $display (" s_w: ", fshow (s_w));
end
- endrule: rl_wr_xaction_M_to_S
+ endrule
// ----------------
- // Wr responses (B channel): just pass through as-is.
+ // B channel (write responses): just pass through as-is.
- rule rl_wr_resp_S_to_M;
- AXI4_Wr_Resp #(wd_id_t, wd_user_t) s_wrr <- pop_o (xactor_to_S.o_wr_resp);
- let m_wrr = s_wrr;
- xactor_from_M.i_wr_resp.enq (m_wrr);
+ rule rl_B;
+ AXI4_B #(wd_id_t, wd_user_t) s_b <- pop_o (ifc_S.o_B);
+ let m_b = s_b;
+ ifc_M.i_B.enq (m_b);
if (verbosity > 1) begin
- $display ("%0d: %m::AXI4_Widener.rl_wr_resp_S_to_M: m <- s", cur_cycle);
- $display (" s_wrr: ", fshow (s_wrr));
- $display (" m_wrr: ", fshow (m_wrr));
+ $display ("%0d: AXI4_Widener.rl_B: m <- s", cur_cycle);
+ $display (" s_b: ", fshow (s_b));
+ $display (" m_b: ", fshow (m_b));
end
endrule
// ----------------
- // Rd requests (AR channel); just pass it through, as-is
+ // AR channel (read requests); just pass it through, as-is
// but remember the addr in order to align the data response.
- rule rl_rd_xaction_M_to_S;
- AXI4_Rd_Addr #(wd_id_t, wd_addr_t, wd_user_t) m_rda <- pop_o (xactor_from_M.o_rd_addr);
- let s_rda = m_rda;
- xactor_to_S.i_rd_addr.enq (s_rda);
+ rule rl_AR;
+ AXI4_AR #(wd_id_t, wd_addr_t, wd_user_t) m_ar <- pop_o (ifc_M.o_AR);
+ let s_ar = m_ar;
+ ifc_S.i_AR.enq (s_ar);
- f_araddrs.enq (m_rda.araddr);
+ f_araddrs.enq (m_ar.araddr);
// Debugging
if (verbosity > 0) begin
- $display ("%0d: %m::AXI4_Widener.rl_rd_xaction_M_to_S: m -> s", cur_cycle);
- $display (" m_rda: ", fshow (m_rda));
- $display (" s_rda: ", fshow (s_rda));
+ $display ("%0d: AXI4_Widener.rl_AR: m -> s", cur_cycle);
+ $display (" m_ar: ", fshow (m_ar));
+ $display (" s_ar: ", fshow (s_ar));
end
- endrule: rl_rd_xaction_M_to_S
+ endrule
// ----------------
- // Rd responses
+ // R channel (read responses)
- rule rl_rd_resp_S_to_M;
- AXI4_Rd_Data #(wd_id_t, s_wd_data_t, wd_user_t) s_rdd <- pop_o (xactor_to_S.o_rd_data);
+ rule rl_R;
+ AXI4_R #(wd_id_t, s_wd_data_t, wd_user_t) s_r <- pop_o (ifc_S.o_R);
let araddr <- pop (f_araddrs);
- let m_rdata = fv_align_to_narrower (araddr, s_rdd.rdata);
- AXI4_Rd_Data #(wd_id_t, m_wd_data_t, wd_user_t) m_rdd = AXI4_Rd_Data {rid: s_rdd.rid,
- rdata: m_rdata,
- rresp: s_rdd.rresp,
- rlast: s_rdd.rlast,
- ruser: s_rdd.ruser};
- xactor_from_M.i_rd_data.enq (m_rdd);
+ let m_rdata = fv_align_to_narrower (araddr, s_r.rdata);
+ AXI4_R #(wd_id_t, m_wd_data_t, wd_user_t) m_r = AXI4_R {rid: s_r.rid,
+ rdata: m_rdata,
+ rresp: s_r.rresp,
+ rlast: s_r.rlast,
+ ruser: s_r.ruser};
+ ifc_M.i_R.enq (m_r);
// Debugging
if (verbosity > 0) begin
- $display ("%0d: %m::AXI4_Widener.rl_rd_resp_S_to_M: m <- s", cur_cycle);
- $display (" s_rdd: ", fshow (s_rdd));
- $display (" m_rdd: ", fshow (m_rdd));
+ $display ("%0d: AXI4_Widener.rl_R: m <- s", cur_cycle);
+ $display (" s_r: ", fshow (s_r));
+ $display (" m_r: ", fshow (m_r));
end
- endrule: rl_rd_resp_S_to_M
+ endrule
- // ----------------------------------------------------------------
+ // ================================================================
// INTERFACE
- interface from_M = xactor_from_M.axi_side;
- interface to_S = xactor_to_S.axi_side;
+ // Empty
endmodule
-// ================================================================
+// ****************************************************************
endpackage: AXI4_Widener
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_Xactors.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_Xactors.bsv
deleted file mode 100644
index 6389b75..0000000
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_Xactors.bsv
+++ /dev/null
@@ -1,336 +0,0 @@
-// Copyright (c) 2022 University of Cambridge Computer Laboratory.
-// Copyright (c) 2022 Bluespec, Inc.
-// Authors: U.Cambridge CL -> Joe Stoy -> Rishiyur Nikhil
-//
-// SPDX-License-Identifier: BSD-3-Clause
-
-package AXI4_Xactors;
-
-// ================================================================
-// These are M and S transactors for AXI4, i.e., converters between
-// BSV FIFO-like interfaces (flow-controlled)
-// ARM AXI4 signals (ready/valid protocol)
-
-// ================================================================
-// BSV library imports
-
-// None
-
-// ----------------
-// BSV additional libs
-
-import Semi_FIFOF :: *;
-
-// ----------------
-// Local imports
-
-import AXI4_Types :: *;
-
-// ================================================================
-// Typeclass to convert
-// normal FIFO_I and FIFO_O interfaces
-// to unguarded FIFO_I and FIFO_O interfaces.
-
-typeclass ToUnguarded #(type a);
- module mkUnguarded #(a x)(a);
-endtypeclass
-
-instance ToUnguarded #(FIFOF_I #(a))
- provisos (Bits#(a, __));
- module mkUnguarded #(FIFOF_I #(a) ifc)(FIFOF_I #(a));
- let enqWire <- mkRWire;
- rule warnDoEnq (isValid(enqWire.wget) && !ifc.notFull);
- $display("WARNING: enqing into an already full FIFOF_I");
- $finish(0);
- endrule
- rule doEnq (isValid(enqWire.wget));
- ifc.enq(enqWire.wget.Valid);
- endrule
- return interface FIFOF_I;
- method notFull = ifc.notFull;
- method enq = enqWire.wset;
- endinterface;
- endmodule
-endinstance
-
-instance ToUnguarded #(FIFOF_O #(a))
- provisos (Bits#(a, _));
- module mkUnguarded#(FIFOF_O #(a) ifc)(FIFOF_O#(a));
- let firstWire <- mkDWire(unpack(0));
- let deqWire <- mkPulseWire;
- rule setFirst; firstWire <= ifc.first; endrule
- rule warnDoDeq (deqWire && !ifc.notEmpty);
- $display("WARNING: deqing from empty FIFOF_O");
- $finish(0);
- endrule
- rule doDeq (deqWire && ifc.notEmpty);
- ifc.deq;
- endrule
- return interface FIFOF_O;
- method notEmpty = ifc.notEmpty;
- method first = firstWire;
- method deq = deqWire.send;
- endinterface;
- endmodule
-endinstance
-
-// ================================================================
-// M transactor
-// Arguments aw, w, b, ar and r are the standard five AXI4 channels, as normal FIFOFs.
-// Returns ARM-signalling interface.
-
-module mkAXI4_Xactor_M_3
- #(aw_t aw, w_t w, b_t b, ar_t ar, r_t r)
- (AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user))
-
- provisos (To_FIFOF_IO #(aw_t, AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)),
- To_FIFOF_IO #(w_t, AXI4_Wr_Data #(wd_data, wd_user)),
- To_FIFOF_IO #(b_t, AXI4_Wr_Resp #(wd_id, wd_user)),
- To_FIFOF_IO #(ar_t, AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)),
- To_FIFOF_IO #(r_t, AXI4_Rd_Data #(wd_id, wd_data, wd_user)));
-
- // For each argument FIFOF, unguard the ARM-signalling side.
-
- FIFOF_O #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user))
- f_wr_addr <- mkUnguarded (to_FIFOF_O (aw));
-
- FIFOF_O #(AXI4_Wr_Data #(wd_data, wd_user))
- f_wr_data <- mkUnguarded (to_FIFOF_O (w));
-
- FIFOF_I #(AXI4_Wr_Resp #(wd_id, wd_user))
- f_wr_resp <- mkUnguarded (to_FIFOF_I (b));
-
- FIFOF_O #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user))
- f_rd_addr <- mkUnguarded (to_FIFOF_O (ar));
-
- FIFOF_I #(AXI4_Rd_Data #(wd_id, wd_data, wd_user))
- f_rd_data <- mkUnguarded (to_FIFOF_I (r));
-
- // ----------------------------------------------------------------
- // INTERFACE (ARM signals)
-
- return interface AXI4_M_IFC;
- // Wr Addr channel
- method Bool m_awvalid = f_wr_addr.notEmpty;
- method Bit #(wd_id) m_awid = f_wr_addr.first.awid;
- method Bit #(wd_addr) m_awaddr = f_wr_addr.first.awaddr;
- method Bit #(8) m_awlen = f_wr_addr.first.awlen;
- method AXI4_Size m_awsize = f_wr_addr.first.awsize;
- method Bit #(2) m_awburst = f_wr_addr.first.awburst;
- method Bit #(1) m_awlock = f_wr_addr.first.awlock;
- method Bit #(4) m_awcache = f_wr_addr.first.awcache;
- method Bit #(3) m_awprot = f_wr_addr.first.awprot;
- method Bit #(4) m_awqos = f_wr_addr.first.awqos;
- method Bit #(4) m_awregion = f_wr_addr.first.awregion;
- method Bit #(wd_user) m_awuser = f_wr_addr.first.awuser;
- method Action m_awready (Bool awready);
- if (f_wr_addr.notEmpty && awready) f_wr_addr.deq;
- endmethod
-
- // Wr Data channel
- method Bool m_wvalid = f_wr_data.notEmpty;
- method Bit #(wd_data) m_wdata = f_wr_data.first.wdata;
- method Bit #(TDiv #(wd_data, 8)) m_wstrb = f_wr_data.first.wstrb;
- method Bool m_wlast = f_wr_data.first.wlast;
- method Bit #(wd_user) m_wuser = f_wr_data.first.wuser;
- method Action m_wready (Bool wready);
- if (f_wr_data.notEmpty && wready) f_wr_data.deq;
- endmethod
-
- // Wr Response channel
- method Action m_bvalid (Bool bvalid,
- Bit #(wd_id) bid,
- Bit #(2) bresp,
- Bit #(wd_user) buser);
- if (bvalid && f_wr_resp.notFull)
- f_wr_resp.enq (AXI4_Wr_Resp {bid: bid,
- bresp: bresp,
- buser: buser});
- endmethod
-
- method Bool m_bready;
- return f_wr_resp.notFull;
- endmethod
-
- // Rd Addr channel
- method Bool m_arvalid = f_rd_addr.notEmpty;
- method Bit #(wd_id) m_arid = f_rd_addr.first.arid;
- method Bit #(wd_addr) m_araddr = f_rd_addr.first.araddr;
- method Bit #(8) m_arlen = f_rd_addr.first.arlen;
- method AXI4_Size m_arsize = f_rd_addr.first.arsize;
- method Bit #(2) m_arburst = f_rd_addr.first.arburst;
- method Bit #(1) m_arlock = f_rd_addr.first.arlock;
- method Bit #(4) m_arcache = f_rd_addr.first.arcache;
- method Bit #(3) m_arprot = f_rd_addr.first.arprot;
- method Bit #(4) m_arqos = f_rd_addr.first.arqos;
- method Bit #(4) m_arregion = f_rd_addr.first.arregion;
- method Bit #(wd_user) m_aruser = f_rd_addr.first.aruser;
-
- method Action m_arready (Bool arready);
- if (f_rd_addr.notEmpty && arready) f_rd_addr.deq;
- endmethod
-
- // Rd Data channel
- method Action m_rvalid (Bool rvalid, // in
- Bit #(wd_id) rid, // in
- Bit #(wd_data) rdata, // in
- Bit #(2) rresp, // in
- Bool rlast, // in
- Bit #(wd_user) ruser); // in
- if (rvalid && f_rd_data.notFull)
- f_rd_data.enq (AXI4_Rd_Data {rid: rid,
- rdata: rdata,
- rresp: rresp,
- rlast: rlast,
- ruser: ruser});
- endmethod
-
- method Bool m_rready;
- return f_rd_data.notFull;
- endmethod
-
- endinterface;
-endmodule: mkAXI4_Xactor_M_3
-
-// ================================================================
-// S transactor
-// Arguments aw, w, b, ar and r are the standard five AXI4 channels, as normal FIFOFs.
-// Returns ARM-signalling interface.
-
-module mkAXI4_Xactor_S_3
- #(aw_t aw, w_t w, b_t b, ar_t ar, r_t r)
- (AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user))
-
- provisos (To_FIFOF_IO #(aw_t, AXI4_Wr_Addr #(wd_id, wd_addr, wd_user)),
- To_FIFOF_IO #(w_t, AXI4_Wr_Data #(wd_data, wd_user)),
- To_FIFOF_IO #(b_t, AXI4_Wr_Resp #(wd_id, wd_user)),
- To_FIFOF_IO #(ar_t, AXI4_Rd_Addr #(wd_id, wd_addr, wd_user)),
- To_FIFOF_IO #(r_t, AXI4_Rd_Data #(wd_id, wd_data, wd_user)));
-
- // For each argument FIFOF, unguard the ARM-signalling side.
-
- FIFOF_I #(AXI4_Wr_Addr #(wd_id, wd_addr, wd_user))
- f_wr_addr <- mkUnguarded (to_FIFOF_I (aw));
-
- FIFOF_I #(AXI4_Wr_Data #(wd_data, wd_user))
- f_wr_data <- mkUnguarded (to_FIFOF_I (w));
-
- FIFOF_O #(AXI4_Wr_Resp #(wd_id, wd_user))
- f_wr_resp <- mkUnguarded (to_FIFOF_O (b));
-
- FIFOF_I #(AXI4_Rd_Addr #(wd_id, wd_addr, wd_user))
- f_rd_addr <- mkUnguarded (to_FIFOF_I (ar));
-
- FIFOF_O #(AXI4_Rd_Data #(wd_id, wd_data, wd_user))
- f_rd_data <- mkUnguarded (to_FIFOF_O (r));
-
- // ----------------------------------------------------------------
- // INTERFACE (ARM signals)
-
- return interface AXI4_S_IFC;
- // Wr Addr channel
- method Action m_awvalid (Bool awvalid,
- Bit #(wd_id) awid,
- Bit #(wd_addr) awaddr,
- Bit #(8) awlen,
- AXI4_Size awsize,
- Bit #(2) awburst,
- Bit #(1) awlock,
- Bit #(4) awcache,
- Bit #(3) awprot,
- Bit #(4) awqos,
- Bit #(4) awregion,
- Bit #(wd_user) awuser);
- if (awvalid && f_wr_addr.notFull)
- f_wr_addr.enq (AXI4_Wr_Addr {awid: awid,
- awaddr: awaddr,
- awlen: awlen,
- awsize: awsize,
- awburst: awburst,
- awlock: awlock,
- awcache: awcache,
- awprot: awprot,
- awqos: awqos,
- awregion: awregion,
- awuser: awuser});
- endmethod
-
- method Bool m_awready;
- return f_wr_addr.notFull;
- endmethod
-
- // Wr Data channel
- method Action m_wvalid (Bool wvalid,
- Bit #(wd_data) wdata,
- Bit #(TDiv #(wd_data, 8)) wstrb,
- Bool wlast,
- Bit #(wd_user) wuser);
- if (wvalid && f_wr_data.notFull)
- f_wr_data.enq (AXI4_Wr_Data {wdata: wdata,
- wstrb: wstrb,
- wlast: wlast,
- wuser: wuser});
- endmethod
-
- method Bool m_wready;
- return f_wr_data.notFull;
- endmethod
-
- // Wr Response channel
- method Bool m_bvalid = f_wr_resp.notEmpty;
- method Bit #(wd_id) m_bid = f_wr_resp.first.bid;
- method Bit #(2) m_bresp = f_wr_resp.first.bresp;
- method Bit #(wd_user) m_buser = f_wr_resp.first.buser;
- method Action m_bready (Bool bready);
- if (bready && f_wr_resp.notEmpty)
- f_wr_resp.deq;
- endmethod
-
- // Rd Addr channel
- method Action m_arvalid (Bool arvalid,
- Bit #(wd_id) arid,
- Bit #(wd_addr) araddr,
- Bit #(8) arlen,
- AXI4_Size arsize,
- Bit #(2) arburst,
- Bit #(1) arlock,
- Bit #(4) arcache,
- Bit #(3) arprot,
- Bit #(4) arqos,
- Bit #(4) arregion,
- Bit #(wd_user) aruser);
- if (arvalid && f_rd_addr.notFull)
- f_rd_addr.enq (AXI4_Rd_Addr {arid: arid,
- araddr: araddr,
- arlen: arlen,
- arsize: arsize,
- arburst: arburst,
- arlock: arlock,
- arcache: arcache,
- arprot: arprot,
- arqos: arqos,
- arregion: arregion,
- aruser: aruser});
- endmethod
-
- method Bool m_arready;
- return f_rd_addr.notFull;
- endmethod
-
- // Rd Data channel
- method Bool m_rvalid = f_rd_data.notEmpty;
- method Bit #(wd_id) m_rid = f_rd_data.first.rid;
- method Bit #(wd_data) m_rdata = f_rd_data.first.rdata;
- method Bit #(2) m_rresp = f_rd_data.first.rresp;
- method Bool m_rlast = f_rd_data.first.rlast;
- method Bit #(wd_user) m_ruser = f_rd_data.first.ruser;
- method Action m_rready (Bool rready);
- if (rready && f_rd_data.notEmpty)
- f_rd_data.deq;
- endmethod
- endinterface;
-endmodule: mkAXI4_Xactor_S_3
-
-// ================================================================
-
-endpackage
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_to_LD.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_to_LD.bsv
index 365dfa6..c47817d 100644
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_to_LD.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4/AXI4_to_LD.bsv
@@ -1,6 +1,6 @@
-// Copyright (c) 2021 Rishiyur S. Nikhil and Bluespec, Inc. All Rights Reserved
+// Copyright (c) 2021-2024 Rishiyur S. Nikhil and Bluespec, Inc. All Rights Reserved
// Author: Rishiyur S. Nikhil
-//
+
// SPDX-License-Identifier: BSD-3-Clause
package AXI4_to_LD;
@@ -22,7 +22,7 @@ import Vector :: *;
import FIFOF :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Cur_Cycle :: *;
import Semi_FIFOF :: *;
@@ -71,8 +71,8 @@ Integer verbosity = 0;
// Loads: Module
module mkAXI4_to_LD
- #(FIFOF_O #(AXI4_Rd_Addr #(wd_id_t, wd_addr_t, wd_user_t)) o_rd_addr,
- FIFOF_I #(AXI4_Rd_Data #(wd_id_t, wd_axi_data_t, wd_user_t)) i_rd_data)
+ #(FIFOF_O #(AXI4_AR #(wd_id_t, wd_addr_t, wd_user_t)) o_rd_addr,
+ FIFOF_I #(AXI4_R #(wd_id_t, wd_axi_data_t, wd_user_t)) i_rd_data)
(AXI4_to_LD_IFC #(wd_addr_t, wd_ldst_data_t))
provisos (Add #(a__, 8, wd_addr_t),
@@ -157,10 +157,11 @@ module mkAXI4_to_LD
Bit #(wd_addr_t) addr_axi_bus_lo = fn_addr_to_NAPOT (araddr,
fromInteger (wdB_axi_data_I));
// Bytelane of araddr on AXI data
- Bit #(8) addr_bytelane = fn_addr_to_axi_data_bytelane (araddr, wdB_axi_data_I);
+ Bit #(8) addr_bytelane = fn_addr_to_axi_data_bytelane (araddr, wdB_axi_data_I);
// ARSIZE specifies a NAPOT window around araddr, ...
- Bit #(8) wdB_szwindow_B = fv_AXI4_Size_to_num_bytes (rd_addr_S.arsize);
+ Bit #(8) wdB_szwindow_B = fv_AXI4_Size_to_num_bytes (rd_addr_S.arsize);
+
// Address of NAPOT ARSIZE window containing araddr
Bit #(wd_addr_t) addr_szwindow_lo = fn_addr_to_NAPOT (araddr, wdB_szwindow_B);
@@ -300,7 +301,7 @@ module mkAXI4_to_LD
rule rl_start_xaction (rg_state == STATE_IDLE);
if (verbosity > 0) begin
- $display ("%0d: %m.AXI4_to_LD:rl_start_xaction ================", cur_cycle);
+ $display ("%0d: AXI4_to_LD:rl_start_xaction ================", cur_cycle);
fa_show_axi_req_values();
end
@@ -309,7 +310,7 @@ module mkAXI4_to_LD
Bool illegal_req = False;
if (wdB_szwindow_B > fromInteger (wdB_axi_data_I)) begin
if (verbosity == 0)
- $display ("%0d: %m.AXI4_to_LD:rl_start_xaction ================", cur_cycle);
+ $display ("%0d: AXI4_to_LD:rl_start_xaction ================", cur_cycle);
$display (" ERROR: illegal AXI4 request");
$display (" awsize 0x%0h bytes > axi data bus width 0x%0h bytes",
wdB_szwindow_B, wdB_axi_data_I);
@@ -318,7 +319,7 @@ module mkAXI4_to_LD
if (rd_addr_S.arlen != 0) begin
if (verbosity == 0)
- $display ("%0d: %m.AXI4_to_LD:rl_start_xaction ================", cur_cycle);
+ $display ("%0d: AXI4_to_LD:rl_start_xaction ================", cur_cycle);
$display (" ERROR: illegal AXI4 request");
$display (" arlen 0x%0h; only arlen 0 (1-beat bursts) supported",
rd_addr_S.arlen);
@@ -353,7 +354,7 @@ module mkAXI4_to_LD
rule rl_next_slice (rg_state == STATE_SLICE);
if (verbosity > 0)
- $display ("%0d: %m.AXI4_to_LD:rl_next_slice", cur_cycle);
+ $display ("%0d: AXI4_to_LD:rl_next_slice", cur_cycle);
Bit #(8) bytelane_slice_lo = rg_bytelane_slice_lo;
Bit #(8) bytelane_slice_hi = rg_bytelane_slice_lo + fromInteger (wdB_ldst_data_I - 1);
@@ -371,7 +372,7 @@ module mkAXI4_to_LD
rule rl_partial (rg_state == STATE_PARTIAL);
if (verbosity > 0) begin
- $display ("%0d: %m.AXI4_to_LD:rl_partial", cur_cycle);
+ $display ("%0d: AXI4_to_LD:rl_partial", cur_cycle);
$display (" rg_bytelane_hi..lo [%0h..%0h] rg_bytelane_slice_lo %0h",
rg_bytelane_hi, rg_bytelane_lo, rg_bytelane_slice_lo);
end
@@ -400,7 +401,7 @@ module mkAXI4_to_LD
rule rl_finish_req (rg_state == STATE_FINISH_REQ);
if (verbosity > 0)
- $display ("%0d: %m.AXI4_to_LD:rl_finish_ld_req", cur_cycle);
+ $display ("%0d: AXI4_to_LD:rl_finish_ld_req", cur_cycle);
f_ld_rsp_info.enq (tuple2 (RSP_DONE, ?)); // 'done' sentinel
f_axi_rsp_info.enq (tuple3 (False, rd_addr_S.arid, rd_addr_S.aruser));
@@ -433,7 +434,7 @@ module mkAXI4_to_LD
rg_v_slice <= v_slice;
if (verbosity > 0) begin
- $display ("%0d: %m.AXI4_to_LD:rl_handle_ld_rsp: err = %0h data %0h", cur_cycle,
+ $display ("%0d: AXI4_to_LD:rl_handle_ld_rsp: err = %0h data %0h", cur_cycle,
err, ld_data);
$display (" ShiftInAtN slice %016h; new v_slice", slice);
fa_show_v_slices (v_slice);
@@ -450,7 +451,7 @@ module mkAXI4_to_LD
rg_remaining_slices <= rg_remaining_slices - 1;
if (verbosity > 0) begin
- $display ("%0d: %m.AXI4_to_LD:rl_handle_ld_slice_ignore: skipping slice", cur_cycle);
+ $display ("%0d: AXI4_to_LD:rl_handle_ld_slice_ignore: skipping slice", cur_cycle);
$display (" new v_slice");
fa_show_v_slices (v_slice);
end
@@ -464,7 +465,7 @@ module mkAXI4_to_LD
rg_remaining_slices <= rg_remaining_slices - 1;
if (verbosity > 0) begin
- $display ("%0d: %m.AXI4_to_LD:rl_send_axi_response; shift only; new v_slice", cur_cycle);
+ $display ("%0d: AXI4_to_LD:rl_send_axi_response; shift only; new v_slice", cur_cycle);
fa_show_v_slices (v_slice);
end
endrule
@@ -477,21 +478,21 @@ module mkAXI4_to_LD
Bit #(wd_axi_data_t) rdata = pack (rg_v_slice);
- let rd_data_S = AXI4_Rd_Data {rid: rid,
- rresp: ((illegal_req || rg_cumulative_err)
- ? axi4_resp_slverr
- : axi4_resp_okay),
- rdata: rdata,
- ruser: ruser,
- rlast: True};
+ let rd_data_S = AXI4_R {rid: rid,
+ rresp: ((illegal_req || rg_cumulative_err)
+ ? axi4_resp_slverr
+ : axi4_resp_okay),
+ rdata: rdata,
+ ruser: ruser,
+ rlast: True};
i_rd_data.enq (rd_data_S);
// Get ready for next axi transaction
rg_remaining_slices <= fromInteger (slices_per_axi_data_I);
if (verbosity > 0) begin
- $display ("%0d: %m.AXI4_to_LD:rl_send_axi_response", cur_cycle);
- $display (" AXI4_Rd_Data rid %0h rresp %0h rlast %0d ruser %0h",
+ $display ("%0d: AXI4_to_LD:rl_send_axi_response", cur_cycle);
+ $display (" AXI4_R rid %0h rresp %0h rlast %0d ruser %0h",
rd_data_S.rid, rd_data_S.rresp, rd_data_S.rlast, rd_data_S.ruser);
fa_show_v_slices (rg_v_slice);
end
@@ -506,7 +507,7 @@ module mkAXI4_to_LD
rule rl_illegal_req (rg_state == STATE_ILLEGAL_REQ);
if (verbosity > 0)
- $display ("%0d: %m.AXI4_to_LD:rl_illegal_req", cur_cycle);
+ $display ("%0d: AXI4_to_LD:rl_illegal_req", cur_cycle);
f_ld_rsp_info.enq (tuple2 (RSP_DONE, ?));
f_axi_rsp_info.enq (tuple3 (True, rd_addr_S.arid, rd_addr_S.aruser));
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_to_LDST.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_to_LDST.bsv
index 4ed8514..83de7cb 100644
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_to_LDST.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4/AXI4_to_LDST.bsv
@@ -1,20 +1,20 @@
-// Copyright (c) 2021 Rishiyur S. Nikhil and Bluespec, Inc. All Rights Reserved
-// Author: Rishiyur S. Nikhil
-//
+// Copyright (c) 2021-2024 Rishiyur S. Nikhil and Bluespec, Inc. All Rights Reserved
+
// SPDX-License-Identifier: BSD-3-Clause
package AXI4_to_LDST;
// ================================================================
// This package defines module mkAXI4_to_LDST and its interface.
-// The axi4_S sub-interface is an AXI4 subordinate for single (not burst) transactions.
-// The ldst_M sub-interface is a simple memory Load/Store interface where
-// - the op is LB, LH, LW, LD, SB, SH, SW, SD
-// for loads/stores of bytes (8b), halfwords (16b), words (32b), doublewords (64b),
-// but only up to the ldst_M data bus width
+// The module's argment is an AXI4_M_IFC from some upstream M.
+// It does not accept bursts (use a Deburster in front, if needed).
+
+// The module's interface has 4 FIFOs for LO/ST requests and responses.
+// Load and store requests
+// - have a width (B/H/W/D) for 1/2/4/8 bytes (but limited to wd_axi_data)
// - addresses are properly aligned (lsbs are 0 for H, 00 for W and 000 for D)
// - data are always in LSBS no matter the address (unlike AXI4's lane-alignment)
-// - The axi4_S data bus width must be >= ldst_M bus width
+// - wd_axi_dat must be >= wd_ldst_data
// - This module 'slices' the axi4_S data (width wd_axi_data)
// into slices of width wd_ldst_data for the load/store data bus.
@@ -23,7 +23,7 @@ package AXI4_to_LDST;
// NAPOT naturally aligned power of two
// wd_... width in bits
// wdB_... width in bytes
-// wd_..._t width as a type (numeric kind)
+// wd_... width as a type (numeric kind)
// wd_..._I width as an Integer value
// wd_..._B width as a Bit #(n) value
@@ -33,7 +33,7 @@ package AXI4_to_LDST;
// slices_per_axi_data number of wd_ldst_data slices in wd_axi_data
// szwindow NAPOT window of size specified by AWSIZE, containing AWADDR
-// ================================================================
+// ****************************************************************
export ldst_b, ldst_h, ldst_w, ldst_d;
export AXI4_to_LDST_IFC (..);
@@ -46,7 +46,7 @@ import Vector :: *;
import FIFOF :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Cur_Cycle :: *;
import Semi_FIFOF :: *;
@@ -59,83 +59,71 @@ import AXI4_to_LDST_utils :: *;
import AXI4_to_LD :: *;
import AXI4_to_ST :: *;
-// ================================================================
+// ****************************************************************
// The interface for the module
-interface AXI4_to_LDST_IFC #(numeric type wd_id_t,
- numeric type wd_addr_t,
- numeric type wd_axi_data_t,
- numeric type wd_user_t,
- numeric type wd_ldst_data_t);
-
- interface AXI4_S_IFC #(wd_id_t, wd_addr_t, wd_axi_data_t, wd_user_t)
- axi4_S;
-
+interface AXI4_to_LDST_IFC #(numeric type wd_id,
+ numeric type wd_addr,
+ numeric type wd_axi_data,
+ numeric type wd_user,
+ numeric type wd_ldst_data);
// Stores
- interface FIFOF_O #(Tuple3 #(Bit #(2), // width B/H/W/D
- Bit #(wd_addr_t), // addr
- Bit #(wd_ldst_data_t))) // wdata
+ interface FIFOF_O #(Tuple3 #(Bit #(2), // width B/H/W/D
+ Bit #(wd_addr), // addr
+ Bit #(wd_ldst_data))) // wdata
st_reqs;
interface FIFOF_I #(Bool) // True <=> err
st_rsps;
// Loads
- interface FIFOF_O #(Tuple2 #(Bit #(2), // width B/H/W/D
- Bit #(wd_addr_t))) // addr
+ interface FIFOF_O #(Tuple2 #(Bit #(2), // width B/H/W/D
+ Bit #(wd_addr))) // addr
ld_reqs;
interface FIFOF_I #(Tuple2 #(Bool, // True <=> err
- Bit #(wd_ldst_data_t))) // rdata
+ Bit #(wd_ldst_data))) // rdata
ld_rsps;
endinterface
// ================================================================
// The module (uses separate modules, below, for Load and Store, respectively
-module mkAXI4_to_LDST (AXI4_to_LDST_IFC #(wd_id_t,
- wd_addr_t,
- wd_axi_data_t,
- wd_user_t,
- wd_ldst_data_t))
+module mkAXI4_to_LDST #(AXI4_M_IFC #(wd_id, wd_addr, wd_axi_data, wd_user) ifc_M)
+ (AXI4_to_LDST_IFC #(wd_id,
+ wd_addr,
+ wd_axi_data,
+ wd_user,
+ wd_ldst_data))
- provisos (Add #(a__, 8, wd_addr_t),
+ provisos (Add #(a__, 8, wd_addr),
- Mul #(wd_ldst_data_t, slices_per_axi_data_t, wd_axi_data_t),
+ Mul #(wd_ldst_data, slices_per_axi_data, wd_axi_data),
- Mul #(wdB_axi_data_t, 8, wd_axi_data_t),
+ Mul #(wdB_axi_data, 8, wd_axi_data),
// bsc demands this next proviso though it seems redundant
// (maybe not redundant due to integer div?)
- Div #(wd_axi_data_t, 8, wdB_axi_data_t),
+ Div #(wd_axi_data, 8, wdB_axi_data),
- Mul #(wdB_ldst_data_t, 8, wd_ldst_data_t),
+ Mul #(wdB_ldst_data, 8, wd_ldst_data),
// Redundant, but bsc doesn't work it out
- Mul #(wdB_ldst_data_t, slices_per_axi_data_t, wdB_axi_data_t),
+ Mul #(wdB_ldst_data, slices_per_axi_data, wdB_axi_data),
- Add #(b__, TLog #(TAdd #(1, wdB_ldst_data_t)), 8)
+ Add #(b__, TLog #(TAdd #(1, wdB_ldst_data)), 8)
);
- // Transactor for axi4_S
- AXI4_S_Xactor_IFC #(wd_id_t, wd_addr_t, wd_axi_data_t, wd_user_t)
- axi4_S_xactor <- mkAXI4_S_Xactor;
-
// Store converter
- AXI4_to_ST_IFC #(wd_addr_t, wd_ldst_data_t)
- st_ifc <- mkAXI4_to_ST (axi4_S_xactor.o_wr_addr,
- axi4_S_xactor.o_wr_data,
- axi4_S_xactor.i_wr_resp);
+ AXI4_to_ST_IFC #(wd_addr, wd_ldst_data)
+ st_ifc <- mkAXI4_to_ST (ifc_M.o_AW, ifc_M.o_W, ifc_M.i_B);
// Load converter
- AXI4_to_LD_IFC #(wd_addr_t, wd_ldst_data_t)
- ld_ifc <- mkAXI4_to_LD (axi4_S_xactor.o_rd_addr,
- axi4_S_xactor.i_rd_data);
+ AXI4_to_LD_IFC #(wd_addr, wd_ldst_data)
+ ld_ifc <- mkAXI4_to_LD (ifc_M.o_AR, ifc_M.i_R);
// ----------------------------------------------------------------
// INTERFACE
- interface axi4_S = axi4_S_xactor.axi_side;
-
interface st_reqs = st_ifc.reqs;
interface st_rsps = st_ifc.rsps;
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_to_LDST_utils.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_to_LDST_utils.bsv
index 4fb6252..11da26c 100644
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_to_LDST_utils.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4/AXI4_to_LDST_utils.bsv
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 Rishiyur S. Nikhil and Bluespec, Inc. All Rights Reserved
+// Copyright (c) 2021-2024 Rishiyur S. Nikhil and Bluespec, Inc. All Rights Reserved
// Author: Rishiyur S. Nikhil
//
// SPDX-License-Identifier: BSD-3-Clause
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI4_to_ST.bsv b/Libraries/AMBA_Fabrics/AXI4/AXI4_to_ST.bsv
index 64072b6..95ce357 100644
--- a/Libraries/AMBA_Fabrics/AXI4/AXI4_to_ST.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4/AXI4_to_ST.bsv
@@ -1,6 +1,5 @@
-// Copyright (c) 2021 Rishiyur S. Nikhil and Bluespec, Inc. All Rights Reserved
-// Author: Rishiyur S. Nikhil
-//
+// Copyright (c) 2021-2024 Rishiyur S. Nikhil and Bluespec, Inc. All Rights Reserved
+
// SPDX-License-Identifier: BSD-3-Clause
package AXI4_to_ST;
@@ -22,7 +21,7 @@ import Vector :: *;
import FIFOF :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Cur_Cycle :: *;
import Semi_FIFOF :: *;
@@ -67,9 +66,9 @@ Integer verbosity = 0;
// Module
module mkAXI4_to_ST
- #(FIFOF_O #(AXI4_Wr_Addr #(wd_id_t, wd_addr_t, wd_user_t)) o_wr_addr,
- FIFOF_O #(AXI4_Wr_Data #(wd_axi_data_t, wd_user_t)) o_wr_data,
- FIFOF_I #(AXI4_Wr_Resp #(wd_id_t, wd_user_t)) i_wr_resp)
+ #(FIFOF_O #(AXI4_AW #(wd_id_t, wd_addr_t, wd_user_t)) o_wr_addr,
+ FIFOF_O #(AXI4_W #(wd_axi_data_t, wd_user_t)) o_wr_data,
+ FIFOF_I #(AXI4_B #(wd_id_t, wd_user_t)) i_wr_resp)
(AXI4_to_ST_IFC #(wd_addr_t, wd_ldst_data_t))
provisos (Add #(a__, 8, wd_addr_t),
@@ -160,10 +159,11 @@ module mkAXI4_to_ST
Bit #(wd_addr_t) addr_axi_bus_lo = fn_addr_to_NAPOT (awaddr,
fromInteger (wdB_axi_data_I));
// Bytelane of awaddr on AXI data
- Bit #(8) addr_bytelane = fn_addr_to_axi_data_bytelane (awaddr, wdB_axi_data_I);
+ Bit #(8) addr_bytelane = fn_addr_to_axi_data_bytelane (awaddr, wdB_axi_data_I);
// AWSIZE specifies a NAPOT window around awaddr, ...
- Bit #(8) wdB_szwindow_B = fv_AXI4_Size_to_num_bytes (wr_addr_S.awsize);
+ Bit #(8) wdB_szwindow_B = fv_AXI4_Size_to_num_bytes (wr_addr_S.awsize);
+
// Address of NAPOT AWSIZE window containing awaddr
Bit #(wd_addr_t) addr_szwindow_lo = fn_addr_to_NAPOT (awaddr, wdB_szwindow_B);
@@ -311,7 +311,7 @@ module mkAXI4_to_ST
rule rl_start_xaction (rg_state == STATE_IDLE);
if (verbosity > 0) begin
- $display ("%0d: %m.AXI4_to_ST:rl_start_xaction ================", cur_cycle);
+ $display ("%0d: AXI4_to_ST:rl_start_xaction ================", cur_cycle);
fa_show_values();
end
@@ -320,7 +320,7 @@ module mkAXI4_to_ST
Bool illegal_req = False;
if (wdB_szwindow_B > fromInteger (wdB_axi_data_I)) begin
if (verbosity == 0)
- $display ("%0d: %m.AXI4_to_ST:rl_start_xaction ================", cur_cycle);
+ $display ("%0d: AXI4_to_ST:rl_start_xaction ================", cur_cycle);
$display (" ERROR: illegal AXI4 request");
$display (" awsize 0x%0h bytes > axi data bus width 0x%0h bytes",
wdB_szwindow_B, wdB_axi_data_I);
@@ -329,7 +329,7 @@ module mkAXI4_to_ST
if (wr_addr_S.awlen != 0) begin
if (verbosity == 0)
- $display ("%0d: %m.AXI4_to_ST:rl_start_xaction ================", cur_cycle);
+ $display ("%0d: AXI4_to_ST:rl_start_xaction ================", cur_cycle);
$display (" ERROR: illegal AXI4 request");
$display (" awlen 0x%0h; only awlen 0 (1-beat bursts) supported",
wr_addr_S.awlen);
@@ -338,7 +338,7 @@ module mkAXI4_to_ST
if (! wr_data_S.wlast) begin
if (verbosity == 0)
- $display ("%0d: %m.AXI4_to_ST:rl_start_xaction ================", cur_cycle);
+ $display ("%0d: AXI4_to_ST:rl_start_xaction ================", cur_cycle);
$display (" ERROR: illegal AXI4 request");
$display (" wlast != 1; only 1-beat bursts supported");
illegal_req = True;
@@ -381,7 +381,7 @@ module mkAXI4_to_ST
rule rl_next_slice (rg_state == STATE_SLICE);
if (verbosity > 0)
- $display ("%0d: %m.AXI4_to_ST:rl_next_slice", cur_cycle);
+ $display ("%0d: AXI4_to_ST:rl_next_slice", cur_cycle);
Vector #(slices_per_axi_data_t,
Bit #(wd_ldst_data_t)) v_slice = rg_v_slice;
@@ -407,7 +407,7 @@ module mkAXI4_to_ST
rule rl_partial (rg_state == STATE_PARTIAL);
if (verbosity > 0) begin
- $display ("%0d: %m.AXI4_to_ST:rl_partial", cur_cycle);
+ $display ("%0d: AXI4_to_ST:rl_partial", cur_cycle);
$display (" rg_slice %0h rg_bytelane_hi..lo [%0h..%0h] rg_bytelane_slice_lo %0h",
rg_slice, rg_bytelane_hi, rg_bytelane_lo, rg_bytelane_slice_lo);
end
@@ -442,7 +442,7 @@ module mkAXI4_to_ST
rule rl_finish_req (rg_state == STATE_FINISH_REQ);
if (verbosity > 0)
- $display ("%0d: %m.AXI4_to_ST:rl_finish_req", cur_cycle);
+ $display ("%0d: AXI4_to_ST:rl_finish_req", cur_cycle);
f_st_rsp_info.enq (1); // 'done' sentinel
f_axi_rsp_info.enq (tuple3 (False, wr_addr_S.awid, wr_addr_S.awuser));
@@ -462,7 +462,7 @@ module mkAXI4_to_ST
rg_cumulative_err <= (rg_cumulative_err || err);
if (verbosity > 0)
- $display ("%0d: %m.AXI4_to_ST:rl_handle_st_rsps: err = %0d", cur_cycle, err);
+ $display ("%0d: AXI4_to_ST:rl_handle_st_rsps: err = %0d", cur_cycle, err);
endrule
// ----------------
@@ -472,15 +472,15 @@ module mkAXI4_to_ST
match { .illegal_req, .bid, .buser } = f_axi_rsp_info.first;
f_axi_rsp_info.deq;
- let wr_resp_S = AXI4_Wr_Resp {bid: bid,
- bresp: ((illegal_req || rg_cumulative_err)
- ? axi4_resp_slverr
- : axi4_resp_okay),
- buser: buser};
+ let wr_resp_S = AXI4_B {bid: bid,
+ bresp: ((illegal_req || rg_cumulative_err)
+ ? axi4_resp_slverr
+ : axi4_resp_okay),
+ buser: buser};
i_wr_resp.enq (wr_resp_S);
if (verbosity > 0) begin
- $display ("%0d: %m.AXI4_to_ST:rl_send_axi_response", cur_cycle);
+ $display ("%0d: AXI4_to_ST:rl_send_axi_response", cur_cycle);
$display (" ", fshow (wr_resp_S));
end
endrule
@@ -493,7 +493,7 @@ module mkAXI4_to_ST
rule rl_illegal_req (rg_state == STATE_ILLEGAL_REQ);
if (verbosity > 0) begin
- $write ("%0d: %m.AXI4_to_ST:rl_illegal_req: rg_discard_count = %0h",
+ $write ("%0d: AXI4_to_ST:rl_illegal_req: rg_discard_count = %0h",
cur_cycle, rg_discard_count);
if (rg_discard_count == 0) $write (" (last)");
$display ("");
diff --git a/Libraries/AMBA_Fabrics/AXI4/Makefile b/Libraries/AMBA_Fabrics/AXI4/Makefile
index 8f7df88..06be1fe 100644
--- a/Libraries/AMBA_Fabrics/AXI4/Makefile
+++ b/Libraries/AMBA_Fabrics/AXI4/Makefile
@@ -8,28 +8,25 @@ LIBNAME=AMBA_Fabrics/AXI4
# and defines the install target
include ../../common.mk
-# Requires files in Misc
+# Requires files in Misc and Utils
BSCFLAGS += -p $(BUILDDIR)/../../Misc:+
+BSCFLAGS += -p $(BUILDDIR)/../Utils:+
.PHONY: build
build:
+ $(BSC) -u $(BSCFLAGS) AXI4_Types.bsv
+ $(BSC) -u $(BSCFLAGS) AXI4_BSV_RTL.bsv
+ $(BSC) -u $(BSCFLAGS) AXI4_Mem_Model.bsv
+ $(BSC) -u $(BSCFLAGS) AXI4_to_LD.bsv
+ $(BSC) -u $(BSCFLAGS) AXI4_to_LDST.bsv
+ $(BSC) -u $(BSCFLAGS) AXI4_to_LDST_utils.bsv
+ $(BSC) -u $(BSCFLAGS) AXI4_to_ST.bsv
$(BSC) -u $(BSCFLAGS) AXI4_Addr_Translator.bsv
- $(BSC) -u $(BSCFLAGS) AXI4_ClockCrossing.bsv
$(BSC) -u $(BSCFLAGS) AXI4_Clock_Crossers.bsv
$(BSC) -u $(BSCFLAGS) AXI4_Deburster.bsv
- $(BSC) -u $(BSCFLAGS) AXI4_Extra_Xactors.bsv
$(BSC) -u $(BSCFLAGS) AXI4_Fabric.bsv
$(BSC) -u $(BSCFLAGS) AXI4_Gate.bsv
- $(BSC) -u $(BSCFLAGS) AXI4_Mem_Model.bsv
- $(BSC) -u $(BSCFLAGS) AXI4_Types.bsv
$(BSC) -u $(BSCFLAGS) AXI4_Widener.bsv
- $(BSC) -u $(BSCFLAGS) AXI4_Xactors.bsv
- $(BSC) -u $(BSCFLAGS) AXI4_to_LD.bsv
- $(BSC) -u $(BSCFLAGS) AXI4_to_LDST.bsv
- $(BSC) -u $(BSCFLAGS) AXI4_to_LDST_utils.bsv
- $(BSC) -u $(BSCFLAGS) AXI4_to_ST.bsv
- $(BSC) -u $(BSCFLAGS) AXI_SyncBuffer.bsv
- $(BSC) -u $(BSCFLAGS) AXI4_DDR_Model.bsv
.PHONY: clean full_clean
clean full_clean:
diff --git a/Libraries/AMBA_Fabrics/AXI4/README_AXI4.adoc b/Libraries/AMBA_Fabrics/AXI4/README_AXI4.adoc
new file mode 100644
index 0000000..4aee1c2
--- /dev/null
+++ b/Libraries/AMBA_Fabrics/AXI4/README_AXI4.adoc
@@ -0,0 +1,176 @@
+= About `bsc-contrib/Libraries/AMBA_Fabrics/AXI4`
+:revnumber: v1.00
+:revdate: 2024-12-09
+:sectnums:
+:imagesdir: Doc/Figs
+:toc:
+:toclevels: 3
+:toc-title: Contents
+:keywords: Bluespec, B-Lang, BSV, BH, AMBA, ARM AXI, AXI4, AXI4-Lite, AXI4-Stream
+
+// ================================================================
+
+Copyright (C) 2017-2023 Bluespec, Inc. All Rights Reserved +
+Copyright (C) 2024 B-Lang.org. All Rights Reserved
+
+SPDX-License-Identifier: BSD-3-Clause
+
+// ================================================================
+
+Pleae see README in parent directory
+(link:../README_AMBA_Fabrics.adoc[adoc],link:../README_AMBA_Fabrics.html[html])
+for general introduction and about compiling/building/testing.
+
+This directory describes AXI4 facilities, including type definitions,
+cross-bar switches, connectors, clock-crossers, and edge-transactors
+to connect the B-Lang world to existing RTL (e.g., external AMBA IP).
+
+These source codes may import other `bsv-contrib` libraries; be sure
+they are visible in your _bsc_ compiler paths:
+
+ bsc-contrib/Libraries/AMBA_Fabrics/Utils/
+ bsc-contrib/Libraries/Misc/
+
+// ================================================================
+== General
+
+Many of these modules take an upstream `AXI4_M_IFC` and/or a
+downstream `AXI4_S_IFC` as a module parameter. Thus, the actual FIFO
+buffers producing these interfaces are external, allowing a choice of
+buffering alternatives.
+
+// ================================================================
+== `AXI4_Types.bsv`
+
+This is a key file used by all the others. Defines:
+
+* Basic bus and field payload types and structs for AW, W, B, AR, R,
+ some help-functions and display-formatting functions
+
+* M and S interface types, their connections, and dummy tie-offs
+* AXI4 Buffers with different kinds of internal FIFOs
+
+Everything is parameterized on wd_id, wd_addr, wd_data, wd_user (bit
+widths of corresponding buses).
+
+// ================================================================
+== `AXI4_Fabric.bsv`
+
+NOTE: Needs _bsc_ `-aggressive-conditions` flag (else may deadlock).
+
+Defines a module for a crossbar switch from a vector of Ms to a vector of Ss.
+
+Parameterized on number of Ms and Ss (`num_M` and `num_S`) and AXI4
+bus bitwidths (`wd_id`, `wd_addr`, `wd_data`, `wd_user`).
+
+Also paramterized by function `fn_addr_to_S_num()` which decides which
+S (if any) services which address (used to route transactions from an
+M to the appropriate S).
+
+The vector-of-Ms and vector-of-Ss are module parameters, so all
+buffering decisions are external to this module.
+
+Arbitration is statically decided, based on the index of an M or S in
+the input vectors:
+
+* For simultaneously arriving requests from two Ms for a common S, the
+ lower-indexed M wins.
+
+* For simultaneously arriving responses from two Ss for a common M,
+ the lower-indexed S wins.
+
+Limitation: Corresponding field-widths are kept identical across AW,
+W, B, AR and R. Technically, the `awwidth` and `arwidth` could
+differ; `awid`, `bid`, `arid`, `rid` could differ; all the `user`
+fields could differ, etc., but we have chosen not to make separate
+parameters for all these. Please make your own modified variant of
+this code if you need such capability.
+
+See:
+
+ testing/bsc.contrib/AMBA_Fabrics/AXI4/Test_AXI4_Fabric.bsv
+
+for an example of instantiating an `AXI4_Fabric` and connecting it to Ms and Ss.
+
+// ================================================================
+== `AXI4_Mem_Model.bsv`
+
+Module that takes an M interface parameter and attaches a memory model
+to it. Parameterized by module-id, base address and address limit,
+and all the AXI4 bus widths. Optionally zeroes out memory after
+reset. In simulation, can load a memhex file to initialize memory.
+
+Implements the memory using a B-Lang `RegFile`, so this is technically
+synthesizable to hardware, although `RegFile` is not a good choice for
+anything other than small memories.
+
+// ================================================================
+== Misc.
+
+=== `AXI4_Addr_Translator.bsv`
+
+Functions to transform an M interface into another M, and an S into
+another S, simply adding/subtracting a given address-delta to incoming
+address.
+
+=== `AXI4_Deburster.bsv`
+
+Module that attaches to S interface parameter (downstream) and itself
+offers another S interface (upstream). A burst transaction from the
+upstream side is converted into individual (non-burst) transactions on
+the downstream side.
+
+=== `AXI4_Widener.bsv`
+
+Module which connects an M and an S interface paramter. The data
+width on S is some power-of-2 multiple of the data width on M.
+
+=== `AXI4_Gate.bsv`
+
+Module which connects an M and an S interface parameter. A method in
+the module interface controls whether traffic flows between M and S or
+is blocked. Can be used to for authenticated access.
+
+// ================================================================
+== `AXI4_to_LDST.bsv`
+
+Module which takes an M interface (upstream), and whose interface is a
+pair of FIFOs representing an simple "store" request/response
+interface and a pair of FIFOs representing an ordinary "load"
+request/response interface. Data on the simple interfaces are
+LSB-aligned (not lane-aligned like in AXI).
+
+Internal help-packages:
+
+* `AXI4_to_LD.bsv`
+* `AXI4_to_ST.bsv`
+* `AXI4_to_LDST_utils.bsv`
+
+// ================================================================
+== `AXI4_Clock_Crossers.bsv`
+
+Facilities for taking an AXI4 bus across a clock- and/or reset-domain
+boundary. Effectively an AXI4 buffer where the upstream and
+downstream sides have different clocks and resets.
+
+// ================================================================
+== `AXI4_BSV_RTL.bsv`
+
+Defines RTL-level interfaces `AXI4_RTL_M_IFC` and `AXI4_RTL_M_IFC`
+(AMBA AXI bus names, ready-valid signals), `mkConnection` to connect
+them in a one-liner, dummy M and S interfaces (tie-offs), and buffers
+to connect B-Lang-style interfaces to RTL-style interfaces (B-Lang M
+to RTL S, and RTL B-Lang to B-Lang S).
+
+// ================================================================
+== Unit tests
+
+There are some unit tests in:
+
+ bsc-contrib/testing/bsc.contrib/AMBA_Fabrics/AXI4/Test_*.bsv
+
+The conventions for unit tests are described in more detail in the
+README in the parent directory
+(link:../README_AMBA_Fabrics.adoc[adoc],link:../README_AMBA_Fabrics.html[html]).
+
+// ================================================================
diff --git a/Libraries/AMBA_Fabrics/AXI4/README_AXI4.html b/Libraries/AMBA_Fabrics/AXI4/README_AXI4.html
new file mode 100644
index 0000000..8f332a7
--- /dev/null
+++ b/Libraries/AMBA_Fabrics/AXI4/README_AXI4.html
@@ -0,0 +1,733 @@
+
+
+
+
+
+
+
+
+About bsc-contrib/Libraries/AMBA_Fabrics/AXI4
+
+
+
+
+
+
+
+
+
+
Copyright © 2017-2023 Bluespec, Inc. All Rights Reserved
+Copyright © 2024 B-Lang.org. All Rights Reserved
+
+
+
SPDX-License-Identifier: BSD-3-Clause
+
+
+
Pleae see README in parent directory
+(adoc ,html )
+for general introduction and about compiling/building/testing.
+
+
+
This directory describes AXI4 facilities, including type definitions,
+cross-bar switches, connectors, clock-crossers, and edge-transactors
+to connect the B-Lang world to existing RTL (e.g., external AMBA IP).
+
+
+
These source codes may import other bsv-contrib
libraries; be sure
+they are visible in your bsc compiler paths:
+
+
+
+
bsc-contrib/Libraries/AMBA_Fabrics/Utils/
+bsc-contrib/Libraries/Misc/
+
+
+
+
+
+
1. General
+
+
+
Many of these modules take an upstream AXI4_M_IFC
and/or a
+downstream AXI4_S_IFC
as a module parameter. Thus, the actual FIFO
+buffers producing these interfaces are external, allowing a choice of
+buffering alternatives.
+
+
+
+
+
2. AXI4_Types.bsv
+
+
+
This is a key file used by all the others. Defines:
+
+
+
+
+Basic bus and field payload types and structs for AW, W, B, AR, R,
+some help-functions and display-formatting functions
+
+
+M and S interface types, their connections, and dummy tie-offs
+
+
+AXI4 Buffers with different kinds of internal FIFOs
+
+
+
+
+
Everything is parameterized on wd_id, wd_addr, wd_data, wd_user (bit
+widths of corresponding buses).
+
+
+
+
+
3. AXI4_Fabric.bsv
+
+
+
+
+
+Note
+
+
+Needs bsc -aggressive-conditions
flag (else may deadlock).
+
+
+
+
+
+
Defines a module for a crossbar switch from a vector of Ms to a vector of Ss.
+
+
+
Parameterized on number of Ms and Ss (num_M
and num_S
) and AXI4
+bus bitwidths (wd_id
, wd_addr
, wd_data
, wd_user
).
+
+
+
Also paramterized by function fn_addr_to_S_num()
which decides which
+S (if any) services which address (used to route transactions from an
+M to the appropriate S).
+
+
+
The vector-of-Ms and vector-of-Ss are module parameters, so all
+buffering decisions are external to this module.
+
+
+
Arbitration is statically decided, based on the index of an M or S in
+the input vectors:
+
+
+
+
+For simultaneously arriving requests from two Ms for a common S, the
+lower-indexed M wins.
+
+
+For simultaneously arriving responses from two Ss for a common M,
+the lower-indexed S wins.
+
+
+
+
+
Limitation: Corresponding field-widths are kept identical across AW,
+W, B, AR and R. Technically, the awwidth
and arwidth
could
+differ; awid
, bid
, arid
, rid
could differ; all the user
+fields could differ, etc., but we have chosen not to make separate
+parameters for all these. Please make your own modified variant of
+this code if you need such capability.
+
+
+
+
+
testing/bsc.contrib/AMBA_Fabrics/AXI4/Test_AXI4_Fabric.bsv
+
+
+
+
for an example of instantiating an AXI4_Fabric
and connecting it to Ms and Ss.
+
+
+
+
+
4. AXI4_Mem_Model.bsv
+
+
+
Module that takes an M interface parameter and attaches a memory model
+to it. Parameterized by module-id, base address and address limit,
+and all the AXI4 bus widths. Optionally zeroes out memory after
+reset. In simulation, can load a memhex file to initialize memory.
+
+
+
Implements the memory using a B-Lang RegFile
, so this is technically
+synthesizable to hardware, although RegFile
is not a good choice for
+anything other than small memories.
+
+
+
+
+
5. Misc.
+
+
+
5.1. AXI4_Addr_Translator.bsv
+
+
Functions to transform an M interface into another M, and an S into
+another S, simply adding/subtracting a given address-delta to incoming
+address.
+
+
+
+
5.2. AXI4_Deburster.bsv
+
+
Module that attaches to S interface parameter (downstream) and itself
+offers another S interface (upstream). A burst transaction from the
+upstream side is converted into individual (non-burst) transactions on
+the downstream side.
+
+
+
+
5.3. AXI4_Widener.bsv
+
+
Module which connects an M and an S interface paramter. The data
+width on S is some power-of-2 multiple of the data width on M.
+
+
+
+
5.4. AXI4_Gate.bsv
+
+
Module which connects an M and an S interface parameter. A method in
+the module interface controls whether traffic flows between M and S or
+is blocked. Can be used to for authenticated access.
+
+
+
+
+
+
6. AXI4_to_LDST.bsv
+
+
+
Module which takes an M interface (upstream), and whose interface is a
+pair of FIFOs representing an simple "store" request/response
+interface and a pair of FIFOs representing an ordinary "load"
+request/response interface. Data on the simple interfaces are
+LSB-aligned (not lane-aligned like in AXI).
+
+
+
Internal help-packages:
+
+
+
+
+AXI4_to_LD.bsv
+
+
+AXI4_to_ST.bsv
+
+
+AXI4_to_LDST_utils.bsv
+
+
+
+
+
+
+
7. AXI4_Clock_Crossers.bsv
+
+
+
Facilities for taking an AXI4 bus across a clock- and/or reset-domain
+boundary. Effectively an AXI4 buffer where the upstream and
+downstream sides have different clocks and resets.
+
+
+
+
+
8. AXI4_BSV_RTL.bsv
+
+
+
Defines RTL-level interfaces AXI4_RTL_M_IFC
and AXI4_RTL_M_IFC
+(AMBA AXI bus names, ready-valid signals), mkConnection
to connect
+them in a one-liner, dummy M and S interfaces (tie-offs), and buffers
+to connect B-Lang-style interfaces to RTL-style interfaces (B-Lang M
+to RTL S, and RTL B-Lang to B-Lang S).
+
+
+
+
+
9. Unit tests
+
+
+
There are some unit tests in:
+
+
+
+
bsc-contrib/testing/bsc.contrib/AMBA_Fabrics/AXI4/Test_*.bsv
+
+
+
+
The conventions for unit tests are described in more detail in the
+README in the parent directory
+(adoc ,html ).
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Clock_Crossers.bsv b/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Clock_Crossers.bsv
index 4992ec0..895d672 100644
--- a/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Clock_Crossers.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Clock_Crossers.bsv
@@ -33,7 +33,7 @@ import Clocks :: *;
import Connectable :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Cur_Cycle :: *;
import GetPut_Aux :: *;
@@ -42,7 +42,7 @@ import Semi_FIFOF :: *;
// ================================================================
// Project imports
-import AXI_SyncBuffer :: *;
+import AXIx_SyncBuffer :: *;
import AXI4L_Types :: *;
import AXI4L_Xactors :: *;
@@ -64,12 +64,12 @@ module mkAXI4L_S_Clock_Crosser
axi4L_M_xactor <- mkAXI4L_M_Xactor (clocked_by clk1, reset_by rst1);
// Syncbuffer between transactors
- AXI_SyncBuffer_IFC #(AXI4L_Wr_Addr #(wd_addr, wd_user),
- AXI4L_Wr_Data #(wd_data),
- AXI4L_Wr_Resp #(wd_user),
- AXI4L_Rd_Addr #(wd_addr, wd_user),
- AXI4L_Rd_Data #(wd_data, wd_user))
- axi4L_syncbuf <- mkAXI_SyncBuffer (depth, clk2, rst2, clk1, rst1);
+ AXIx_SyncBuffer_IFC #(AXI4L_Wr_Addr #(wd_addr, wd_user),
+ AXI4L_Wr_Data #(wd_data),
+ AXI4L_Wr_Resp #(wd_user),
+ AXI4L_Rd_Addr #(wd_addr, wd_user),
+ AXI4L_Rd_Data #(wd_data, wd_user))
+ axi4L_syncbuf <- mkAXIx_SyncBuffer (depth, clk2, rst2, clk1, rst1);
// Transactor with ifc2
AXI4L_S_Xactor_IFC #(wd_addr, wd_data, wd_user)
@@ -115,12 +115,12 @@ module mkAXI4L_M_Clock_Crosser
axi4L_S_xactor <- mkAXI4L_S_Xactor (clocked_by clk1, reset_by rst1);
// Syncbuffer between transactors
- AXI_SyncBuffer_IFC #(AXI4L_Wr_Addr #(wd_addr, wd_user),
- AXI4L_Wr_Data #(wd_data),
- AXI4L_Wr_Resp #(wd_user),
- AXI4L_Rd_Addr #(wd_addr, wd_user),
- AXI4L_Rd_Data #(wd_data, wd_user))
- axi4L_syncbuf <- mkAXI_SyncBuffer (depth, clk1, rst1, clk2, rst2);
+ AXIx_SyncBuffer_IFC #(AXI4L_Wr_Addr #(wd_addr, wd_user),
+ AXI4L_Wr_Data #(wd_data),
+ AXI4L_Wr_Resp #(wd_user),
+ AXI4L_Rd_Addr #(wd_addr, wd_user),
+ AXI4L_Rd_Data #(wd_data, wd_user))
+ axi4L_syncbuf <- mkAXIx_SyncBuffer (depth, clk1, rst1, clk2, rst2);
// Transactor with ifc2
AXI4L_M_Xactor_IFC #(wd_addr, wd_data, wd_user)
diff --git a/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Fabric.bsv b/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Fabric.bsv
index b7a7cf0..a1c2122 100644
--- a/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Fabric.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Fabric.bsv
@@ -17,7 +17,7 @@ import SpecialFIFOs :: *;
import ConfigReg :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Cur_Cycle :: *;
diff --git a/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Gate.bsv b/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Gate.bsv
index a9e1bcc..1852d6b 100644
--- a/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Gate.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Gate.bsv
@@ -21,7 +21,7 @@ import Vector :: *;
import FIFOF :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Cur_Cycle :: *;
import GetPut_Aux :: *;
@@ -111,8 +111,7 @@ module mkAXI4L_Gate
$display ("WARNING: rl_wr_addr_disabled: rec'd wr request from M when gate disabled.");
$display (" ", fshow (wra));
- $display (" Returning error response.");
- $display (" %0d: %m", cur_cycle);
+ $display (" %0d: Returning error response.", cur_cycle);
endrule
rule rl_wr_data_disabled (respond_with_err && (! rg_enabled));
@@ -123,8 +122,7 @@ module mkAXI4L_Gate
rule rl_wr_resp_disabled_drain_S (respond_with_err && (! rg_enabled));
let wrr <- pop_o (xactor_to_S.o_wr_resp);
$display ("WARNING: rl_wr_resp_disabled: rec'd wr resp from S when gate disabled; ignoring");
- $display (" (there couldn't have been a request)");
- $display (" %0d: %m", cur_cycle);
+ $display (" %0d: (there couldn't have been a request)", cur_cycle);
endrule
rule rl_rd_addr_disabled (respond_with_err && (! rg_enabled));
@@ -136,15 +134,13 @@ module mkAXI4L_Gate
$display ("WARNING: rl_rd_addr_disabled: rec'd rd request from M when gate disabled.");
$display (" ", fshow (rda));
- $display (" Returning error response.");
- $display (" %0d: %m", cur_cycle);
+ $display (" %0d: Returning error response.", cur_cycle);
endrule
rule rl_rd_data_disabled_drain_S (respond_with_err && (! rg_enabled));
let rdd <- pop_o (xactor_to_S.o_rd_data);
$display ("WARNING: rl_rd_data_disabled: rec'd rd resp from S when gate disabled; ignoring");
- $display (" (there couldn't have been a request)");
- $display (" %0d: %m", cur_cycle);
+ $display (" %0d: (there couldn't have been a request)", cur_cycle);
endrule
// ----------------------------------------------------------------
@@ -155,9 +151,9 @@ module mkAXI4L_Gate
method Action m_enable (Bool enabled);
if (enabled && (! rg_enabled) && (verbosity != 0))
- $display ("%0d: %m: AXI4L ENABLING", cur_cycle);
+ $display ("%0d: AXI4L ENABLING", cur_cycle);
else if ((! enabled) && rg_enabled && (verbosity != 0))
- $display ("%0d: %m: AXI4L DISABLING", cur_cycle);
+ $display ("%0d: AXI4L DISABLING", cur_cycle);
rg_enabled <= enabled;
endmethod
diff --git a/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Types.bsv b/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Types.bsv
index a1a2213..e90ccc0 100644
--- a/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Types.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Types.bsv
@@ -71,7 +71,7 @@ import Connectable :: *;
import BUtils :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Semi_FIFOF :: *;
import EdgeFIFOFs :: *;
diff --git a/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Xactors.bsv b/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Xactors.bsv
index 0cc0b32..7b885b4 100644
--- a/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Xactors.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4_Lite/AXI4L_Xactors.bsv
@@ -20,7 +20,7 @@ package AXI4L_Xactors;
// None
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Semi_FIFOF :: *;
diff --git a/Libraries/AMBA_Fabrics/AXI4_Lite/Makefile b/Libraries/AMBA_Fabrics/AXI4_Lite/Makefile
index c81dd29..fda37ce 100644
--- a/Libraries/AMBA_Fabrics/AXI4_Lite/Makefile
+++ b/Libraries/AMBA_Fabrics/AXI4_Lite/Makefile
@@ -8,8 +8,9 @@ LIBNAME=AMBA_Fabrics/AXI4_Lite
# and defines the install target
include ../../common.mk
-# Requires files in Misc and AMBA_Fabrics/AXI4
-BSCFLAGS += -p $(BUILDDIR)/../../Misc:$(BUILDDIR)/../../AMBA_Fabrics/AXI4:+
+# Requires files in Misc and Utils
+BSCFLAGS += -p $(BUILDDIR)/../../Misc:+
+BSCFLAGS += -p $(BUILDDIR)/../Utils:+
.PHONY: build
build:
diff --git a/Libraries/AMBA_Fabrics/AXI4_Lite/README_AXI4L.adoc b/Libraries/AMBA_Fabrics/AXI4_Lite/README_AXI4L.adoc
new file mode 100644
index 0000000..c8ef8e1
--- /dev/null
+++ b/Libraries/AMBA_Fabrics/AXI4_Lite/README_AXI4L.adoc
@@ -0,0 +1,105 @@
+= About `bsc-contrib/Libraries/AMBA_Fabrics/AXI4_Lite`
+:revnumber: v1.00
+:revdate: 2024-12-07
+:sectnums:
+:imagesdir: ../Doc/Figs
+:toc:
+:toclevels: 3
+:toc-title: Contents
+:keywords: Bluespec, B-Lang, BSV, BH, AMBA, ARM AXI, AXI4, AXI4-Lite, AXI4-Stream
+
+// ================================================================
+
+Copyright (C) 2017-2023 Bluespec, Inc. All Rights Reserved +
+Copyright (C) 2024-2025 B-Lang.org. All Rights Reserved
+
+SPDX-License-Identifier: BSD-3-Clause
+
+// ================================================================
+
+Pleae see README in parent directory
+(link:../README_AMBA_Fabrics.adoc[adoc],link:../README_AMBA_Fabrics.html[html])
+for general introduction and about compiling/building/testing.
+
+This directory describes AXI4-Lite facilities, including type definitions,
+cross-bar switches, connectors, clock-crossers, and edge-transactors
+to connect the B-Lang world to existing RTL (e.g., external AMBA IP).
+
+These source codes may import other `bsv-contrib` libraries; be sure
+they are visible in your _bsc_ compiler paths:
+
+ bsc-contrib/Libraries/AMBA_Fabrics/Utils/
+ bsc-contrib/Libraries/Misc/
+
+// ================================================================
+
+image::IMG_Under_Construction.png[align="left", width=100]
+
+The packages in this directory can be used as-is, but are expected to
+be restructured to be more like their AXI4 siblings (more consistent
+naming, clean separation of B-Lang-style and RTL-style, etc.)
+
+This documentation will be updated after that restructuring.
+
+// ================================================================
+== General
+
+Many of these modules take an upstream `AXI4L_M_IFC` and/or a
+downstream `AXI4L_S_IFC` as a module parameter. Thus, the actual FIFO
+buffers producing these interfaces are external, allowing a choice of
+buffering alternatives.
+
+All these have a 'user' field which is not standard in AXI4-Lite (same
+role as 'user' in AXI4), which can be left unused, and/or set to width
+0.
+
+// ================================================================
+== `AXI4_Lite_Types.bsv`
+
+Definitions for AXI4_Lite bus types, M and S interfaces, connections
+between Ms and Ss, dummy M and S tie-offs, and transactors to provide
+higher-level FIFO-like interfaces to drive Ms and Ss.
+
+Everything is parameterizd on width of address, data and user buses.
+
+Note: some aspects of these definitions may seem a bit verbose and
+messy; that is not typical of BSV code, but is true here because it is
+meant to interface to hand-written Verilog, so we need to provide
+precise control on interface signal names and protocols that are
+required by the Verilog side. Pure BSV code can be an order of
+magnitude more compact.
+
+Everything is parameterized on wd_addr, wd_data, wd_user.
+
+== `AXI4_Lite_Fabric.bsv`
+
+NOTE: Needs _bsc_ `-aggressive-conditions` flag (else will deadlock).
+
+Definition for interface and module for an num_M x num_S crossbar
+switch with AXI4-Lite interfaces.
+
+This is also an example of how, within BSV code, we don't worry about
+the details of AXI4-Lite signalling. We just instantiate the
+transactors defined in AXI4_Lite_Types.bsv, and then work only with
+simple, FIFO-like interfaces.
+
+Everything is parameterized on num_M, num_S, wd_addr, wd_data,
+wd_user.
+
+// ================================================================
+== Clock-crossers, other transactors
+
+(... To be written ...)
+
+// ================================================================
+== Unit tests
+
+There are some unit tests in:
+
+ bsc-contrib/testing/bsc.contrib/AMBA_Fabrics/AXI4_Lite/Test_*.bsv
+
+The conventions for unit tests are described in more detail in the
+README in the parent directory
+(link:../README_AMBA_Fabrics.adoc[adoc],link:../README_AMBA_Fabrics.html[html]).
+
+// ================================================================
diff --git a/Libraries/AMBA_Fabrics/AXI4_Lite/README_AXI4L.html b/Libraries/AMBA_Fabrics/AXI4_Lite/README_AXI4L.html
new file mode 100644
index 0000000..37e9765
--- /dev/null
+++ b/Libraries/AMBA_Fabrics/AXI4_Lite/README_AXI4L.html
@@ -0,0 +1,606 @@
+
+
+
+
+
+
+
+
+About bsc-contrib/Libraries/AMBA_Fabrics/AXI4_Lite
+
+
+
+
+
+
+
+
+
+
Copyright © 2017-2023 Bluespec, Inc. All Rights Reserved
+Copyright © 2024-2025 B-Lang.org. All Rights Reserved
+
+
+
SPDX-License-Identifier: BSD-3-Clause
+
+
+
Pleae see README in parent directory
+(adoc ,html )
+for general introduction and about compiling/building/testing.
+
+
+
This directory describes AXI4-Lite facilities, including type definitions,
+cross-bar switches, connectors, clock-crossers, and edge-transactors
+to connect the B-Lang world to existing RTL (e.g., external AMBA IP).
+
+
+
These source codes may import other bsv-contrib
libraries; be sure
+they are visible in your bsc compiler paths:
+
+
+
+
bsc-contrib/Libraries/AMBA_Fabrics/Utils/
+bsc-contrib/Libraries/Misc/
+
+
+
+
+
+
+
+
+
The packages in this directory can be used as-is, but are expected to
+be restructured to be more like their AXI4 siblings (more consistent
+naming, clean separation of B-Lang-style and RTL-style, etc.)
+
+
+
This documentation will be updated after that restructuring.
+
+
+
+
+
1. General
+
+
+
Many of these modules take an upstream AXI4L_M_IFC
and/or a
+downstream AXI4L_S_IFC
as a module parameter. Thus, the actual FIFO
+buffers producing these interfaces are external, allowing a choice of
+buffering alternatives.
+
+
+
All these have a 'user' field which is not standard in AXI4-Lite (same
+role as 'user' in AXI4), which can be left unused, and/or set to width
+0.
+
+
+
+
+
2. AXI4_Lite_Types.bsv
+
+
+
Definitions for AXI4_Lite bus types, M and S interfaces, connections
+between Ms and Ss, dummy M and S tie-offs, and transactors to provide
+higher-level FIFO-like interfaces to drive Ms and Ss.
+
+
+
Everything is parameterizd on width of address, data and user buses.
+
+
+
Note: some aspects of these definitions may seem a bit verbose and
+messy; that is not typical of BSV code, but is true here because it is
+meant to interface to hand-written Verilog, so we need to provide
+precise control on interface signal names and protocols that are
+required by the Verilog side. Pure BSV code can be an order of
+magnitude more compact.
+
+
+
Everything is parameterized on wd_addr, wd_data, wd_user.
+
+
+
+
+
3. AXI4_Lite_Fabric.bsv
+
+
+
+
+
+Note
+
+
+Needs bsc -aggressive-conditions
flag (else will deadlock).
+
+
+
+
+
+
Definition for interface and module for an num_M x num_S crossbar
+switch with AXI4-Lite interfaces.
+
+
+
This is also an example of how, within BSV code, we don’t worry about
+the details of AXI4-Lite signalling. We just instantiate the
+transactors defined in AXI4_Lite_Types.bsv, and then work only with
+simple, FIFO-like interfaces.
+
+
+
Everything is parameterized on num_M, num_S, wd_addr, wd_data,
+wd_user.
+
+
+
+
+
4. Clock-crossers, other transactors
+
+
+
+
5. Unit tests
+
+
+
There are some unit tests in:
+
+
+
+
bsc-contrib/testing/bsc.contrib/AMBA_Fabrics/AXI4_Lite/Test_*.bsv
+
+
+
+
The conventions for unit tests are described in more detail in the
+README in the parent directory
+(adoc ,html ).
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Libraries/AMBA_Fabrics/AXI4_Stream/AXI4_Stream.bsv b/Libraries/AMBA_Fabrics/AXI4_Stream/AXI4_Stream.bsv
index 3087585..933b090 100644
--- a/Libraries/AMBA_Fabrics/AXI4_Stream/AXI4_Stream.bsv
+++ b/Libraries/AMBA_Fabrics/AXI4_Stream/AXI4_Stream.bsv
@@ -11,7 +11,7 @@ import FIFOF :: *;
import Connectable :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Semi_FIFOF :: *;
import EdgeFIFOFs :: *;
@@ -303,477 +303,6 @@ module mkAXI4_Stream_S_Xactor (AXI4_Stream_S_Xactor_IFC #(wd_id, wd_dest, wd_dat
interface o_stream = to_FIFOF_O (f_data);
endmodule: mkAXI4_Stream_S_Xactor
-/*
-// ----------------------------------------------------------------
-// M transactor
-// This version uses crgs and regs instead of FIFOFs.
-// This uses 1/2 the resources, but introduces scheduling dependencies.
-
-module mkAXI4_M_Xactor_2 (AXI4_M_Xactor_IFC #(wd_id, wd_dest, wd_data, wd_user));
-
- // Each crg_full, rg_data pair below represents a 1-element fifo.
-
- Array #(Reg #(Bool)) crg_wr_addr_full <- mkCReg (3, False);
- Reg #(AXI4_Wr_Addr #(wd_id, wd_dest, wd_user)) rg_wr_addr <- mkRegU;
-
- Array #(Reg #(Bool)) crg_wr_data_full <- mkCReg (3, False);
- Reg #(AXI4_Wr_Data #(wd_id, wd_data, wd_user)) rg_wr_data <- mkRegU;
-
- Array #(Reg #(Bool)) crg_wr_resp_full <- mkCReg (3, False);
- Reg #(AXI4_Wr_Resp #(wd_id, wd_user)) rg_wr_resp <- mkRegU;
-
- Array #(Reg #(Bool)) crg_rd_addr_full <- mkCReg (3, False);
- Reg #(AXI4_Rd_Addr #(wd_id, wd_dest, wd_user)) rg_rd_addr <- mkRegU;
-
- Array #(Reg #(Bool)) crg_rd_data_full <- mkCReg (3, False);
- Reg #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) rg_rd_data <- mkRegU;
-
- // The following CReg port indexes specify the relative scheduling of:
- // {first,deq,notEmpty} {enq,notFull} clear
-
- // TODO: 'deq/enq/clear = 1/2/0' is unusual, but eliminates a
- // scheduling cycle in Piccolo's DCache. Normally should be 0/1/2.
-
- Integer port_deq = 1;
- Integer port_enq = 2;
- Integer port_clear = 0;
-
- // ----------------------------------------------------------------
- // INTERFACE
-
- method Action reset;
- crg_wr_addr_full [port_clear] <= False;
- crg_wr_data_full [port_clear] <= False;
- crg_wr_resp_full [port_clear] <= False;
- crg_rd_addr_full [port_clear] <= False;
- crg_rd_data_full [port_clear] <= False;
- endmethod
-
- // AXI side
- interface axi_side = interface AXI4_M_IFC;
- // Wr Addr channel
- method Bool m_awvalid = crg_wr_addr_full [port_deq];
- method Bit #(wd_id) m_awid = rg_wr_addr.awid;
- method Bit #(wd_dest) m_awaddr = rg_wr_addr.awaddr;
- method Bit #(8) m_awlen = rg_wr_addr.awlen;
- method AXI4_Size m_awsize = rg_wr_addr.awsize;
- method Bit #(2) m_awburst = rg_wr_addr.awburst;
- method Bit #(1) m_awlock = rg_wr_addr.awlock;
- method Bit #(4) m_awcache = rg_wr_addr.awcache;
- method Bit #(3) m_awprot = rg_wr_addr.awprot;
- method Bit #(4) m_awqos = rg_wr_addr.awqos;
- method Bit #(4) m_awregion = rg_wr_addr.awregion;
- method Bit #(wd_user) m_awuser = rg_wr_addr.awuser;
- method Action m_awready (Bool awready);
- if (crg_wr_addr_full [port_deq] && awready)
- crg_wr_addr_full [port_deq] <= False; // deq
- endmethod
-
- // Wr Data channel
- method Bool m_wvalid = crg_wr_data_full [port_deq];
- method Bit #(wd_id) m_wid = rg_wr_data.wid;
- method Bit #(wd_data) m_wdata = rg_wr_data.wdata;
- method Bit #(TDiv #(wd_data, 8)) m_wstrb = rg_wr_data.wstrb;
- method Bool m_wlast = rg_wr_data.wlast;
- method Bit #(wd_user) m_wuser = rg_wr_data.wuser;
- method Action m_wready (Bool wready);
- if (crg_wr_data_full [port_deq] && wready)
- crg_wr_data_full [port_deq] <= False;
- endmethod
-
- // Wr Response channel
- method Action m_bvalid (Bool bvalid,
- Bit #(wd_id) bid,
- Bit #(2) bresp,
- Bit #(wd_user) buser);
- if (bvalid && (! (crg_wr_resp_full [port_enq]))) begin
- crg_wr_resp_full [port_enq] <= True;
- rg_wr_resp <= AXI4_Wr_Resp {bid: bid,
- bresp: bresp,
- buser: buser};
- end
- endmethod
-
- method Bool m_bready;
- return (! (crg_wr_resp_full [port_enq]));
- endmethod
-
- // Rd Addr channel
- method Bool m_arvalid = crg_rd_addr_full [port_deq];
- method Bit #(wd_id) m_arid = rg_rd_addr.arid;
- method Bit #(wd_dest) m_araddr = rg_rd_addr.araddr;
- method Bit #(8) m_arlen = rg_rd_addr.arlen;
- method AXI4_Size m_arsize = rg_rd_addr.arsize;
- method Bit #(2) m_arburst = rg_rd_addr.arburst;
- method Bit #(1) m_arlock = rg_rd_addr.arlock;
- method Bit #(4) m_arcache = rg_rd_addr.arcache;
- method Bit #(3) m_arprot = rg_rd_addr.arprot;
- method Bit #(4) m_arqos = rg_rd_addr.arqos;
- method Bit #(4) m_arregion = rg_rd_addr.arregion;
- method Bit #(wd_user) m_aruser = rg_rd_addr.aruser;
- method Action m_arready (Bool arready);
- if (crg_rd_addr_full [port_deq] && arready)
- crg_rd_addr_full [port_deq] <= False; // deq
- endmethod
-
- // Rd Data channel
- method Action m_rvalid (Bool rvalid,
- Bit #(wd_id) rid,
- Bit #(wd_data) rdata,
- Bit #(2) rresp,
- Bool rlast,
- Bit #(wd_user) ruser);
- if (rvalid && (! (crg_rd_data_full [port_enq])))
- crg_rd_data_full [port_enq] <= True;
- rg_rd_data <= (AXI4_Rd_Data {rid: rid,
- rdata: rdata,
- rresp: rresp,
- rlast: rlast,
- ruser: ruser});
- endmethod
-
- method Bool m_rready;
- return (! (crg_rd_data_full [port_enq]));
- endmethod
-
- endinterface;
-
- // FIFOF side
- interface i_wr_addr = fn_crg_and_rg_to_FIFOF_I (crg_wr_addr_full [port_enq], rg_wr_addr);
- interface i_wr_data = fn_crg_and_rg_to_FIFOF_I (crg_wr_data_full [port_enq], rg_wr_data);
- interface o_wr_resp = fn_crg_and_rg_to_FIFOF_O (crg_wr_resp_full [port_deq], rg_wr_resp);
-
- interface i_rd_addr = fn_crg_and_rg_to_FIFOF_I (crg_rd_addr_full [port_enq], rg_rd_addr);
- interface o_rd_data = fn_crg_and_rg_to_FIFOF_O (crg_rd_data_full [port_deq], rg_rd_data);
-endmodule: mkAXI4_M_Xactor_2
-
-// ================================================================
-// S transactor interface
-
-interface AXI4_S_Xactor_IFC #(numeric type wd_id,
- numeric type wd_dest,
- numeric type wd_data,
- numeric type wd_user);
- method Action reset;
-
- // AXI side
- interface AXI4_S_IFC #(wd_id, wd_dest, wd_data, wd_user) axi_side;
-
- // FIFOF side
- interface FIFOF_O #(AXI4_Wr_Addr #(wd_id, wd_dest, wd_user)) o_wr_addr;
- interface FIFOF_O #(AXI4_Wr_Data #(wd_id, wd_data, wd_user)) o_wr_data;
- interface FIFOF_I #(AXI4_Wr_Resp #(wd_id, wd_user)) i_wr_resp;
-
- interface FIFOF_O #(AXI4_Rd_Addr #(wd_id, wd_dest, wd_user)) o_rd_addr;
- interface FIFOF_I #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) i_rd_data;
-endinterface: AXI4_S_Xactor_IFC
-
-// ----------------------------------------------------------------
-// S transactor
-// This version uses FIFOFs for total decoupling.
-
-module mkAXI4_S_Xactor (AXI4_S_Xactor_IFC #(wd_id, wd_dest, wd_data, wd_user));
-
- Bool unguarded = True;
- Bool guarded = False;
-
- // These FIFOs are guarded on BSV side, unguarded on AXI side
- FIFOF #(AXI4_Wr_Addr #(wd_id, wd_dest, wd_user)) f_wr_addr <- mkGFIFOF (unguarded, guarded);
- FIFOF #(AXI4_Wr_Data #(wd_id, wd_data, wd_user)) f_wr_data <- mkGFIFOF (unguarded, guarded);
- FIFOF #(AXI4_Wr_Resp #(wd_id, wd_user)) f_wr_resp <- mkGFIFOF (guarded, unguarded);
-
- FIFOF #(AXI4_Rd_Addr #(wd_id, wd_dest, wd_user)) f_rd_addr <- mkGFIFOF (unguarded, guarded);
- FIFOF #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) f_rd_data <- mkGFIFOF (guarded, unguarded);
-
- // ----------------------------------------------------------------
- // INTERFACE
-
- method Action reset;
- f_wr_addr.clear;
- f_wr_data.clear;
- f_wr_resp.clear;
- f_rd_addr.clear;
- f_rd_data.clear;
- endmethod
- // AXI side
- interface axi_side = interface AXI4_S_IFC;
- // Wr Addr channel
- method Action m_awvalid (Bool awvalid,
- Bit #(wd_id) awid,
- Bit #(wd_dest) awaddr,
- Bit #(8) awlen,
- AXI4_Size awsize,
- Bit #(2) awburst,
- Bit #(1) awlock,
- Bit #(4) awcache,
- Bit #(3) awprot,
- Bit #(4) awqos,
- Bit #(4) awregion,
- Bit #(wd_user) awuser);
- if (awvalid && f_wr_addr.notFull)
- f_wr_addr.enq (AXI4_Wr_Addr {awid: awid,
- awaddr: awaddr,
- awlen: awlen,
- awsize: awsize,
- awburst: awburst,
- awlock: awlock,
- awcache: awcache,
- awprot: awprot,
- awqos: awqos,
- awregion: awregion,
- awuser: awuser});
- endmethod
-
- method Bool m_awready;
- return f_wr_addr.notFull;
- endmethod
-
- // Wr Data channel
- method Action m_wvalid (Bool wvalid,
- Bit #(wd_id) wid,
- Bit #(wd_data) wdata,
- it #(TDiv #(wd_data, 8)) wstrb,
- Bool wlast,
- Bit #(wd_user) wuser);
- if (wvalid && f_wr_data.notFull)
- f_wr_data.enq (AXI4_Wr_Data {wid: wid,
- wdata: wdata,
- wstrb: wstrb,
- wlast: wlast,
- wuser: wuser});
- endmethod
-
- method Bool m_wready;
- return f_wr_data.notFull;
- endmethod
-
- // Wr Response channel
- method Bool m_bvalid = f_wr_resp.notEmpty;
- method Bit #(wd_id) m_bid = f_wr_resp.first.bid;
- method Bit #(2) m_bresp = f_wr_resp.first.bresp;
- method Bit #(wd_user) m_buser = f_wr_resp.first.buser;
- method Action m_bready (Bool bready);
- if (bready && f_wr_resp.notEmpty)
- f_wr_resp.deq;
- endmethod
-
- // Rd Addr channel
- method Action m_arvalid (Bool arvalid,
- Bit #(wd_id) arid,
- Bit #(wd_dest) araddr,
- Bit #(8) arlen,
- AXI4_Size arsize,
- Bit #(2) arburst,
- Bit #(1) arlock,
- Bit #(4) arcache,
- Bit #(3) arprot,
- Bit #(4) arqos,
- Bit #(4) arregion,
- Bit #(wd_user) aruser);
- if (arvalid && f_rd_addr.notFull)
- f_rd_addr.enq (AXI4_Rd_Addr {arid: arid,
- araddr: araddr,
- arlen: arlen,
- arsize: arsize,
- arburst: arburst,
- arlock: arlock,
- arcache: arcache,
- arprot: arprot,
- arqos: arqos,
- arregion: arregion,
- aruser: aruser});
- endmethod
-
- method Bool m_arready;
- return f_rd_addr.notFull;
- endmethod
-
- // Rd Data channel
- method Bool m_rvalid = f_rd_data.notEmpty;
- method Bit #(wd_id) m_rid = f_rd_data.first.rid;
- method Bit #(wd_data) m_rdata = f_rd_data.first.rdata;
- method Bit #(2) m_rresp = f_rd_data.first.rresp;
- method Bool m_rlast = f_rd_data.first.rlast;
- method Bit #(wd_user) m_ruser = f_rd_data.first.ruser;
- method Action m_rready (Bool rready);
- if (rready && f_rd_data.notEmpty)
- f_rd_data.deq;
- endmethod
- endinterface;
-
- // FIFOF side
- interface o_wr_addr = to_FIFOF_O (f_wr_addr);
- interface o_wr_data = to_FIFOF_O (f_wr_data);
- interface i_wr_resp = to_FIFOF_I (f_wr_resp);
-
- interface o_rd_addr = to_FIFOF_O (f_rd_addr);
- interface i_rd_data = to_FIFOF_I (f_rd_data);
-endmodule: mkAXI4_S_Xactor
-
-// ----------------------------------------------------------------
-// S transactor
-// This version uses crgs and regs instead of FIFOFs.
-// This uses 1/2 the resources, but introduces scheduling dependencies.
-
-module mkAXI4_S_Xactor_2 (AXI4_S_Xactor_IFC #(wd_id, wd_dest, wd_data, wd_user));
-
- // Each crg_full, rg_data pair below represents a 1-element fifo.
-
- // These FIFOs are guarded on BSV side, unguarded on AXI side
- Array #(Reg #(Bool)) crg_wr_addr_full <- mkCReg (3, False);
- Reg #(AXI4_Wr_Addr #(wd_id, wd_dest, wd_user)) rg_wr_addr <- mkRegU;
-
- Array #(Reg #(Bool)) crg_wr_data_full <- mkCReg (3, False);
- Reg #(AXI4_Wr_Data #(wd_id, wd_data, wd_user)) rg_wr_data <- mkRegU;
-
- Array #(Reg #(Bool)) crg_wr_resp_full <- mkCReg (3, False);
- Reg #(AXI4_Wr_Resp #(wd_id, wd_user)) rg_wr_resp <- mkRegU;
-
- Array #(Reg #(Bool)) crg_rd_addr_full <- mkCReg (3, False);
- Reg #(AXI4_Rd_Addr #(wd_id, wd_dest, wd_user)) rg_rd_addr <- mkRegU;
-
- Array #(Reg #(Bool)) crg_rd_data_full <- mkCReg (3, False);
- Reg #(AXI4_Rd_Data #(wd_id, wd_data, wd_user)) rg_rd_data <- mkRegU;
-
- // The following CReg port indexes specify the relative scheduling of:
- // {first,deq,notEmpty} {enq,notFull} clear
- Integer port_deq = 0;
- Integer port_enq = 1;
- Integer port_clear = 2;
-
- // ----------------------------------------------------------------
- // INTERFACE
-
- method Action reset;
- crg_wr_addr_full [port_clear] <= False;
- crg_wr_data_full [port_clear] <= False;
- crg_wr_resp_full [port_clear] <= False;
- crg_rd_addr_full [port_clear] <= False;
- crg_rd_data_full [port_clear] <= False;
- endmethod
-
- // AXI side
- interface axi_side = interface AXI4_S_IFC;
- // Wr Addr channel
- method Action m_awvalid (Bool awvalid,
- Bit #(wd_id) awid,
- Bit #(wd_dest) awaddr,
- Bit #(8) awlen,
- AXI4_Size awsize,
- Bit #(2) awburst,
- Bit #(1) awlock,
- Bit #(4) awcache,
- Bit #(3) awprot,
- Bit #(4) awqos,
- Bit #(4) awregion,
- Bit #(wd_user) awuser);
-
- if (awvalid && (! crg_wr_addr_full [port_enq])) begin
- crg_wr_addr_full [port_enq] <= True; // enq
- rg_wr_addr <= AXI4_Wr_Addr {awid: awid,
- awaddr: awaddr,
- awlen: awlen,
- awsize: awsize,
- awburst: awburst,
- awlock: awlock,
- awcache: awcache,
- awprot: awprot,
- awqos: awqos,
- awregion: awregion,
- awuser: awuser};
- end
- endmethod
-
- method Bool m_awready;
- return (! crg_wr_addr_full [port_enq]);
- endmethod
-
- // Wr Data channel
- method Action m_wvalid (Bool wvalid,
- Bit #(wd_id) wid,
- Bit #(wd_data) wdata,
- Bit #(TDiv #(wd_data, 8)) wstrb,
- Bool wlast,
- Bit #(wd_user) wuser);
- if (wvalid && (! crg_wr_data_full [port_enq])) begin
- crg_wr_data_full [port_enq] <= True; // enq
- rg_wr_data <= AXI4_Wr_Data {wid: wid,
- wdata: wdata,
- wstrb: wstrb,
- wlast: wlast,
- wuser: wuser};
- end
- endmethod
-
- method Bool m_wready;
- return (! crg_wr_data_full [port_enq]);
- endmethod
-
- // Wr Response channel
- method Bool m_bvalid = crg_wr_resp_full [port_deq];
- method Bit #(wd_id) m_bid = rg_wr_resp.bid;
- method Bit #(2) m_bresp = rg_wr_resp.bresp;
- method Bit #(wd_user) m_buser = rg_wr_resp.buser;
- method Action m_bready (Bool bready);
- if (bready && crg_wr_resp_full [port_deq])
- crg_wr_resp_full [port_deq] <= False; // deq
- endmethod
-
- // Rd Addr channel
- method Action m_arvalid (Bool arvalid,
- Bit #(wd_id) arid,
- Bit #(wd_dest) araddr,
- Bit #(8) arlen,
- AXI4_Size arsize,
- Bit #(2) arburst,
- Bit #(1) arlock,
- Bit #(4) arcache,
- Bit #(3) arprot,
- Bit #(4) arqos,
- Bit #(4) arregion,
- Bit #(wd_user) aruser);
- if (arvalid && (! crg_rd_addr_full [port_enq])) begin
- crg_rd_addr_full [port_enq] <= True; // enq
- rg_rd_addr <= AXI4_Rd_Addr {arid: arid,
- araddr: araddr,
- arlen: arlen,
- arsize: arsize,
- arburst: arburst,
- arlock: arlock,
- arcache: arcache,
- arprot: arprot,
- arqos: arqos,
- arregion: arregion,
- aruser: aruser};
- end
- endmethod
-
- method Bool m_arready;
- return (! crg_rd_addr_full [port_enq]);
- endmethod
-
- // Rd Data channel
- method Bool m_rvalid = crg_rd_data_full [port_deq];
- method Bit #(wd_id) m_rid = rg_rd_data.rid;
- method Bit #(wd_data) m_rdata = rg_rd_data.rdata;
- method Bit #(2) m_rresp = rg_rd_data.rresp;
- method Bool m_rlast = rg_rd_data.rlast;
- method Bit #(wd_user) m_ruser = rg_rd_data.ruser;
- method Action m_rready (Bool rready);
- if (rready && crg_rd_data_full [port_deq])
- crg_rd_data_full [port_deq] <= False; // deq
- endmethod
- endinterface;
-
- // FIFOF side
- interface o_wr_addr = fn_crg_and_rg_to_FIFOF_O (crg_wr_addr_full [port_deq], rg_wr_addr);
- interface o_wr_data = fn_crg_and_rg_to_FIFOF_O (crg_wr_data_full [port_deq], rg_wr_data);
- interface i_wr_resp = fn_crg_and_rg_to_FIFOF_I (crg_wr_resp_full [port_enq], rg_wr_resp);
-
- interface o_rd_addr = fn_crg_and_rg_to_FIFOF_O (crg_rd_addr_full [port_deq], rg_rd_addr);
- interface i_rd_data = fn_crg_and_rg_to_FIFOF_I (crg_rd_data_full [port_enq], rg_rd_data);
-endmodule: mkAXI4_S_Xactor_2
-*/
// ================================================================
endpackage
diff --git a/Libraries/AMBA_Fabrics/AXI4_Stream/README_AXI4S.adoc b/Libraries/AMBA_Fabrics/AXI4_Stream/README_AXI4S.adoc
new file mode 100644
index 0000000..d8e61bb
--- /dev/null
+++ b/Libraries/AMBA_Fabrics/AXI4_Stream/README_AXI4S.adoc
@@ -0,0 +1,58 @@
+= About `bsc-contrib/Libraries/AMBA_Fabrics/AXI4_Stream`
+:revnumber: v1.00
+:revdate: 2024-12-07
+:sectnums:
+:imagesdir: ../Doc/Figs
+:toc:
+:toclevels: 3
+:toc-title: Contents
+:keywords: Bluespec, B-Lang, BSV, BH, AMBA, ARM AXI, AXI4, AXI4-Lite, AXI4-Stream
+
+// ================================================================
+
+Copyright (C) 2017-2023 Bluespec, Inc. All Rights Reserved +
+Copyright (C) 2024-2025 B-Lang.org. All Rights Reserved
+
+SPDX-License-Identifier: BSD-3-Clause
+
+// ================================================================
+
+Pleae see README in parent directory
+(link:../README_AMBA_Fabrics.adoc[adoc],link:../README_AMBA_Fabrics.html[html])
+for general introduction and about compiling/building/testing.
+
+This directory describes AXI4-Stream facilities.
+
+These source codes may import other `bsv-contrib` libraries; be sure
+they are visible in your _bsc_ compiler paths:
+
+ bsc-contrib/Libraries/AMBA_Fabrics/Utils/
+ bsc-contrib/Libraries/Misc/
+
+// ================================================================
+
+image::IMG_Under_Construction.png[align="left", width=100]
+
+The packages in this directory can be used as-is, but are expected to
+be restructured to be more like their AXI4 siblings (more consistent
+naming, clean separation of B-Lang-style and RTL-style, etc.)
+
+This documentation will be updated after that restructuring.
+
+// ================================================================
+== `AXI4_Stream.bsv`
+
+(... To be written ...)
+
+// ================================================================
+== Unit tests
+
+Unit tests will be found in:
+
+ bsc-contrib/testing/bsc.contrib/AMBA_Fabrics/AXI4_Stream/Test_*.bsv
+
+The conventions for unit tests are described in more detail in the
+README in the parent directory
+(link:../README_AMBA_Fabrics.adoc[adoc],link:../README_AMBA_Fabrics.html[html]).
+
+// ================================================================
diff --git a/Libraries/AMBA_Fabrics/AXI4_Stream/README_AXI4S.html b/Libraries/AMBA_Fabrics/AXI4_Stream/README_AXI4S.html
new file mode 100644
index 0000000..0350f0f
--- /dev/null
+++ b/Libraries/AMBA_Fabrics/AXI4_Stream/README_AXI4S.html
@@ -0,0 +1,530 @@
+
+
+
+
+
+
+
+
+About bsc-contrib/Libraries/AMBA_Fabrics/AXI4_Stream
+
+
+
+
+
+
+
+
+
+
Copyright © 2017-2023 Bluespec, Inc. All Rights Reserved
+Copyright © 2024-2025 B-Lang.org. All Rights Reserved
+
+
+
SPDX-License-Identifier: BSD-3-Clause
+
+
+
Pleae see README in parent directory
+(adoc ,html )
+for general introduction and about compiling/building/testing.
+
+
+
This directory describes AXI4-Stream facilities.
+
+
+
These source codes may import other bsv-contrib
libraries; be sure
+they are visible in your bsc compiler paths:
+
+
+
+
bsc-contrib/Libraries/AMBA_Fabrics/Utils/
+bsc-contrib/Libraries/Misc/
+
+
+
+
+
+
+
+
+
The packages in this directory can be used as-is, but are expected to
+be restructured to be more like their AXI4 siblings (more consistent
+naming, clean separation of B-Lang-style and RTL-style, etc.)
+
+
+
This documentation will be updated after that restructuring.
+
+
+
+
+
+
2. Unit tests
+
+
+
Unit tests will be found in:
+
+
+
+
bsc-contrib/testing/bsc.contrib/AMBA_Fabrics/AXI4_Stream/Test_*.bsv
+
+
+
+
The conventions for unit tests are described in more detail in the
+README in the parent directory
+(adoc ,html ).
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Libraries/AMBA_Fabrics/Adapters/AXI4L_S_to_AXI4_M_Adapter.bsv b/Libraries/AMBA_Fabrics/Adapters/AXI4L_S_to_AXI4_M_Adapter.bsv
index e13c275..4db5422 100644
--- a/Libraries/AMBA_Fabrics/Adapters/AXI4L_S_to_AXI4_M_Adapter.bsv
+++ b/Libraries/AMBA_Fabrics/Adapters/AXI4L_S_to_AXI4_M_Adapter.bsv
@@ -19,7 +19,7 @@ import FIFOF :: *;
import SpecialFIFOs :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Cur_Cycle :: *;
import GetPut_Aux :: *;
@@ -27,9 +27,10 @@ import GetPut_Aux :: *;
// ================================================================
// Project imports
-import Semi_FIFOF :: *;
-import AXI4L_Types :: *;
-import AXI4_Types :: *;
+import Semi_FIFOF :: *;
+import AXI4L_Types :: *;
+import AXI4_Types :: *;
+import AXI4_BSV_RTL :: *;
// ================================================================
// The interface for the adapter module
@@ -56,10 +57,10 @@ interface AXI4L_S_to_AXI4_M_Adapter_IFC #(numeric type wd_addr_AXI4L_S,
wd_user_AXI4L_S) ifc_AXI4L_S;
// AXI4 M side
- interface AXI4_M_IFC #(wd_id_AXI4_M,
- wd_addr_AXI4_M,
- wd_data_AXI4_M,
- wd_user_AXI4_M) ifc_AXI4_M;
+ interface AXI4_RTL_M_IFC #(wd_id_AXI4_M,
+ wd_addr_AXI4_M,
+ wd_data_AXI4_M,
+ wd_user_AXI4_M) ifc_AXI4_M;
endinterface
// ================================================================
@@ -96,10 +97,10 @@ module mkAXI4L_S_to_AXI4_M_Adapter (AXI4L_S_to_AXI4_M_Adapter_IFC #(wd_addr_AXI4
wd_user_AXI4L_S) xactor_AXI4L_S <- mkAXI4L_S_Xactor;
// AXI4 M transactor
- AXI4_M_Xactor_IFC #(wd_id_AXI4_M,
- wd_addr_AXI4_M,
- wd_data_AXI4_M,
- wd_user_AXI4_M) xactor_AXI4_M <- mkAXI4_M_Xactor;
+ AXI4_BSV_to_RTL_IFC #(wd_id_AXI4_M,
+ wd_addr_AXI4_M,
+ wd_data_AXI4_M,
+ wd_user_AXI4_M) xactor_AXI4_M <- mkAXI4_BSV_to_RTL;
// ================================================================
// BEHAVIOR
@@ -107,26 +108,26 @@ module mkAXI4L_S_to_AXI4_M_Adapter (AXI4L_S_to_AXI4_M_Adapter_IFC #(wd_addr_AXI4
// ----------------------------------------------------------------
// Write requests (Write Address and Write Data channels)
- rule rl_wr_addr_data;
- let awaddr_AXI4L <- pop_o (xactor_AXI4L_S.o_wr_addr);
- let wdata_AXI4L <- pop_o (xactor_AXI4L_S.o_wr_data);
+ rule rl_AW_W;
+ let aw_AXI4L <- pop_o (xactor_AXI4L_S.o_wr_addr);
+ let w_AXI4L <- pop_o (xactor_AXI4L_S.o_wr_data);
Bit #(wd_id_AXI4_M) id_AXI4 = 1;
- Bit #(wd_addr_AXI4_M) addr_AXI4 = zeroExtend (awaddr_AXI4L.awaddr);
- Bit #(wd_user_AXI4_M) user_AXI4 = zeroExtend (awaddr_AXI4L.awuser);
-
- AXI4_Wr_Addr #(wd_id_AXI4_M, wd_addr_AXI4_M, wd_user_AXI4_M)
- awaddr_AXI4 = AXI4_Wr_Addr {awid: id_AXI4,
- awaddr: addr_AXI4,
- awlen: 0, // AXI4 encoding for "1 beat"
- awsize: axsize_4,
- awburst: axburst_fixed,
- awlock: axlock_normal,
- awcache: awcache_dev_nonbuf,
- awprot: awaddr_AXI4L.awprot,
- awqos: 0,
- awregion: 0,
- awuser: user_AXI4};
+ Bit #(wd_addr_AXI4_M) addr_AXI4 = zeroExtend (aw_AXI4L.awaddr);
+ Bit #(wd_user_AXI4_M) user_AXI4 = zeroExtend (aw_AXI4L.awuser);
+
+ AXI4_AW #(wd_id_AXI4_M, wd_addr_AXI4_M, wd_user_AXI4_M)
+ aw_AXI4 = AXI4_AW {awid: id_AXI4,
+ awaddr: addr_AXI4,
+ awlen: 0, // AXI4 encoding for "1 beat"
+ awsize: axsize_4,
+ awburst: axburst_fixed,
+ awlock: axlock_normal,
+ awcache: awcache_dev_nonbuf,
+ awprot: aw_AXI4L.awprot,
+ awqos: 0,
+ awregion: 0,
+ awuser: user_AXI4};
// Lane-align wdata for the wider AXI4
@@ -135,47 +136,47 @@ module mkAXI4L_S_to_AXI4_M_Adapter (AXI4L_S_to_AXI4_M_Adapter_IFC #(wd_addr_AXI4
Integer hi = valueOf (addr_index_M_t) - 1;
Integer lo = valueOf (addr_index_S_t);
- Bit #(index_width_t) index = awaddr_AXI4L.awaddr [hi:lo];
- v_data [index] = wdata_AXI4L.wdata;
- v_strb [index] = wdata_AXI4L.wstrb;
+ Bit #(index_width_t) index = aw_AXI4L.awaddr [hi:lo];
+ v_data [index] = w_AXI4L.wdata;
+ v_strb [index] = w_AXI4L.wstrb;
- AXI4_Wr_Data #(wd_data_AXI4_M, wd_user_AXI4_M)
- wdata_AXI4 = AXI4_Wr_Data {wdata: pack (v_data),
- wstrb: pack (v_strb),
- wlast: True,
- wuser: user_AXI4};
+ AXI4_W #(wd_data_AXI4_M, wd_user_AXI4_M)
+ w_AXI4 = AXI4_W {wdata: pack (v_data),
+ wstrb: pack (v_strb),
+ wlast: True,
+ wuser: user_AXI4};
- xactor_AXI4_M.i_wr_addr.enq (awaddr_AXI4);
- xactor_AXI4_M.i_wr_data.enq (wdata_AXI4);
+ xactor_AXI4_M.ifc_S.i_AW.enq (aw_AXI4);
+ xactor_AXI4_M.ifc_S.i_W.enq (w_AXI4);
// Debugging
if (verbosity > 0) begin
- $display ("%0d: %m.rl_wr_addr_data:", cur_cycle);
- $display (" ", fshow (awaddr_AXI4L));
- $display (" ==> ", fshow (awaddr_AXI4));
- $display (" ", fshow (wdata_AXI4));
- $display (" ==> ", fshow (wdata_AXI4));
+ $display ("%0d: rl_AW_W:", cur_cycle);
+ $display (" ", fshow (aw_AXI4L));
+ $display (" ==> ", fshow (aw_AXI4));
+ $display (" ", fshow (w_AXI4));
+ $display (" ==> ", fshow (w_AXI4));
end
endrule
// ----------------------------------------------------------------
- // Write responses (Write Data channel)
+ // B channel (write responses)
- rule rl_wr_resp;
- let wr_resp_AXI4 <- pop_o (xactor_AXI4_M.o_wr_resp);
+ rule rl_B;
+ let b_AXI4 <- pop_o (xactor_AXI4_M.ifc_S.o_B);
- Bit #(wd_user_AXI4L_S) user = truncate (wr_resp_AXI4.buser);
+ Bit #(wd_user_AXI4L_S) user = truncate (b_AXI4.buser);
AXI4L_Wr_Resp #(wd_user_AXI4L_S)
- wr_resp_AXI4L = AXI4L_Wr_Resp {bresp: unpack (wr_resp_AXI4.bresp),
- buser: user};
- xactor_AXI4L_S.i_wr_resp.enq (wr_resp_AXI4L);
+ b_AXI4L = AXI4L_Wr_Resp {bresp: unpack (b_AXI4.bresp),
+ buser: user};
+ xactor_AXI4L_S.i_wr_resp.enq (b_AXI4L);
// Debugging
if (verbosity > 0) begin
- $display ("%0d: %m.rl_wr_resp:", cur_cycle);
- $display (" ", fshow (wr_resp_AXI4));
- $display (" ==> ", fshow (wr_resp_AXI4L));
+ $display ("%0d: rl_B:", cur_cycle);
+ $display (" ", fshow (b_AXI4));
+ $display (" ==> ", fshow (b_AXI4L));
end
endrule
@@ -188,69 +189,69 @@ module mkAXI4L_S_to_AXI4_M_Adapter (AXI4L_S_to_AXI4_M_Adapter_IFC #(wd_addr_AXI4
// ----------------
- rule rl_rd_addr;
- let araddr_AXI4L <- pop_o (xactor_AXI4L_S.o_rd_addr);
+ rule rl_AR;
+ let ar_AXI4L <- pop_o (xactor_AXI4L_S.o_rd_addr);
Bit #(wd_id_AXI4_M) id_AXI4 = 1;
- Bit #(wd_addr_AXI4_M) addr_AXI4 = zeroExtend (araddr_AXI4L.araddr);
- Bit #(wd_user_AXI4_M) user_AXI4 = zeroExtend (araddr_AXI4L.aruser);
-
- AXI4_Rd_Addr #(wd_id_AXI4_M, wd_addr_AXI4_M, wd_user_AXI4_M)
- araddr_AXI4 = AXI4_Rd_Addr {arid: id_AXI4,
- araddr: addr_AXI4,
- arlen: 0, // AXI4 encoding for "1 beat"
- arsize: axsize_4,
- arburst: axburst_fixed,
- arlock: axlock_normal,
- arcache: arcache_dev_nonbuf,
- arprot: araddr_AXI4L.arprot,
- arqos: 0,
- arregion: 0,
- aruser: user_AXI4};
-
- xactor_AXI4_M.i_rd_addr.enq (araddr_AXI4);
+ Bit #(wd_addr_AXI4_M) addr_AXI4 = zeroExtend (ar_AXI4L.araddr);
+ Bit #(wd_user_AXI4_M) user_AXI4 = zeroExtend (ar_AXI4L.aruser);
+
+ AXI4_AR #(wd_id_AXI4_M, wd_addr_AXI4_M, wd_user_AXI4_M)
+ ar_AXI4 = AXI4_AR {arid: id_AXI4,
+ araddr: addr_AXI4,
+ arlen: 0, // AXI4 encoding for "1 beat"
+ arsize: axsize_4,
+ arburst: axburst_fixed,
+ arlock: axlock_normal,
+ arcache: arcache_dev_nonbuf,
+ arprot: ar_AXI4L.arprot,
+ arqos: 0,
+ arregion: 0,
+ aruser: user_AXI4};
+
+ xactor_AXI4_M.ifc_S.i_AR.enq (ar_AXI4);
// Remember addrs so returned data can properly lane-aligned
- f_rd_addrs.enq (araddr_AXI4L.araddr);
+ f_rd_addrs.enq (ar_AXI4L.araddr);
// Debugging
if (verbosity > 0) begin
- $display ("%0d: %m.rl_rd_addr:", cur_cycle);
- $display (" ", fshow (araddr_AXI4L));
- $display (" ==> ", fshow (araddr_AXI4));
+ $display ("%0d: rl_AR:", cur_cycle);
+ $display (" ", fshow (ar_AXI4L));
+ $display (" ==> ", fshow (ar_AXI4));
end
endrule
// ----------------------------------------------------------------
// Read responses (Read Data channel)
- rule rl_rd_data;
- let rd_data_AXI4 <- pop_o (xactor_AXI4_M.o_rd_data);
+ rule rl_R;
+ let r_AXI4 <- pop_o (xactor_AXI4_M.ifc_S.o_R);
let addr_AXI4L <- pop (f_rd_addrs);
// Lane-align rdata for the narrower AXI4L
- Vector #(expansion_t, Bit #(wd_data_AXI4L_S)) v_data = unpack (rd_data_AXI4.rdata);
+ Vector #(expansion_t, Bit #(wd_data_AXI4L_S)) v_data = unpack (r_AXI4.rdata);
Integer hi = valueOf (addr_index_M_t) - 1;
Integer lo = valueOf (addr_index_S_t);
Bit #(index_width_t) index = addr_AXI4L [hi:lo];
Bit #(wd_data_AXI4L_S) rdata_AXI4L = v_data [index];
- Bit #(wd_user_AXI4L_S) ruser_AXI4L = truncate (rd_data_AXI4.ruser);
+ Bit #(wd_user_AXI4L_S) ruser_AXI4L = truncate (r_AXI4.ruser);
AXI4L_Rd_Data #(wd_data_AXI4L_S, wd_user_AXI4L_S)
- rd_data_AXI4L = AXI4L_Rd_Data {rresp: unpack (rd_data_AXI4.rresp),
- rdata: rdata_AXI4L,
- ruser: ruser_AXI4L };
+ r_AXI4L = AXI4L_Rd_Data {rresp: unpack (r_AXI4.rresp),
+ rdata: rdata_AXI4L,
+ ruser: ruser_AXI4L };
- xactor_AXI4L_S.i_rd_data.enq (rd_data_AXI4L);
+ xactor_AXI4L_S.i_rd_data.enq (r_AXI4L);
// Debugging
if (verbosity > 0) begin
- $display ("%0d: %m.rl_rd_data:", cur_cycle);
- $display (" ", fshow (rd_data_AXI4));
- $display (" ==> ", fshow (rd_data_AXI4L));
+ $display ("%0d: rl_R:", cur_cycle);
+ $display (" ", fshow (r_AXI4));
+ $display (" ==> ", fshow (r_AXI4L));
end
endrule
@@ -258,7 +259,7 @@ module mkAXI4L_S_to_AXI4_M_Adapter (AXI4L_S_to_AXI4_M_Adapter_IFC #(wd_addr_AXI4
// INTERFACE
interface ifc_AXI4L_S = xactor_AXI4L_S.axi_side;
- interface ifc_AXI4_M = xactor_AXI4_M .axi_side;
+ interface ifc_AXI4_M = xactor_AXI4_M .rtl_M;
endmodule
// ================================================================
diff --git a/Libraries/AMBA_Fabrics/Adapters/AXI4_AXI4L_Adapters.bsv b/Libraries/AMBA_Fabrics/Adapters/AXI4_AXI4L_Adapters.bsv
index 213a4cd..8c28714 100644
--- a/Libraries/AMBA_Fabrics/Adapters/AXI4_AXI4L_Adapters.bsv
+++ b/Libraries/AMBA_Fabrics/Adapters/AXI4_AXI4L_Adapters.bsv
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 Bluespec, Inc. All Rights Reserved
+// Copyright (c) 2019-2024 Bluespec, Inc. All Rights Reserved
//
// SPDX-License-Identifier: BSD-3-Clause
@@ -21,7 +21,7 @@ package AXI4_AXI4L_Adapters;
export
-fn_AXI4L_M_IFC_to_AXI4_M_IFC;
+fn_AXI4L_M_IFC_to_AXI4_RTL_M_IFC;
// ================================================================
// BSV library imports
@@ -30,7 +30,7 @@ import FIFOF :: *;
import Connectable :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
import Semi_FIFOF :: *;
import EdgeFIFOFs :: *;
@@ -38,8 +38,9 @@ import EdgeFIFOFs :: *;
// ================================================================
// Project imports
-import AXI4L_Types :: *;
-import AXI4_Types :: *;
+import AXI4L_Types :: *;
+import AXI4_Types :: *;
+import AXI4_BSV_RTL :: *;
// ================================================================
// Compute the encoding of AWSIZE/ARSIZE
@@ -55,12 +56,12 @@ endfunction
// ================================================================
-function AXI4_M_IFC #(wd_id, wd_addr, wd_data, wd_user)
- fn_AXI4L_M_IFC_to_AXI4_M_IFC
+function AXI4_RTL_M_IFC #(wd_id, wd_addr, wd_data, wd_user)
+ fn_AXI4L_M_IFC_to_AXI4_RTL_M_IFC
(AXI4L_M_IFC #(wd_addr, wd_data, wd_user) axi4L);
return
- interface AXI4_M_IFC;
+ interface AXI4_RTL_M_IFC;
// ----------------
// Wr Addr channel
@@ -151,8 +152,8 @@ endfunction
// Transformer to get AXI4L S interface from an AXI4 S interface
function AXI4L_S_IFC #(wd_addr, wd_data, wd_user)
- fv_AXI4_S_IFC_to_AXI4L_S_IFC
- (AXI4_S_IFC #(wd_id, wd_addr, wd_data, wd_user) axi4);
+ fv_AXI4_RTL_S_IFC_to_AXI4L_S_IFC
+ (AXI4_RTL_S_IFC #(wd_id, wd_addr, wd_data, wd_user) axi4);
return
interface AXI4L_S_IFC;
diff --git a/Libraries/AMBA_Fabrics/Adapters/README_AXI_Adapters.adoc b/Libraries/AMBA_Fabrics/Adapters/README_AXI_Adapters.adoc
new file mode 100644
index 0000000..b4c3ac8
--- /dev/null
+++ b/Libraries/AMBA_Fabrics/Adapters/README_AXI_Adapters.adoc
@@ -0,0 +1,71 @@
+= About `bsc-contrib/Libraries/AMBA_Fabrics/Adapters`
+:revnumber: v1.00
+:revdate: 2024-12-07
+:sectnums:
+:imagesdir: ../Doc/Figs
+:toc:
+:toclevels: 3
+:toc-title: Contents
+:keywords: Bluespec, B-Lang, BSV, BH, AMBA, ARM AXI, AXI4, AXI4-Lite, AXI4-Stream
+
+// ================================================================
+
+Copyright (C) 2017-2023 Bluespec, Inc. All Rights Reserved +
+Copyright (C) 2024-2025 B-Lang.org. All Rights Reserved
+
+SPDX-License-Identifier: BSD-3-Clause
+
+// ================================================================
+
+Pleae see README in parent directory
+(link:../README_AMBA_Fabrics.adoc[adoc],link:../README_AMBA_Fabrics.html[html])
+for general introduction and about compiling/building/testing.
+
+This directory describes adapters between AXI4 and AXI4-Lite.
+
+These source codes may import other `bsv-contrib` libraries; be sure
+they are visible in your _bsc_ compiler paths:
+
+ bsc-contrib/Libraries/AMBA_Fabrics/Utils/
+ bsc-contrib/Libraries/Misc/
+
+These source codes may import other `bsv-contrib` libraries; be sure
+they are visible in your _bsc_ compiler paths:
+
+ bsc-contrib/Libraries/AMBA_Fabrics/Utils/
+ bsc-contrib/Libraries/Misc/
+
+// ================================================================
+
+image::IMG_Under_Construction.png[align="left", width=100]
+
+The packages in this directory can be used as-is, but are expected to
+be restructured to be more like their AXI4 siblings (more consistent
+naming, clean separation of B-Lang-style and RTL-style, etc.)
+
+This documentation will be updated after that restructuring.
+
+// ================================================================
+== `AXI4L_S_to_AXI4_M_Adapter.bsv`
+
+A module to bridge from an AXI4-Lite S to an AXI4 M.
+
+(... To be written ...)
+
+// ================================================================
+== `AXI4_AXI4_Lite_Adapters.bsv`
+
+(... To be written ...)
+
+// ================================================================
+== Unit tests
+
+Unit tests will be found in:
+
+ bsc-contrib/testing/bsc.contrib/AMBA_Fabrics/Adapters/Test_*.bsv
+
+The conventions for unit tests are described in more detail in the
+README in the parent directory
+(link:../README_AMBA_Fabrics.adoc[adoc],link:../README_AMBA_Fabrics.html[html]).
+
+// ================================================================
diff --git a/Libraries/AMBA_Fabrics/Adapters/README_AXI_Adapters.html b/Libraries/AMBA_Fabrics/Adapters/README_AXI_Adapters.html
new file mode 100644
index 0000000..dfbb502
--- /dev/null
+++ b/Libraries/AMBA_Fabrics/Adapters/README_AXI_Adapters.html
@@ -0,0 +1,552 @@
+
+
+
+
+
+
+
+
+About bsc-contrib/Libraries/AMBA_Fabrics/Adapters
+
+
+
+
+
+
+
+
+
+
Copyright © 2017-2023 Bluespec, Inc. All Rights Reserved
+Copyright © 2024-2025 B-Lang.org. All Rights Reserved
+
+
+
SPDX-License-Identifier: BSD-3-Clause
+
+
+
Pleae see README in parent directory
+(adoc ,html )
+for general introduction and about compiling/building/testing.
+
+
+
This directory describes adapters between AXI4 and AXI4-Lite.
+
+
+
These source codes may import other bsv-contrib
libraries; be sure
+they are visible in your bsc compiler paths:
+
+
+
+
bsc-contrib/Libraries/AMBA_Fabrics/Utils/
+bsc-contrib/Libraries/Misc/
+
+
+
+
These source codes may import other bsv-contrib
libraries; be sure
+they are visible in your bsc compiler paths:
+
+
+
+
bsc-contrib/Libraries/AMBA_Fabrics/Utils/
+bsc-contrib/Libraries/Misc/
+
+
+
+
+
+
+
+
+
The packages in this directory can be used as-is, but are expected to
+be restructured to be more like their AXI4 siblings (more consistent
+naming, clean separation of B-Lang-style and RTL-style, etc.)
+
+
+
This documentation will be updated after that restructuring.
+
+
+
+
+
1. AXI4L_S_to_AXI4_M_Adapter.bsv
+
+
+
A module to bridge from an AXI4-Lite S to an AXI4 M.
+
+
+
+
+
+
2. AXI4_AXI4_Lite_Adapters.bsv
+
+
+
+
3. Unit tests
+
+
+
Unit tests will be found in:
+
+
+
+
bsc-contrib/testing/bsc.contrib/AMBA_Fabrics/Adapters/Test_*.bsv
+
+
+
+
The conventions for unit tests are described in more detail in the
+README in the parent directory
+(adoc ,html ).
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Libraries/AMBA_Fabrics/Doc/Figs/IMG_Under_Construction.png b/Libraries/AMBA_Fabrics/Doc/Figs/IMG_Under_Construction.png
new file mode 100644
index 0000000..9b4a346
Binary files /dev/null and b/Libraries/AMBA_Fabrics/Doc/Figs/IMG_Under_Construction.png differ
diff --git a/Libraries/AMBA_Fabrics/Doc/Figs/RSN_2024-12-07.000.00.png b/Libraries/AMBA_Fabrics/Doc/Figs/RSN_2024-12-07.000.00.png
new file mode 100644
index 0000000..eb5785e
Binary files /dev/null and b/Libraries/AMBA_Fabrics/Doc/Figs/RSN_2024-12-07.000.00.png differ
diff --git a/Libraries/AMBA_Fabrics/Makefile b/Libraries/AMBA_Fabrics/Makefile
index 3cd8328..76e66a7 100644
--- a/Libraries/AMBA_Fabrics/Makefile
+++ b/Libraries/AMBA_Fabrics/Makefile
@@ -1,11 +1,10 @@
-
# Enumerate all sub-dirs for recursive traversal
BUILD_ORDER = \
+ Utils \
AXI4 \
AXI4_Lite \
AXI4_Stream \
Adapters \
- Utils \
.PHONY: all
all: install
@@ -13,4 +12,3 @@ all: install
.PHONY: install clean full_clean
install clean full_clean:
$(foreach dir, $(BUILD_ORDER), $(MAKE) -C $(dir) $@ &&) true
-
diff --git a/Libraries/AMBA_Fabrics/README_AMBA_Fabrics.adoc b/Libraries/AMBA_Fabrics/README_AMBA_Fabrics.adoc
new file mode 100644
index 0000000..fad447e
--- /dev/null
+++ b/Libraries/AMBA_Fabrics/README_AMBA_Fabrics.adoc
@@ -0,0 +1,191 @@
+= About `bsc-contrib/Libraries/AMBA_Fabrics`
+:revnumber: v1.00
+:revdate: 2024-12-07
+:sectnums:
+:imagesdir: Doc/Figs
+:toc:
+:toclevels: 3
+:toc-title: Contents
+:keywords: Bluespec, B-Lang, BSV, BH, AMBA, ARM AXI, AXI4, AXI4-Lite, AXI4-Stream
+
+// ================================================================
+
+Copyright (C) 2017-2023 Bluespec, Inc. All Rights Reserved +
+Copyright (C) 2024-2025 B-Lang.org. All Rights Reserved
+
+SPDX-License-Identifier: BSD-3-Clause
+
+NOTE: AMBA, ARM AXI, AXI4, AXI4-Lite, AXI4-Stream are specifications
+by the company _ARM Limited_. The specs are open (no license required)
+and can be downloaded from
+https://www.arm.com/architecture/system-architectures/amba/amba-specifications[ARM's website].
+
+// ================================================================
+== Introduction
+
+This directory contains libraries for various AMBA resources (AXI4,
+AXI4-Lite, AXI4_Stream) including type definitions, cross-bar
+switches, connectors, clock-crossers, and edge-transactors to connect
+the B-Lang world to existing RTL (e.g., external AMBA IP).
+
+The source code is written in a B-Lang (BSV/BH/Bluespec Classic). The
+free and open-source _bsc_ compiler tool can be used to generate
+synthesizable Verilog (https://github.com/B-Lang-org/bsc[]).
+
+The origins of this code date at least as far back as 2018 inside
+https://bluespec.com[Bluespec, Inc.] The codes have evolved over time
+and various versions have been used and are still in use in numerous
+RISC-V CPUs and SoC designs at several universities and companies,
+including in commercialized ASICs. The codes were moved to this
+repository in November-December 2024.
+
+CAUTION: In moving these codes to this repository, they are being
+ further cleaned up, so there may be a short period of
+ instability. The cleanups to the `AXI4/` directory have been
+ completed; cleanups to `AXI4_Lite` and `AXI4_Stream`
+ directories are ongoing. We will remove this CAUTION when
+ that work is completed.
+
+// ----------------------------------------------------------------
+=== Terminology:
+
+Since 2021 ARM has replaced the terms "Master" and "Slave" by
+"Manager" and "Subordinate", respectively; in this library we just use
+"M" and "S" for these concepts. An M sends requests (on AW, W, AR)
+and recieves responses (on B, R). An S recieves requests (on AW, W,
+AR) and sends responses (on B, R).
+
+In this library, identifiers use `AXI4` for AXI4 itsef, `AXI4L` for
+AXI4-Lite, and `AXI4S` for AXI4-Stream, three distinct parts of the
+AMBA AXI spec.
+
+// ================================================================
+== Principles
+
+=== Background on ARM AMBA AXI
+
+AXI4 and AXI4-Lite are specifications of buses, each with five
+independent "channels" (AW, W, B, AR, R).
+
+ARM's specs are described at the signal (RTL) level). Each channel
+has multiple sub-buses (e.g., awaddr, awsize, arlen, bresp, rdata,
+...) and is unidirectional (all sub-buses carry data in the same
+direction). Each channel is independently flow-controlled with a
+traditional handshake on two additional wires called `ready` (receiver
+to sender) and `valid` (sender-to-receiver). Please see "RTL view" in
+diagram below.
+
+For a write-transaction, the sender sends information on AW (address
+etc.) and W (data etc.), and receives a response on B (status etc.).
+For a read-transaction, the sender sends information on AR (address
+etc.) and receives a response on R (status, data, etc.).
+
+Please see ARM's specs for full details of the channels, sub-buses,
+ready-valid handshaking, and detailed semantics of transactions.
+
+=== B-Lang view vs. RTL view
+
+In BSV/BH/Bluespec Classic the natural way to do unidirectional
+flow-controlled communication is with FIFOs. Further, groups of
+related data values are naturally represented as "structs". Further,
+complex interfaces can contain sub-interfaces.
+
+Thus, AMBA AXI is represented in BSV as shown in "B-Lang view" in the
+diagram below. Each of the groups AW, W, B, AR, R is defined as a
+`struct` with fields corresponding to the sub-buses of the group.
+Each struct is communicated as a unit from sender to receiver with
+FIFO buffers. An M interface (`AXI4_M_IFC`) contains five
+sub-interfaces, each corresponding to one end of a FIFO ("enqueue" end
+or "dequeue" end). An S interface (`AXI4_S_IFC`) is the dual, using
+the opposite ends of FIFOs. A one-line `mkConnection` is sufficient
+to connect two such interfaces together.
+
+image::RSN_2024-12-07.000.00.png[align="left"]
+
+As long as one is working within a B-Lang, that is the complete story
+on bus representation. However, if it is necessary to connect to
+RTL-level AXI IP---Verilog/SystemVerilog buses, sub-buses, and
+ready-valid handshaking--- we provide two "transactors"
+`mkAXI4_BSV_to_RTL` (BSV M to RTL S) and `mkAXI4_RTL_to_BSV` (RTL M to
+BSV S) to perform the conversions. Each transactor has a B-Lang-view
+interface on one side and an RTL-view interface on the other side.
+These transactors are written in BSV, but when compiled by the _bsc_
+compiler, will produced RTL signals and logic with the correct signal
+names and ready-valid handshaking. Within B-Lang, a one-line
+`mkConnection` is sufficient to connect `AXI4_RTL_M_IFC` and
+`AXI4_RTL_S_IFC` interfaces.
+
+CAUTION: In these AXI4 resources, WRAP bursts are not supported.
+ Where bursts are supported, it generally assumes INCR
+ (incrementing) bursts or FIXED.
+
+// ================================================================
+== Directory structure and links to details
+
+The source tree for this library is:
+
+ bsc-contrib_RSN/
+ └── Libraries/
+ └── AMBA_Fabrics/
+ ├── README_AMBA_Fabrics.txt
+ ├── AXI4/
+ ├── AXI4_Lite/
+ ├── AXI4_Stream/
+ ├── Adapters/
+ ├── Utils/
+ └── Makefile
+
+The code in `AXI4` is a substantially cleaned up version of existing
+codes that have been used in a number of projects. The cleanup
+involved consistent naming, clean separation of B-Lang-view and
+RTL-view, externalizing of buffering choices, etc.
+
+The code in `AXI4_Lite`, `AXI4_Stream`, and `Adapters` are also
+snapshots of existing codes that have been used in a number of
+projects (and so they can be used, as-is), but they have not yet gone
+through the analogous cleanup, which is a work-in-progress.
+
+Please see READMEs in each directory for specifics of directory
+contents:
+
+* AXI4 (link:AXI4/README_AXI4.adoc[adoc], link:AXI4/README_AXI4.html[html]),
+* AXI4_Lite (link:AXI4_Lite/README_AXI4L.adoc[adoc], link:AXI4_Lite/README_AXI4L.html[html]),
+* AXI4_Stream (link:AXI4_Stream/README_AXI4S.adoc[adoc], link:AXI4_Stream/README_AXI4S.html[html]),
+* Adapters (link:Adapters/README_AXI_Adapters.adoc[adoc], link:Adapters/README_AXI_Adapters.html[html]).
+
+// ================================================================
+== Compiling/Building/Testing
+
+You can compile these libraries from source using the _bsc_ compiler
+as part of your own compile/build flow, by making sure the files you
+need are in located in your _bsc_ compiler search path.
+
+NOTE: Some of these files require the `-aggressive-conditions` flag (else may deadlock).
+
+The Makefiles in this library can be used if you wish to pre-compile
+these files using the _bsc_ compiler, by doing:
+
+ $ make install
+
+This will invoke _bsc_ and place the resulting `.bo` files in:
+
+ bsc-contrib/inst/lib/Libraries/AMBA_Fabrics/...
+
+There are several "unit tests" for this library located in:
+
+ bsc-contrib_RSN/
+ └── testing/
+ └── bsc.contrib/
+ ├── AMBA_Fabrics_AXI4/
+ ├── AMBA_Fabrics_AXI4_Lite/
+ ...
+
+Each directory, `Makefile`, script fragment (`foo.exp` file) and
+expected output (`foo.out.expected` file) is set up for the CI
+(Continuous Integration) flow that is run repeatedly for the _bsc_
+compiler. Please see the "How to Contribute to bsc-contrib" document
+(link:../../doc/How_to_Contribute.adoc[adoc],
+link:../../doc/How_to_Contribute.html[html]) for details on this
+setup.
+
+// ================================================================
diff --git a/Libraries/AMBA_Fabrics/README_AMBA_Fabrics.html b/Libraries/AMBA_Fabrics/README_AMBA_Fabrics.html
new file mode 100644
index 0000000..0d05d94
--- /dev/null
+++ b/Libraries/AMBA_Fabrics/README_AMBA_Fabrics.html
@@ -0,0 +1,754 @@
+
+
+
+
+
+
+
+
+About bsc-contrib/Libraries/AMBA_Fabrics
+
+
+
+
+
+
+
+
+
+
Copyright © 2017-2023 Bluespec, Inc. All Rights Reserved
+Copyright © 2024-2025 B-Lang.org. All Rights Reserved
+
+
+
SPDX-License-Identifier: BSD-3-Clause
+
+
+
+
+
+Note
+
+
+AMBA, ARM AXI, AXI4, AXI4-Lite, AXI4-Stream are specifications
+by the company ARM Limited . The specs are open (no license required)
+and can be downloaded from
+ARM’s website .
+
+
+
+
+
+
+
+
1. Introduction
+
+
+
This directory contains libraries for various AMBA resources (AXI4,
+AXI4-Lite, AXI4_Stream) including type definitions, cross-bar
+switches, connectors, clock-crossers, and edge-transactors to connect
+the B-Lang world to existing RTL (e.g., external AMBA IP).
+
+
+
+
The origins of this code date at least as far back as 2018 inside
+Bluespec, Inc. The codes have evolved over time
+and various versions have been used and are still in use in numerous
+RISC-V CPUs and SoC designs at several universities and companies,
+including in commercialized ASICs. The codes were moved to this
+repository in November-December 2024.
+
+
+
+
+
+Caution
+
+
+In moving these codes to this repository, they are being
+ further cleaned up, so there may be a short period of
+ instability. The cleanups to the AXI4/
directory have been
+ completed; cleanups to AXI4_Lite
and AXI4_Stream
+ directories are ongoing. We will remove this CAUTION when
+ that work is completed.
+
+
+
+
+
+
1.1. Terminology:
+
+
Since 2021 ARM has replaced the terms "Master" and "Slave" by
+"Manager" and "Subordinate", respectively; in this library we just use
+"M" and "S" for these concepts. An M sends requests (on AW, W, AR)
+and recieves responses (on B, R). An S recieves requests (on AW, W,
+AR) and sends responses (on B, R).
+
+
+
In this library, identifiers use AXI4
for AXI4 itsef, AXI4L
for
+AXI4-Lite, and AXI4S
for AXI4-Stream, three distinct parts of the
+AMBA AXI spec.
+
+
+
+
+
+
2. Principles
+
+
+
2.1. Background on ARM AMBA AXI
+
+
AXI4 and AXI4-Lite are specifications of buses, each with five
+independent "channels" (AW, W, B, AR, R).
+
+
+
ARM’s specs are described at the signal (RTL) level). Each channel
+has multiple sub-buses (e.g., awaddr, awsize, arlen, bresp, rdata,
+…) and is unidirectional (all sub-buses carry data in the same
+direction). Each channel is independently flow-controlled with a
+traditional handshake on two additional wires called ready
(receiver
+to sender) and valid
(sender-to-receiver). Please see "RTL view" in
+diagram below.
+
+
+
For a write-transaction, the sender sends information on AW (address
+etc.) and W (data etc.), and receives a response on B (status etc.).
+For a read-transaction, the sender sends information on AR (address
+etc.) and receives a response on R (status, data, etc.).
+
+
+
Please see ARM’s specs for full details of the channels, sub-buses,
+ready-valid handshaking, and detailed semantics of transactions.
+
+
+
+
2.2. B-Lang view vs. RTL view
+
+
In BSV/BH/Bluespec Classic the natural way to do unidirectional
+flow-controlled communication is with FIFOs. Further, groups of
+related data values are naturally represented as "structs". Further,
+complex interfaces can contain sub-interfaces.
+
+
+
Thus, AMBA AXI is represented in BSV as shown in "B-Lang view" in the
+diagram below. Each of the groups AW, W, B, AR, R is defined as a
+struct
with fields corresponding to the sub-buses of the group.
+Each struct is communicated as a unit from sender to receiver with
+FIFO buffers. An M interface (AXI4_M_IFC
) contains five
+sub-interfaces, each corresponding to one end of a FIFO ("enqueue" end
+or "dequeue" end). An S interface (AXI4_S_IFC
) is the dual, using
+the opposite ends of FIFOs. A one-line mkConnection
is sufficient
+to connect two such interfaces together.
+
+
+
+
+
+
+
+
As long as one is working within a B-Lang, that is the complete story
+on bus representation. However, if it is necessary to connect to
+RTL-level AXI IP---Verilog/SystemVerilog buses, sub-buses, and
+ready-valid handshaking--- we provide two "transactors"
+mkAXI4_BSV_to_RTL
(BSV M to RTL S) and mkAXI4_RTL_to_BSV
(RTL M to
+BSV S) to perform the conversions. Each transactor has a B-Lang-view
+interface on one side and an RTL-view interface on the other side.
+These transactors are written in BSV, but when compiled by the bsc
+compiler, will produced RTL signals and logic with the correct signal
+names and ready-valid handshaking. Within B-Lang, a one-line
+mkConnection
is sufficient to connect AXI4_RTL_M_IFC
and
+AXI4_RTL_S_IFC
interfaces.
+
+
+
+
+
+Caution
+
+
+In these AXI4 resources, WRAP bursts are not supported.
+ Where bursts are supported, it generally assumes INCR
+ (incrementing) bursts or FIXED.
+
+
+
+
+
+
+
+
+
3. Directory structure and links to details
+
+
+
The source tree for this library is:
+
+
+
+
bsc-contrib_RSN/
+└── Libraries/
+ └── AMBA_Fabrics/
+ ├── README_AMBA_Fabrics.txt
+ ├── AXI4/
+ ├── AXI4_Lite/
+ ├── AXI4_Stream/
+ ├── Adapters/
+ ├── Utils/
+ └── Makefile
+
+
+
+
The code in AXI4
is a substantially cleaned up version of existing
+codes that have been used in a number of projects. The cleanup
+involved consistent naming, clean separation of B-Lang-view and
+RTL-view, externalizing of buffering choices, etc.
+
+
+
The code in AXI4_Lite
, AXI4_Stream
, and Adapters
are also
+snapshots of existing codes that have been used in a number of
+projects (and so they can be used, as-is), but they have not yet gone
+through the analogous cleanup, which is a work-in-progress.
+
+
+
Please see READMEs in each directory for specifics of directory
+contents:
+
+
+
+
+
+
4. Compiling/Building/Testing
+
+
+
You can compile these libraries from source using the bsc compiler
+as part of your own compile/build flow, by making sure the files you
+need are in located in your bsc compiler search path.
+
+
+
+
+
+Note
+
+
+Some of these files require the -aggressive-conditions
flag (else may deadlock).
+
+
+
+
+
+
The Makefiles in this library can be used if you wish to pre-compile
+these files using the bsc compiler, by doing:
+
+
+
+
This will invoke bsc and place the resulting .bo
files in:
+
+
+
+
bsc-contrib/inst/lib/Libraries/AMBA_Fabrics/...
+
+
+
+
There are several "unit tests" for this library located in:
+
+
+
+
bsc-contrib_RSN/
+└── testing/
+ └── bsc.contrib/
+ ├── AMBA_Fabrics_AXI4/
+ ├── AMBA_Fabrics_AXI4_Lite/
+ ...
+
+
+
+
Each directory, Makefile
, script fragment (foo.exp
file) and
+expected output (foo.out.expected
file) is set up for the CI
+(Continuous Integration) flow that is run repeatedly for the bsc
+compiler. Please see the "How to Contribute to bsc-contrib" document
+(adoc ,
+html ) for details on this
+setup.
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Libraries/AMBA_Fabrics/README_AMBA_Fabrics.txt b/Libraries/AMBA_Fabrics/README_AMBA_Fabrics.txt
deleted file mode 100644
index 0c7050f..0000000
--- a/Libraries/AMBA_Fabrics/README_AMBA_Fabrics.txt
+++ /dev/null
@@ -1,174 +0,0 @@
-Copyright (c) 2017-2024 Bluespec, Inc. All Rights Reserved
-
-SPDX-License-Identifier: BSD-3-Clause
-
-This directory contains B-Lang libraries for various AMBA resources
-(AXI4, AXI4-Lite, AXI4_Stream) including type definitions, cross-bar
-switches, connectors, clock-crossers, transactors to convert from
-BSV-internal connection idioms (FIFOs) to AMBA connection signalling,
-etc.
-
-The source code is written in Bluespec BSV. The `bsc` compiler tool
-can be used to generate synthesizable Verilog.
-
-Some of these components have been used in numerous RISC-V CPUs and
-SoC designs at Bluespec, Inc.
-
-CAUTION: When using resources from this library, please examine the
- source code and check that it is fit for your purpose.
-
- The components here were added piecemeal, in an _ad hoc_ way,
- over a number of years, each component serving some specific
- immediate, narrow need. The whole library could do with a
- ground-up rewrite, including filling in many obvious missing
- components.
-
-CAUTION: In these resources, where bursts are supported, it generally
- assumes INCR (incrementing) bursts, not FIXED or WRAP.
-
-// ================================================================
-Terminology:
-
-Since 2021 ARM has replaced the terms "Master" and "Slave" by
-"Manager" and "Subordinate", respectively; in this library we adopt
-this convention. Identifiers and file names use the abbreviated `M`
-and `S`.
-
-In this library, identifiers use `AXI4` for AXI4 itsef and `AXI4L` for
-AXI4-Lite.
-
-// ================================================================
-The source tree for this library is:
-
- bsc-contrib_RSN/
- ├── Libraries
- │ ├── AMBA_Fabrics
- │ │ ├── AXI4
- │ │ ├── AXI4_Lite
- │ │ ├── AXI4_Stream
- │ │ ├── Adapters
- │ │ └── Utils
- ...
- └── testing
- └── bsc.contrib
- ├── AMBA_Fabrics_AXI4
- ├── AMBA_Fabrics_AXI4_Lite
- ...
-
-What follows is a quick tour.
-
-// ----------------
-AXI4_Lite/
-
- All these have a 'user' field which is not standard in AXI4-Lite
- (same as 'user' in AXI4), which can be left unused, and/or set to
- width 0.
-
- AXI4_Lite_Types.bsv
-
- Definitions for AXI4_Lite bus types, M and S interfaces,
- connections between Ms and Ss, dummy M and S tie-offs, and
- transactors to provide higher-level FIFO-like interfaces to
- drive Ms and Ss.
-
- Everything is parameterizd on width of address, data and user buses.
-
- Note: some aspects of these definitions may seem a bit verbose
- and messy; that is not typical of BSV code, but is true here
- because it is meant to interface to hand-written Verilog, so
- we need to provide precise control on interface signal names
- and protocols that are required by the Verilog side. Pure BSV
- code can be an order of magnitude more compact.
-
- Everything is parameterized on wd_addr, wd_data, wd_user.
-
-AXI4_Lite_Fabric.bsv
-
- Definition for interface and module for an num_M x num_S
- crossbar switch with AXI4-Lite interfaces.
-
- This is also an example of how, within BSV code, we don't
- worry about the details of AXI4-Lite signalling. We just
- instantiate the transactors defined in AXI4_Lite_Types.bsv,
- and then work only with simple, FIFO-like interfaces.
-
- Everything is parameterized on num_M, num_S, wd_addr, wd_data,
- wd_user.
-
-... clock-crossers, other transactors ...
-
-// ----------------
-AXI4/
-
-AXI4_Types.bsv
-
-Definitions for AXI4 bus types, M and S interfaces, connections
-between Ms and Ss, dummy M and S tie-offs, and transactors to provide
-higher-level FIFO-like interfaces to drive Ms and Ss.
-
-Everything is parameterized on wd_id, wd_addr, wd_data, wd_user.
-
-Note: some aspects of these definitions may seem a bit verbose and
-messy; that is not typical of BSV code, but is true here because it is
-meant to interface to hand-written Verilog, so we need to provide
-precise control on interface signal names and protocols that are
-required by the Verilog side. Pure BSV code can be an order of
-magnitude more compact.
-
-AXI4_Fabric.bsv
-
-Definition for interface and module for an num_M x num_S crossbar
-switch with AXI4 interfaces.
-
-This is also an example of how, within BSV code, we don't worry about
-the details of AXI4-Lite signalling. We just instantiate the
-transactors defined in AXI4_Lite_Types.bsv, and then work only with
-simple, FIFO-like interfaces.
-
-Everything is parameterized on num_M, num_S, wd_id, wd_addr, wd_data,
-wd_user.
-
-AXI4_Deburster.bsv
-
-A module that converts a slave that does not support AXI4 bursts into
-a slave that does support bursts.
-
-... clock-crossers, other transactors
-
-// ----------------
-Adapters/
-
-AXI4L_S_to_AXI4_M_Adapter.bsv
-
-A module to bridge from an AXI4L S to an AXI4 M.
-
-AXI4_AXI4_Lite_Adapters.bsv
-
-// ================================================================
-Dependencies
-
-Some of these source codes import BSV resources in a sibling directory
-
- bsc-contrib/Libraries/Misc/
-
-// ================================================================
-Build-and-install
-
-Compiling, Building and Testing
-
-These are libraries, so you will normally be compiling selected files
-from here within some other project that uses these libraries.
-
-In `AXI4/Unit_Test/` and `AXI4_Lite/Unit_Test/` the source codes and
-Makefiles show examples of instantiating fabrics in testbenches and
-executing them.
-
-The Makefiles are set up to build both Bluesim and Verilator
-executables. In each case, the Makefile specifies two steps:
-compiling BSV source, and then linking into an executable.
-
-In the Verilator case, the compile step generates Verilog from BSV
-source. This Verilog can be used as Verilog AMBA IP in other Verilog
-or SystemVerilog projects.
-
-// ================================================================
diff --git a/Libraries/AMBA_Fabrics/AXI4/AXI_SyncBuffer.bsv b/Libraries/AMBA_Fabrics/Utils/AXIx_SyncBuffer.bsv
similarity index 72%
rename from Libraries/AMBA_Fabrics/AXI4/AXI_SyncBuffer.bsv
rename to Libraries/AMBA_Fabrics/Utils/AXIx_SyncBuffer.bsv
index 007b391..439ea6b 100644
--- a/Libraries/AMBA_Fabrics/AXI4/AXI_SyncBuffer.bsv
+++ b/Libraries/AMBA_Fabrics/Utils/AXIx_SyncBuffer.bsv
@@ -1,17 +1,16 @@
-// Copyright (c) 2021-2022 Bluespec, Inc. All Rights Reserved
-// Author: Rishiyur S. Nikhil
-//
+// Copyright (c) 2021-2024 Bluespec, Inc. All Rights Reserved
+
// SPDX-License-Identifier: BSD-3-Clause
-package AXI_SyncBuffer;
+package AXIx_SyncBuffer;
// ================================================================
+// This package can be used for both AXI4 and AXI4L.
// This package defines a clock-domain-crossing buffer for an AXI bus
-// (parameterized, so can be used for AXI4 and AXI4 Lite).
-// The interfaces are FIFOF-like (not raw AXI4 signals).
-// The module merely contains 5 SyncFIFOs for each of the 5 AXI4 or
-// AXI4 Lite channels
+// The interfaces are FIFOF-like (not RTL-level AMBA signals).
+// The module merely contains 5 standard SyncFIFOs for each of the 5
+// AXI4 or AXI4 Lite channels.
// ================================================================
// Bluespec library imports
@@ -20,9 +19,8 @@ import Clocks :: *;
import Connectable :: *;
// ----------------
-// BSV additional libs
+// Bluespec misc. libs
-import Cur_Cycle :: *;
import GetPut_Aux :: *;
import Semi_FIFOF :: *;
@@ -32,9 +30,18 @@ import Semi_FIFOF :: *;
// -- none
// ================================================================
-// The interface for the fabric module
+// The AXIx_SyncBuffer interface.
+// Note: AXIx (not AXI4 or AXI4L) because it can be used for both
+
+interface AXIx_SyncBuffer_IFC #(type aw, type w, type b, type ar, type r);
+ interface AXIx_S_IFC #(aw, w, b, ar, r) from_M;
+ interface AXIx_M_IFC #(aw, w, b, ar, r) to_S;
+endinterface
+
+// ----------------
+// The interface for the SyncBuffer
-interface AXI_M_IFC #(type aw, type w, type b, type ar, type r);
+interface AXIx_M_IFC #(type aw, type w, type b, type ar, type r);
interface FIFOF_O #(aw) o_aw;
interface FIFOF_O #(w) o_w;
interface FIFOF_I #(b) i_b;
@@ -42,7 +49,7 @@ interface AXI_M_IFC #(type aw, type w, type b, type ar, type r);
interface FIFOF_I #(r) i_r;
endinterface
-interface AXI_S_IFC #(type aw, type w, type b, type ar, type r);
+interface AXIx_S_IFC #(type aw, type w, type b, type ar, type r);
interface FIFOF_I #(aw) i_aw;
interface FIFOF_I #(w) i_w;
interface FIFOF_O #(b) o_b;
@@ -50,11 +57,11 @@ interface AXI_S_IFC #(type aw, type w, type b, type ar, type r);
interface FIFOF_O #(r) o_r;
endinterface
-instance Connectable #(AXI_M_IFC #(aw, w, b, ar, r),
- AXI_S_IFC #(aw, w, b, ar, r));
+instance Connectable #(AXIx_M_IFC #(aw, w, b, ar, r),
+ AXIx_S_IFC #(aw, w, b, ar, r));
- module mkConnection #(AXI_M_IFC #(aw, w, b, ar, r) m,
- AXI_S_IFC #(aw, w, b, ar, r) s) (Empty);
+ module mkConnection #(AXIx_M_IFC #(aw, w, b, ar, r) m,
+ AXIx_S_IFC #(aw, w, b, ar, r) s) (Empty);
mkConnection (m.o_aw, s.i_aw);
mkConnection (m.o_w, s.i_w);
mkConnection (m.i_b, s.o_b);
@@ -63,22 +70,14 @@ instance Connectable #(AXI_M_IFC #(aw, w, b, ar, r),
endmodule
endinstance
-// ================================================================
-// The SyncBuffer interface
-
-interface AXI_SyncBuffer_IFC #(type aw, type w, type b, type ar, type r);
- interface AXI_S_IFC #(aw, w, b, ar, r) from_M;
- interface AXI_M_IFC #(aw, w, b, ar, r) to_S;
-endinterface
-
// ================================================================
// The SyncBuffer module
-// Implements an AXI (AXI4 or AXI4 Lite) clock-crossing
+// Implements an AXIx (AXI4 or AXI4 Lite) clock-crossing
-module mkAXI_SyncBuffer #(Integer depth,
+module mkAXIx_SyncBuffer #(Integer depth,
Clock sClkIn, Reset sRstIn,
Clock dClkIn, Reset dRstIn)
- (AXI_SyncBuffer_IFC #(aw, w, b, ar, r))
+ (AXIx_SyncBuffer_IFC #(aw, w, b, ar, r))
provisos (Bits #(aw, _size_aw_t),
Bits #(w, _size_w_t),
Bits #(b, _size_b_t),
@@ -113,7 +112,7 @@ module mkAXI_SyncBuffer #(Integer depth,
// ----------------------------------------------------------------
// INTERFACE
- interface from_M = interface AXI_S_IFC;
+ interface from_M = interface AXIx_S_IFC;
interface FIFOF_I i_aw = syncFIFO_to_FIFOF_I (f_aw);
interface FIFOF_I i_w = syncFIFO_to_FIFOF_I (f_w);
interface FIFOF_O o_b = syncFIFO_to_FIFOF_O (f_b);
@@ -121,7 +120,7 @@ module mkAXI_SyncBuffer #(Integer depth,
interface FIFOF_O o_r = syncFIFO_to_FIFOF_O (f_r);
endinterface;
- interface to_S = interface AXI_M_IFC;
+ interface to_S = interface AXIx_M_IFC;
interface FIFOF_O o_aw = syncFIFO_to_FIFOF_O (f_aw);
interface FIFOF_O o_w = syncFIFO_to_FIFOF_O (f_w);
interface FIFOF_I i_b = syncFIFO_to_FIFOF_I (f_b);
diff --git a/Libraries/AMBA_Fabrics/Utils/Makefile b/Libraries/AMBA_Fabrics/Utils/Makefile
index 6f6654f..77387d2 100644
--- a/Libraries/AMBA_Fabrics/Utils/Makefile
+++ b/Libraries/AMBA_Fabrics/Utils/Makefile
@@ -8,9 +8,14 @@ LIBNAME=AMBA_Fabrics/Utils
# and defines the install target
include ../../common.mk
+# Requires files in Misc in Utils
+BSCFLAGS += -p $(BUILDDIR)/../../Misc:+
+BSCFLAGS += -p $(BUILDDIR)/../Utils:+
+
.PHONY: build
build:
$(BSC) -u $(BSCFLAGS) ByteLane.bsv
+ $(BSC) -u $(BSCFLAGS) AXIx_SyncBuffer.bsv
.PHONY: clean full_clean
clean full_clean:
diff --git a/Libraries/Misc/Cur_Cycle.bsv b/Libraries/Misc/Cur_Cycle.bsv
index 5f96131..d98a2ad 100644
--- a/Libraries/Misc/Cur_Cycle.bsv
+++ b/Libraries/Misc/Cur_Cycle.bsv
@@ -34,7 +34,6 @@ ActionValue #(Bit #(32)) cur_cycle = actionvalue
function Action fa_debug_show_location (Integer verbosity);
action
if (verbosity != 0) begin
- $display (" %m");
$write (" %0d: ", cur_cycle);
end
endaction
diff --git a/doc/How_to_Contribute.adoc b/doc/How_to_Contribute.adoc
index b66ff81..e689dd4 100644
--- a/doc/How_to_Contribute.adoc
+++ b/doc/How_to_Contribute.adoc
@@ -1,13 +1,13 @@
= How to Contribute to `bsc-contrib`
:revnumber: v1.03
-:revdate: 2024-11-21
+:revdate: 2024-12-09
:sectnums:
// ================================================================
Let's assume you want to contribute a new library `MyContrib`. All
your B-Lang (BSV/BH) sources and documentation should be placed in a
-new sub-dir:
+new sub-directory:
bsc-contrib/Libraries/MyContrib/
@@ -15,7 +15,7 @@ If your BSV/BH code imports any Verilog, it should be placed in:
bsc-contrib/Verilog/
-If you also have unit-tests, they should be in a new sub-dir:
+If you also have unit tests, they should be in a new sub-directory:
bsc-contrib/testing/bsc.contrib/Unit_Test_MyContrib
@@ -31,12 +31,13 @@ Request (PR).
We suggest the following "flow":
-* On GitHub, create a FORK of the original `bsc-contrib` repo, under your own account.
+* On GitHub, create a FORK of the original `bsc-contrib` repository,
+ under your own account.
* Clone your FORK to your work area (laptop, desktop, ...).
* Create a new BRANCH in your clone of your FORK.
* In this new BRANCH (in your clone of your FORK), prepare your
contribution, including formatting, copyrights, licenses,
- build-and-install Makefiles and optional unit-tests. See the
+ build-and-install Makefiles and optional unit tests. See the
sections below for details.
* Commit your BRANCH.
@@ -46,7 +47,7 @@ We suggest the following "flow":
final commit on top of the most recent `bsc-contrib` commit.
* Push the commit from your clone up to your FORK.
-* From your FORK, create a PR for the original `bsc-contrib` repo.
+* From your FORK, create a PR for the original `bsc-contrib` repository.
// ================================================================
== Source text formatting
@@ -70,7 +71,7 @@ desired Copyright and License text. Example:
// SPDX-License-Identifier: BSD-3-Clause
You are responsible for specifying your preferred copyright and
-license text (but please remember that this is a public repo;
+license text (but please remember that this is a public repository;
everything here is expected to be free and open-source; anything here
should be freely usable in commercial products).
@@ -91,24 +92,25 @@ AsciiDoctor (`.adoc`) are automatically rendered by GitHub.
// ================================================================
== Makefiles for building and installing
-`make all` at the top level descends recursively into all sub-dirs of
-`Libraries` and `Verilog`. In a leaf-level library dir the Makefile
-contains a `build` target to compile source file(s) that are in that
-dir. The corresponding object files get copied into the installation
-directory (default `bsc-contrib/inst`). You can also specify other
-files to be copied (include files, config files, ...).
+`make all` at the top level descends recursively into all
+sub-directories of `Libraries` and `Verilog`. In a leaf-level library
+directory the `Makefile` contains a `build` target to compile source
+file(s) that are in that directory. The corresponding object files
+get copied into the installation directory (default
+`bsc-contrib/inst`). You can also specify other files to be copied
+(include files, config files, ...).
-If you added any files to the `Verilog/` dir, add those filenames to
-the `VERI_FILES` list in the `Verilog/Makefile`.
+If you added any files to the `Verilog/` directory, add those
+filenames to the `VERI_FILES` list in the `Verilog/Makefile`.
The top-level `make all` is performed for installation, but is also
repeated automatically during CI (continuous integration) to check
that it succeeds.
-NOTE: In the `Library` sub-dirs, this just compiles sources, it does
- not build executables. See separate "Unit Tests" section for
- building unit-test executables and running them. Those are also
- performed by CI.
+NOTE: In the `Library` sub-directories, this just compiles sources, it
+ does not build executables. See separate "Unit Tests" section
+ for building unit test executables and running them. Those are
+ also performed by CI.
// ----------------------------------------------------------------
@@ -121,9 +123,9 @@ In the existing
add `MyContrib` to the `BUILD_ORDER` list in order to include your
contribution into the recursive descent.
-If `Libraries/MyContrib/` has sub-dirs, repeat the recursive pattern
-of `Libraries/Makefile` to enable recursive descent into each sub-dir,
-as needed. Example:
+If `Libraries/MyContrib/` has sub-directories, repeat the recursive
+pattern of `Libraries/Makefile` to enable recursive descent into each
+sub-directory, as needed. Example:
Libraries/AMBA_TLM2/Makefile
@@ -153,9 +155,9 @@ your copy (clone of fork) of `bsc-contrib`:
$ cd bsc-contrib // my clone of my fork
$ make all
-This should run the `make install` action on the whole repo, including
-compiling your sources in your newly added `MyContrib`, and installing
-the corresponding object files in:
+This should run the `make install` action on the whole repository,
+including compiling your sources in your newly added `MyContrib`, and
+installing the corresponding object files in:
bsc-contrib/inst/lib/Libraries/MyContrib/
@@ -166,29 +168,34 @@ You can optionally add unit tests for your library source files; these
unit tests are run automatically and repeatedly as part of CI
(Continuous Integration).
-NOTE: `bsc-contrib` 's unit-testing is performed as part of the main
+NOTE: `bsc-contrib` 's unit testing is performed as part of the main
`bsc` compiler's testing of standard libraries, using the same
- infrastructure. The infrastructure has more ways to configure
- testing than described in this section; please see the `bsc`
- repo for more details (https://github.com/B-Lang-org/bsc).
-
-Add your unit tests to `bsc-contrib/testing/bsc.contrib/`. You can
-study any of the existing unit tests in that directory for guidance.
+ infrastructure. The infrastructure has many more ways to
+ configure testing than the brief description here; please see
+ `testsuite/README.md` in the `bsc` repository for more details
+ (https://github.com/B-Lang-org/bsc).
+
+Add your unit tests to `bsc-contrib/testing/bsc.contrib/`. For
+guidance, you can study any of the existing unit tests in that
+directory or in `testsuite/` in the `bsc` compiler repository.
Briefly:
-* Add a sub-dir for a new set of unit-tests for the new library (it
- can have sub-dirs for more detailed structure):
+* Add a sub-directory for a new set of unit tests for the new library
+ (it can have sub-directories for more detailed structure):
bsc-contrib/testing/bsc.contrib/MyContrib/
-* In this dir:
+* In this directory:
+
+** There should be a `Makefile` that is just boilerplate; see any of
+ the other unit test directories for examples.
-** Each top-level test driver module should be in a file `Foo.bsv` or
- `Foo.bs`, and the module should be called `sysFoo`, with an `Empty`
- interface.
+** You can have multiple test programs. Each such top-level `Foo.bsv`
+ (or `Foo.bs`) should contain a top-level module `sysFoo` with an
+ `Empty` interface.
-** If the top-level file imports other support files (just for this
- test, not library files), they can be placed here, too.
+** If the top-level file imports other support source files (just for
+ this test, not library files), they can be placed here, too.
** Create a file `sysFoo.out.expected` containing output expected when
it is run.
@@ -200,6 +207,16 @@ If different output is expected from Bluesim vs. Verilog sim (e.g.,
*** for Bluesim: `sysFoo.c.out.expected`
*** for Verilog: `sysFoo.v.out.expected`
+** Finally, a file `foo.exp` contains a fragment of a "script" to be
+ run in this directory. It can invoke multiple tests in this
+ directory. Each test can be run in Bluesim or Verilog sim or both.
+ Again, see other existing unit tests for examples.
++
+For unit
+ tests included in the `.exp` file, try to keep the run-time short
+ (no more than about a minute) when run in iverilog, to limit the
+ overall run-time of CI (Continuous Integration).
+
// ----------------------------------------------------------------
=== Running unit tests
@@ -208,7 +225,8 @@ Please run your tests before submitting a PR.
See the "Testing" section of the link:../README.md[README] in
`bsc-contrib` for information on how to run them (you have to copy
-`testing/bsc.contrib` into the `bsc` repo and run it there).
+`testing/bsc.contrib` from here into the `bsc` repository's
+`testsuite` directory and run it there).
NOTE: (Future restructuring plans) +
We would like unit tests for
@@ -217,6 +235,6 @@ NOTE: (Future restructuring plans) +
`testing/bsc.contrib/MyContrib`. The current structure exists
because it is derived from historical roots where `bsc-contrib`
's testing was done along with `bsc` 's testing using shared
- infrastructure in the `bsc` repo.
+ infrastructure in the `bsc` repository.
// ================================================================
diff --git a/doc/How_to_Contribute.html b/doc/How_to_Contribute.html
index ec4eef3..bf1025d 100644
--- a/doc/How_to_Contribute.html
+++ b/doc/How_to_Contribute.html
@@ -439,7 +439,7 @@
How to Contribute to bsc-contrib
version v1.03,
-2024-11-21
+2024-12-09
@@ -448,7 +448,7 @@
How to Contribute to bsc-contrib
Let’s assume you want to contribute a new library MyContrib
. All
your B-Lang (BSV/BH) sources and documentation should be placed in a
-new sub-dir:
+new sub-directory:
@@ -464,7 +464,7 @@
How to Contribute to bsc-contrib
-
If you also have unit-tests, they should be in a new sub-dir:
+
If you also have unit tests, they should be in a new sub-directory:
@@ -500,7 +500,8 @@
1. Logistics
-On GitHub, create a FORK of the original bsc-contrib
repo, under your own account.
+On GitHub, create a FORK of the original bsc-contrib
repository,
+under your own account.
Clone your FORK to your work area (laptop, desktop, …).
@@ -511,7 +512,7 @@ 1. Logistics
In this new BRANCH (in your clone of your FORK), prepare your
contribution, including formatting, copyrights, licenses,
-build-and-install Makefiles and optional unit-tests. See the
+build-and-install Makefiles and optional unit tests. See the
sections below for details.
@@ -527,7 +528,7 @@ 1. Logistics
Push the commit from your clone up to your FORK.
-From your FORK, create a PR for the original bsc-contrib
repo.
+From your FORK, create a PR for the original bsc-contrib
repository.
@@ -574,7 +575,7 @@
3. Copyright and License text
You are responsible for specifying your preferred copyright and
-license text (but please remember that this is a public repo;
+license text (but please remember that this is a public repository;
everything here is expected to be free and open-source; anything here
should be freely usable in commercial products).
@@ -606,16 +607,17 @@
4. README
5. Makefiles for building and installing
-
make all
at the top level descends recursively into all sub-dirs of
-Libraries
and Verilog
. In a leaf-level library dir the Makefile
-contains a build
target to compile source file(s) that are in that
-dir. The corresponding object files get copied into the installation
-directory (default bsc-contrib/inst
). You can also specify other
-files to be copied (include files, config files, …).
+
make all
at the top level descends recursively into all
+sub-directories of Libraries
and Verilog
. In a leaf-level library
+directory the Makefile
contains a build
target to compile source
+file(s) that are in that directory. The corresponding object files
+get copied into the installation directory (default
+bsc-contrib/inst
). You can also specify other files to be copied
+(include files, config files, …).
-
If you added any files to the Verilog/
dir, add those filenames to
-the VERI_FILES
list in the Verilog/Makefile
.
+
If you added any files to the Verilog/
directory, add those
+filenames to the VERI_FILES
list in the Verilog/Makefile
.
The top-level make all
is performed for installation, but is also
@@ -629,10 +631,10 @@
5. Makefiles for building and in
Note
-In the Library
sub-dirs, this just compiles sources, it does
- not build executables. See separate "Unit Tests" section for
- building unit-test executables and running them. Those are also
- performed by CI.
+In the Library
sub-directories, this just compiles sources, it
+ does not build executables. See separate "Unit Tests" section
+ for building unit test executables and running them. Those are
+ also performed by CI.
@@ -652,9 +654,9 @@ 5.1. Setting u
contribution into the recursive descent.
-
If Libraries/MyContrib/
has sub-dirs, repeat the recursive pattern
-of Libraries/Makefile
to enable recursive descent into each sub-dir,
-as needed. Example:
+
If Libraries/MyContrib/
has sub-directories, repeat the recursive
+pattern of Libraries/Makefile
to enable recursive descent into each
+sub-directory, as needed. Example:
@@ -711,9 +713,9 @@
5.2. Running build-and-install
-
This should run the make install
action on the whole repo, including
-compiling your sources in your newly added MyContrib
, and installing
-the corresponding object files in:
+
This should run the make install
action on the whole repository,
+including compiling your sources in your newly added MyContrib
, and
+installing the corresponding object files in:
@@ -738,25 +740,27 @@
6. Optional Unit Tests
Note
-bsc-contrib
's unit-testing is performed as part of the main
+bsc-contrib
's unit testing is performed as part of the main
bsc
compiler’s testing of standard libraries, using the same
- infrastructure. The infrastructure has more ways to configure
- testing than described in this section; please see the bsc
- repo for more details (https://github.com/B-Lang-org/bsc ).
+ infrastructure. The infrastructure has many more ways to
+ configure testing than the brief description here; please see
+ testsuite/README.md
in the bsc
repository for more details
+ (https://github.com/B-Lang-org/bsc ).
-
Add your unit tests to bsc-contrib/testing/bsc.contrib/
. You can
-study any of the existing unit tests in that directory for guidance.
+
Add your unit tests to bsc-contrib/testing/bsc.contrib/
. For
+guidance, you can study any of the existing unit tests in that
+directory or in testsuite/
in the bsc
compiler repository.
Briefly:
-Add a sub-dir for a new set of unit-tests for the new library (it
-can have sub-dirs for more detailed structure):
+Add a sub-directory for a new set of unit tests for the new library
+(it can have sub-directories for more detailed structure):
bsc-contrib/testing/bsc.contrib/MyContrib/
@@ -764,17 +768,21 @@
6. Optional Unit Tests
-In this dir:
+In this directory:
-Each top-level test driver module should be in a file Foo.bsv
or
-Foo.bs
, and the module should be called sysFoo
, with an Empty
-interface.
+There should be a Makefile
that is just boilerplate; see any of
+the other unit test directories for examples.
-If the top-level file imports other support files (just for this
-test, not library files), they can be placed here, too.
+You can have multiple test programs. Each such top-level Foo.bsv
+(or Foo.bs
) should contain a top-level module sysFoo
with an
+Empty
interface.
+
+
+If the top-level file imports other support source files (just for
+this test, not library files), they can be placed here, too.
Create a file sysFoo.out.expected
containing output expected when
@@ -795,6 +803,18 @@
6. Optional Unit Tests
+
+Finally, a file foo.exp
contains a fragment of a "script" to be
+run in this directory. It can invoke multiple tests in this
+directory. Each test can be run in Bluesim or Verilog sim or both.
+Again, see other existing unit tests for examples.
+
+
For unit
+ tests included in the .exp
file, try to keep the run-time short
+ (no more than about a minute) when run in iverilog, to limit the
+ overall run-time of CI (Continuous Integration).
+
+
@@ -808,7 +828,8 @@ 6.1. Running unit tests
See the "Testing" section of the README in
bsc-contrib
for information on how to run them (you have to copy
-testing/bsc-contrib
into the bsc
repo and run it there).
+
testing/bsc.contrib
from here into the
bsc
repository’s
+
testsuite
directory and run it there).
@@ -824,7 +845,7 @@ 6.1. Running unit tests
testing/bsc.contrib/MyContrib
. The current structure exists
because it is derived from historical roots where bsc-contrib
's testing was done along with bsc
's testing using shared
- infrastructure in the bsc
repo.
+ infrastructure in the bsc
repository.
@@ -836,7 +857,7 @@
6.1. Running unit tests