aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3')
-rw-r--r--fpga/usrp3/lib/axi4lite_sv/AxiLiteIf.sv209
-rw-r--r--fpga/usrp3/lib/axi4lite_sv/Makefile.srcs13
-rw-r--r--fpga/usrp3/lib/axi4lite_sv/PkgAxiLite.sv21
-rw-r--r--fpga/usrp3/lib/axi4lite_sv/axi_lite.vh106
-rw-r--r--fpga/usrp3/sim/rfnoc/Makefile.srcs13
-rw-r--r--fpga/usrp3/sim/rfnoc/PkgAxiLiteBfm.sv738
6 files changed, 1099 insertions, 1 deletions
diff --git a/fpga/usrp3/lib/axi4lite_sv/AxiLiteIf.sv b/fpga/usrp3/lib/axi4lite_sv/AxiLiteIf.sv
new file mode 100644
index 000000000..beb095bc3
--- /dev/null
+++ b/fpga/usrp3/lib/axi4lite_sv/AxiLiteIf.sv
@@ -0,0 +1,209 @@
+//
+// Copyright 2020 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Interface: AxiLiteIf
+// Description:
+// AXI4-LITE is an ARM standard for lighter weight registers
+// axis based on the AXI4 protocol. For more information
+// on the spec see - https://developer.arm.com/docs/ihi0022/d
+//
+// The interface contains methods for
+// (1) Writing an address
+// (2) Reading an address
+//
+// Parameters:
+// - DATA_WIDTH - Width of the data on AXI4-Lite bus
+// - ADDR_WIDTH - Width of the address on AXI4-Lite bus
+//
+
+//-----------------------------------------------------------------------------
+// AXI4-Lite interface
+//-----------------------------------------------------------------------------
+
+interface AxiLiteIf #(
+ int DATA_WIDTH = 64,
+ int ADDR_WIDTH = 1
+) (
+ input logic clk,
+ input logic rst = 1'b0
+);
+
+ import PkgAxiLite::*;
+
+ localparam BYTES_PER_WORD = DATA_WIDTH/8;
+
+ // local type defs
+ typedef logic [DATA_WIDTH-1:0] data_t;
+ typedef logic [ADDR_WIDTH-1:0] addr_t;
+ typedef logic [BYTES_PER_WORD-1:0] strb_t;
+
+ // Signals that make up an AxiLite interface
+ // Write Address Channel
+ addr_t awaddr;
+ logic awvalid;
+ logic awready;
+
+ // Write Data Channel
+ data_t wdata;
+ strb_t wstrb = '1;
+ logic wvalid;
+ logic wready;
+
+ // Write Response Channel
+ resp_t bresp;
+ logic bvalid;
+ logic bready;
+
+ // Read Address Channel
+ addr_t araddr;
+ logic arvalid;
+ logic arready;
+
+ // Read Data Channel
+ data_t rdata;
+ resp_t rresp;
+ logic rvalid;
+ logic rready;
+
+ // Master Functions
+ task automatic drive_aw(input addr_t addr);
+ awaddr = addr;
+ awvalid = 1;
+ endtask
+
+ task automatic drive_w(input data_t data,
+ input strb_t strb = '1);
+ wdata = data;
+ wstrb = wstrb;
+ wvalid = 1;
+ endtask
+
+ task automatic drive_aw_idle();
+ awaddr = 'X;
+ awvalid = 0;
+ endtask
+
+ task automatic drive_w_idle();
+ wdata = 'X;
+ wstrb = 'X;
+ wvalid = 0;
+ endtask
+ task automatic drive_read(input addr_t addr);
+ araddr = addr;
+ arvalid = 1;
+ endtask
+
+ task automatic drive_read_idle();
+ araddr = 'X;
+ arvalid = 0;
+ endtask
+
+ // Slave Functions
+ task automatic drive_write_resp(input resp_t resp=OKAY);
+ bresp = resp;
+ bvalid = 1;
+ endtask
+
+ task automatic drive_write_resp_idle();
+ bresp = OKAY;
+ bvalid = 0;
+ endtask
+
+ task automatic drive_read_resp(input data_t data,
+ input resp_t resp=OKAY);
+ rdata = data;
+ rresp = resp;
+ rvalid = 1;
+ endtask
+
+ task automatic drive_read_resp_idle();
+ rdata = 'X;
+ rresp = OKAY;
+ rvalid = 0;
+ endtask
+
+ // Drive Functions (These are not particularly useful
+ // but they guarantee the modules using the package don't
+ // drive the interface with a continuous assignment)
+ task automatic drive_awaddr(input addr_t addr);
+ awaddr = addr;
+ endtask
+ task automatic drive_awvalid(input logic valid);
+ awvalid = valid;
+ endtask
+ task automatic drive_awready(input logic ready);
+ awready = ready;
+ endtask
+ task automatic drive_wdata(input data_t data);
+ wdata = data;
+ endtask
+ task automatic drive_wstrb(input strb_t strb);
+ wstrb = strb;
+ endtask
+ task automatic drive_wvalid(input logic valid);
+ wvalid = valid;
+ endtask
+ task automatic drive_wready(input logic ready);
+ wready = ready;
+ endtask
+
+ task automatic drive_bresp(input resp_t resp);
+ bresp = resp;
+ endtask
+ task automatic drive_bvalid(input logic valid);
+ bvalid = valid;
+ endtask
+ task automatic drive_bready(input logic ready);
+ bready = ready;
+ endtask
+
+ task automatic drive_araddr(input addr_t addr);
+ araddr = addr;
+ endtask
+ task automatic drive_arvalid(input logic valid);
+ arvalid = valid;
+ endtask
+ task automatic drive_arready(input logic ready);
+ arready = ready;
+ endtask
+
+ task automatic drive_rdata(input data_t data);
+ rdata = data;
+ endtask
+ task automatic drive_rresp(input resp_t resp);
+ rresp = resp;
+ endtask
+ task automatic drive_rvalid(input logic valid);
+ rvalid = valid;
+ endtask
+ task automatic drive_rready(input logic ready);
+ rready = ready;
+ endtask
+
+ // View from the master side
+ modport master (
+ input clk, rst,
+ output awaddr,awvalid,wdata,wstrb,wvalid,bready,araddr,arvalid,rready,
+ input awready,wready,bresp,bvalid,arready,rdata,rresp,rvalid,
+ import drive_aw,
+ import drive_w,
+ import drive_w_idle,
+ import drive_aw_idle,
+ import drive_read,
+ import drive_read_idle
+ );
+
+ // View from the slave side
+ modport slave (
+ input clk, rst,
+ input awaddr,awvalid,wdata,wstrb,wvalid,bready,araddr,arvalid,rready,
+ output awready,wready,bresp,bvalid,arready,rdata,rresp,rvalid,
+ import drive_write_resp,
+ import drive_write_resp_idle,
+ import drive_read_resp,
+ import drive_read_resp_idle
+ );
+
+endinterface : AxiLiteIf
diff --git a/fpga/usrp3/lib/axi4lite_sv/Makefile.srcs b/fpga/usrp3/lib/axi4lite_sv/Makefile.srcs
new file mode 100644
index 000000000..eb9239a2b
--- /dev/null
+++ b/fpga/usrp3/lib/axi4lite_sv/Makefile.srcs
@@ -0,0 +1,13 @@
+#
+# Copyright 2020 Ettus Research, A National Instruments Brand
+#
+# SPDX-License-Identifier: LGPL-3.0-or-later
+#
+
+##################################################
+# RFNoC Utility Sources
+##################################################
+AXI4LITE_SV_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/axi4lite_sv/, \
+PkgAxiLite.sv \
+AxiLiteIf.sv \
+))
diff --git a/fpga/usrp3/lib/axi4lite_sv/PkgAxiLite.sv b/fpga/usrp3/lib/axi4lite_sv/PkgAxiLite.sv
new file mode 100644
index 000000000..09b15e986
--- /dev/null
+++ b/fpga/usrp3/lib/axi4lite_sv/PkgAxiLite.sv
@@ -0,0 +1,21 @@
+//
+// Copyright 2020 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Package: PkgAxiLite
+// Description:
+// AXI4-Lite is an ARM standard for lighter weight registers
+// axis based on the AXI4 protocol. For more information
+// on the spec see - https://developer.arm.com/docs/ihi0022/d
+//
+// This package contains types used for AxiLiteIf.
+//
+
+//-----------------------------------------------------------------------------
+// AXI4-Lite Package
+//-----------------------------------------------------------------------------
+
+package PkgAxiLite;
+ typedef enum logic [1:0] {OKAY=0,SLVERR=2,DECERR=3} resp_t;
+endpackage : PkgAxiLite
diff --git a/fpga/usrp3/lib/axi4lite_sv/axi_lite.vh b/fpga/usrp3/lib/axi4lite_sv/axi_lite.vh
new file mode 100644
index 000000000..b260a1b24
--- /dev/null
+++ b/fpga/usrp3/lib/axi4lite_sv/axi_lite.vh
@@ -0,0 +1,106 @@
+//
+// Copyright 2020 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Header File: axi_lite.vh
+// Description: Macros for use with AXI4S
+//
+
+//-----------------------------------------------------------------------------
+// Unidirectional AXI4-Stream interface
+//-----------------------------------------------------------------------------
+
+// Macro that drives o from i for all fields. Of course, ready runs in the
+// counter direction.
+
+`define AXI4LITE_ASSIGN(O,I) \
+ /* write address channel */
+ ``O.awaddr = ``I.awaddr;\
+ ``O.awvalid = ``I.awvalid;\
+ ``I.awready = ``O.awready;\
+ /* write data channel */
+ ``O.wdata = ``I.wdata;\
+ ``O.wstrb = ``I.wstrb;\
+ ``O.wvalid = ``I.wvalid;\
+ ``I.wready = ``O.wready;\
+ /* write resp channel */
+ ``I.bresp = ``O.bresp;\
+ ``I.bvalid = ``O.bvalid;\
+ ``O.bready = ``I.bready;\
+ /* read address channel */
+ ``O.araddr = ``I.araddr;\
+ ``O.arvalid = ``I.arvalid;\
+ ``I.arready = ``O.arready;\
+ /* read resp channel */
+ ``I.rdata = ``O.rdata;\
+ ``I.rresp = ``O.rresp;\
+ ``I.rvalid = ``O.rvalid;\
+ ``O.rready = ``I.rready;
+
+`define AXI4LITE_DEBUG_ASSIGN(O,I) \
+ (* mark_debug = "true" *) logic [``I.ADDR_WIDTH-1:0] ``I``_debug_awaddr;\
+ (* mark_debug = "true" *) logic ``I``_debug_awvalid;\
+ (* mark_debug = "true" *) logic ``I``_debug_awready;\
+ (* mark_debug = "true" *) logic [``I.DATA_WIDTH-1:0] ``I``_debug_wdata;\
+ (* mark_debug = "true" *) logic [``I.BYTES_PER_WORD-1:0] ``I``_debug_wstrb;\
+ (* mark_debug = "true" *) logic ``I``_debug_wvalid;\
+ (* mark_debug = "true" *) logic ``I``_debug_wready;\
+ (* mark_debug = "true" *) logic [1:0] ``I``_debug_bresp;\
+ (* mark_debug = "true" *) logic ``I``_debug_bvalid;\
+ (* mark_debug = "true" *) logic ``I``_debug_bready;\
+ (* mark_debug = "true" *) logic [``I.ADDR_WIDTH-1:0] ``I``_debug_araddr;\
+ (* mark_debug = "true" *) logic ``I``_debug_arvalid;\
+ (* mark_debug = "true" *) logic ``I``_debug_arready;\
+ (* mark_debug = "true" *) logic [``I.DATA_WIDTH-1:0] ``I``_debug_rdata;\
+ (* mark_debug = "true" *) logic [1:0] ``I``_debug_rresp;\
+ (* mark_debug = "true" *) logic ``I``_debug_rvalid;\
+ (* mark_debug = "true" *) logic ``I``_debug_rready;\
+ always_comb begin\
+ /* write address channel */
+ ``I``_debug_awaddr = ``I.awaddr;\
+ ``I``_debug_awvalid = ``I.awvalid;\
+ ``I.awready = ``I``_debug_awready;\
+ /* write data channel */
+ ``I``_debug_wdata = ``I.wdata;\
+ ``I``_debug_wstrb = ``I.wstrb;\
+ ``I``_debug_wvalid = ``I.wvalid;\
+ ``I.wready = ``I``_debug_wready;\
+ /* write resp channel */
+ ``I.bresp = ``I``_debug_bresp;\
+ ``I.bvalid = ``I``_debug_bvalid;\
+ ``I``_debug_bready = ``I.bready;\
+ /* read address channel */
+ ``I``_debug_araddr = ``I.araddr;\
+ ``I``_debug_arvalid = ``I.arvalid;\
+ ``I.arready = ``I``_debug_arready;\
+ /* read resp channel */
+ ``I.rdata = ``I``_debug_rdata;\
+ ``I.rresp = ``I``_debug_rresp;\
+ ``I.rvalid = ``I``_debug_rvalid;\
+ ``I``_debug_rready = ``I.rready;
+ end\
+ always_comb begin\
+ /* write address channel */
+ ``O.awaddr = ``I``_debug_awaddr;\
+ ``O.awvalid = ``I``_debug_awvalid;\
+ ``I``_debug_awready = ``O.awready;\
+ /* write data channel */
+ ``O.wdata = ``I``_debug_wdata;\
+ ``O.wstrb = ``I``_debug_wstrb;\
+ ``O.wvalid = ``I``_debug_wvalid;\
+ ``I``_debug_wready = ``O.wready;\
+ /* write resp channel */
+ ``I``_debug_bresp = ``O.bresp;\
+ ``I``_debug_bvalid = ``O.bvalid;\
+ ``O.bready = ``I``_debug_bready;\
+ /* read address channel */
+ ``O.araddr = ``I``_debug_araddr;\
+ ``O.arvalid = ``I``_debug_arvalid;\
+ ``I``_debug_arready = ``O.arready;\
+ /* read resp channel */
+ ``I``_debug_rdata = ``O.rdata;\
+ ``I``_debug_rresp = ``O.rresp;\
+ ``I``_debug_rvalid = ``O.rvalid;\
+ ``O.rready = ``I``_debug_rready;
+ end \ No newline at end of file
diff --git a/fpga/usrp3/sim/rfnoc/Makefile.srcs b/fpga/usrp3/sim/rfnoc/Makefile.srcs
index a48d166b6..d1b59c8e2 100644
--- a/fpga/usrp3/sim/rfnoc/Makefile.srcs
+++ b/fpga/usrp3/sim/rfnoc/Makefile.srcs
@@ -5,13 +5,24 @@
#
##################################################
+# Dependencies for AXI BFMS
+##################################################
+
+SIM_RFNOC_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/, \
+axi4lite_sv/PkgAxiLite.sv \
+axi4lite_sv/AxiLiteIf.sv \
+))
+
+##################################################
# Simulation Libraries/Headers for AXI based interfaces
##################################################
-SIM_RFNOC_SRCS = $(abspath $(addprefix $(BASE_DIR)/../sim/rfnoc/, \
+
+SIM_RFNOC_SRCS += $(abspath $(addprefix $(BASE_DIR)/../sim/rfnoc/, \
PkgTestExec.sv \
test_exec.svh \
sim_clock_gen.sv \
PkgAxiStreamBfm.sv \
+PkgAxiLiteBfm.sv \
PkgChdrData.sv \
PkgChdrUtils.sv \
PkgChdrBfm.sv \
diff --git a/fpga/usrp3/sim/rfnoc/PkgAxiLiteBfm.sv b/fpga/usrp3/sim/rfnoc/PkgAxiLiteBfm.sv
new file mode 100644
index 000000000..62fd2a078
--- /dev/null
+++ b/fpga/usrp3/sim/rfnoc/PkgAxiLiteBfm.sv
@@ -0,0 +1,738 @@
+//
+// Copyright 2020 Ettus Research, A National Instruments Brand
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Module: PkgAxiLiteBfm
+//
+// Description: Package for AXI4-Lite bus functional model (BFM).
+// This consists of the AxiLiteTransaction and AxiLiteBfm classes.
+// It's based on the AxiLiteIf interface.
+//
+
+
+//-----------------------------------------------------------------------------
+// AXI-Lite BFM Package
+//-----------------------------------------------------------------------------
+
+package PkgAxiLiteBfm;
+
+ import PkgAxiLite::*;
+ export PkgAxiLite::*;
+
+
+ typedef enum {READ,WRITE} xtype_t;
+
+ //---------------------------------------------------------------------------
+ // AXI Lite Transaction Class
+ //---------------------------------------------------------------------------
+
+ class AxiLiteTransaction #(DATA_WIDTH = 32, ADDR_WIDTH = 32);
+
+ //------------------
+ // Type Definitions
+ //------------------
+
+ localparam BYTES_PER_WORD = DATA_WIDTH/8;
+
+ // local type defs
+ typedef logic [DATA_WIDTH-1:0] data_t;
+ typedef logic [ADDR_WIDTH-1:0] addr_t;
+ typedef logic [BYTES_PER_WORD-1:0] strb_t;
+
+ typedef AxiLiteTransaction #(DATA_WIDTH, ADDR_WIDTH) AxiLiteTransaction_t;
+
+ //------------
+ // Properties
+ //------------
+
+ xtype_t xtype;
+ data_t data;
+ addr_t addr;
+ strb_t strb = '1;
+ resp_t resp = OKAY;
+ int id;
+
+ //---------
+ // Methods
+ //---------
+
+ // Return a handle to a copy of this transaction
+ function AxiLiteTransaction_t copy();
+ AxiLiteTransaction_t temp;
+ temp = new();
+ temp.xtype = this.xtype;
+ temp.data = this.data;
+ temp.addr = this.addr;
+ temp.strb = this.strb;
+ temp.resp = this.resp;
+ temp.id = this.id;
+ return temp;
+ endfunction
+
+ // Return true if this xaction equals that of the argument
+ virtual function bit equal(AxiLiteTransaction_t xaction);
+
+ return (this.xtype === xaction.xtype &&
+ this.data === xaction.data &&
+ this.addr === xaction.addr &&
+ this.strb === xaction.strb &&
+ this.resp === xaction.resp);
+
+ endfunction : equal
+
+ // Format the contents of the xaction into a string
+ function string sprint();
+ return $sformatf("%s a=%X d=%X strb=%X resp=%s id=%d",this.xtype.name,
+ this.addr,this.data,this.strb,this.resp.name,this.id);
+ endfunction : sprint
+
+ // Print the contents of the xaction
+ function void print();
+ $display(sprint());
+ endfunction : print
+
+ endclass : AxiLiteTransaction;
+
+
+
+ //---------------------------------------------------------------------------
+ // AXI Lite BFM Class
+ //---------------------------------------------------------------------------
+
+ class AxiLiteBfm #(
+ int DATA_WIDTH = 32,
+ int ADDR_WIDTH = 32
+ );
+
+ //------------------
+ // Type Definitions
+ //------------------
+
+ typedef AxiLiteTransaction #(DATA_WIDTH, ADDR_WIDTH) AxiLiteTransaction_t;
+ typedef AxiLiteTransaction_t::data_t data_t;
+ typedef AxiLiteTransaction_t::addr_t addr_t;
+ typedef AxiLiteTransaction_t::strb_t strb_t;
+
+ //------------
+ // Properties
+ //------------
+
+ // Default stall probability, as a percentage (0-100).
+ local const int DEF_STALL_PROB = 38;
+
+ // Virtual interfaces for master and slave connections to DUT
+ local virtual AxiLiteIf #(DATA_WIDTH,ADDR_WIDTH).master master;
+ local virtual AxiLiteIf #(DATA_WIDTH,ADDR_WIDTH).slave slave;
+
+ // NOTE: We should not need these flags if Vivado would be OK with null check
+ // without throwing unnecessary null-ptr deref exceptions.
+ local bit master_en;
+ local bit slave_en;
+
+ // Each submitted transaction is given an id. The id is used when
+ // waiting for the response
+ local int id=0;
+
+ // submit/completion id's are used to enforce rd/wr ordering
+ local int wr_submit_id=0;
+ local int wr_complete_id=0;
+ local int rd_submit_id=0;
+ local int rd_complete_id=0;
+
+ // Queues to store the bus transactions
+ mailbox #(AxiLiteTransaction_t) master_rd_req_xactions;
+ mailbox #(AxiLiteTransaction_t) master_rd_inflight_xactions;
+ mailbox #(AxiLiteTransaction_t) master_rd_resp_xactions;
+
+ mailbox #(AxiLiteTransaction_t) master_wr_req_xactions;
+ mailbox #(AxiLiteTransaction_t) master_wr_inflight_xactions;
+ mailbox #(AxiLiteTransaction_t) master_wr_resp_xactions;
+
+ mailbox #(AxiLiteTransaction_t) slave_rd_req_xactions;
+ mailbox #(AxiLiteTransaction_t) slave_rd_resp_xactions;
+
+ mailbox #(AxiLiteTransaction_t) slave_wr_req_xactions;
+ mailbox #(AxiLiteTransaction_t) slave_wr_resp_xactions;
+
+ // Properties for the stall behavior of the BFM
+ int stall_prob = DEF_STALL_PROB;
+
+ // determine if ready parks innactive
+ bit ready_idle_state = 1;
+ // Read write ordering
+ bit rds_wait_for_wrs = 1;
+ bit wrs_wait_for_rds = 1;
+
+ // Number of clocks betwen transactions
+ int inter_xaction_gap = 0;
+
+ //---------
+ // Methods
+ //---------
+
+ // Returns 1 if the xactions have the same contents, otherwise returns 0.
+ function bit xactions_equal(AxiLiteTransaction_t a, AxiLiteTransaction_t b);
+ return a.equal(b);
+ endfunction : xactions_equal
+
+
+ // Class constructor. This must be given an interface for the master
+ // connection and an interface for the slave connection.
+ function new(
+ virtual AxiLiteIf #(DATA_WIDTH,ADDR_WIDTH).master master=null,
+ virtual AxiLiteIf #(DATA_WIDTH,ADDR_WIDTH).slave slave=null
+ );
+ this.master_en = (master != null);
+ this.slave_en = (slave != null);
+ this.master = master;
+ this.slave = slave;
+
+ master_rd_req_xactions = new;
+ master_rd_inflight_xactions = new;
+ master_rd_resp_xactions = new;
+ master_wr_req_xactions = new;
+ master_wr_inflight_xactions = new;
+ master_wr_resp_xactions = new;
+
+ slave_rd_req_xactions = new;
+ slave_rd_resp_xactions = new;
+ slave_wr_req_xactions = new;
+ slave_wr_resp_xactions = new;
+
+ endfunction : new
+
+ // Internal functions - Users should use wr/wr_block
+ // This function pushes the write_addr/write_data channels
+ task automatic post_wr(addr_t addr, data_t data, strb_t strb='1,
+ AxiLiteTransaction_t xaction);
+ int rd_submit_id_at_start = rd_submit_id;
+ xaction.xtype = WRITE;
+ xaction.addr = addr;
+ xaction.data = data;
+ xaction.strb = strb;
+ xaction.id = ++this.id;
+ wr_submit_id = xaction.id;
+
+ if (wrs_wait_for_rds) begin
+ // wait for any reads that may of been submitted before
+ // this write to complete before exectuing
+ while (rd_complete_id-rd_submit_id_at_start < 0) begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end
+ end
+
+ put(xaction);
+ endtask : post_wr
+
+ // Internal functions - Users should use wr/wr_block
+ // This function wait for the write respone channel
+ task automatic get_wr_response(AxiLiteTransaction_t xaction);
+ AxiLiteTransaction_t resp_xaction = null;
+
+ forever begin
+ while(!try_peek_wr(resp_xaction)) begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end
+ if (resp_xaction.id == xaction.id) begin
+ break;
+ end else begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end
+ end
+ get_wr(xaction);
+ wr_complete_id = xaction.id;
+ endtask :get_wr_response
+
+ // Simple blocking write
+ task automatic wr_block(addr_t addr, data_t data, strb_t strb='1, output resp_t resp);
+ AxiLiteTransaction_t xaction = new;
+ post_wr(addr,data,strb,xaction);
+ get_wr_response(xaction);
+ resp = xaction.resp;
+ endtask : wr_block
+
+ // Non-blocking write that checks against an expected response
+ task automatic wr(addr_t addr, data_t data, strb_t strb='1,resp_t resp=OKAY);
+ AxiLiteTransaction_t xaction = new;
+ post_wr(addr,data,strb,xaction);
+ fork
+ begin
+ get_wr_response(xaction);
+ assert (xaction.resp == resp) else begin
+ xaction.print();
+ $error({"mismatch on wr response. expected:",xaction.resp.name});
+ end
+ end
+ join_none
+ endtask : wr
+
+ // Internal functions - Users should use rd/rd_block
+ // This function pushes the read address channel
+ task automatic post_rd(addr_t addr,AxiLiteTransaction_t xaction);
+ int wr_submit_id_at_start = wr_submit_id;
+ xaction.xtype = READ;
+ xaction.addr = addr;
+ xaction.id = ++this.id;
+ rd_submit_id = xaction.id;
+
+ // wait for any writes that may have been
+ // submitted before this read to complete
+ if (rds_wait_for_wrs) begin
+ while (wr_complete_id-wr_submit_id_at_start < 0) begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end
+ end
+ put(xaction);
+ endtask : post_rd
+
+ // Internal functions - Users should use rd/rd_block
+ // This function waits for the read response channel
+ task automatic get_rd_response(AxiLiteTransaction_t xaction);
+ AxiLiteTransaction_t resp_xaction = null;
+
+ forever begin
+ while(!try_peek_rd(resp_xaction)) begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end
+ if (resp_xaction.id == xaction.id) begin
+ break;
+ end else begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end
+ end
+ get_rd(xaction);
+ rd_complete_id = xaction.id;
+ endtask : get_rd_response
+
+ // Simple blocking read
+ task automatic rd_block(addr_t addr, output data_t data, output resp_t resp);
+ AxiLiteTransaction_t xaction = new;
+ post_rd(addr,xaction);
+ get_rd_response(xaction);
+ data = xaction.data;
+ resp = xaction.resp;
+ endtask : rd_block
+
+ // Non-blocking read that checks against an expected data response
+ task automatic rd(addr_t addr, data_t data, strb_t strb='1,resp_t resp=OKAY);
+ AxiLiteTransaction_t xaction = new;
+ post_rd(addr,xaction);
+ fork
+ begin
+ get_rd_response(xaction);
+ assert (xaction.resp == resp) else begin
+ xaction.print();
+ $error({"mismatch on rd response. expected:",xaction.resp.name});
+ end
+ assert (xaction.data === data) else begin
+ xaction.print();
+ $error({"mismatch on rd data. expected:",$sformatf("%x",data)});
+ end
+ end
+ join_none
+ endtask : rd
+
+ task automatic block();
+ int rd_submit_id_at_start = rd_submit_id;
+ int wr_submit_id_at_start = wr_submit_id;
+ while (rd_complete_id-rd_submit_id_at_start < 0 ||
+ wr_complete_id-wr_submit_id_at_start < 0) begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end
+ endtask : block
+
+ // Queue the provided xaction for transmission
+ task put(AxiLiteTransaction_t xaction);
+ if (xaction.xtype == READ && master_en) begin
+ master_rd_req_xactions.put(xaction);
+ end else if (xaction.xtype == WRITE && master_en) begin
+ master_wr_req_xactions.put(xaction);
+ end else if (xaction.xtype == READ && slave_en) begin
+ slave_rd_resp_xactions.put(xaction);
+ end else if (xaction.xtype == WRITE && slave_en) begin
+ slave_wr_resp_xactions.put(xaction);
+ end
+ endtask : put
+
+ // Attempt to queue the provided xaction for transmission. Return 1 if
+ // successful, return 0 if the queue is full.
+ function bit try_put(AxiLiteTransaction_t xaction);
+ if (xaction.xtype == READ && master_en) begin
+ return master_rd_req_xactions.try_put(xaction);
+ end else if (xaction.xtype == WRITE && master_en) begin
+ return master_wr_req_xactions.try_put(xaction);
+ end else if (xaction.xtype == READ && slave_en) begin
+ return slave_rd_resp_xactions.try_put(xaction);
+ end else if (xaction.xtype == WRITE && slave_en) begin
+ return slave_wr_resp_xactions.try_put(xaction);
+ end
+ endfunction : try_put
+
+ // Get the next rd_xaction when it becomes available (waits if necessary)
+ task get_rd(output AxiLiteTransaction_t xaction);
+ if (master_en) begin
+ master_rd_resp_xactions.get(xaction);
+ end else if (slave_en) begin
+ slave_rd_req_xactions.get(xaction);
+ end
+ endtask : get_rd
+
+ // Get the next wr_xaction when it becomes available (waits if necessary)
+ task get_wr(output AxiLiteTransaction_t xaction);
+ if (master_en) begin
+ master_wr_resp_xactions.get(xaction);
+ end else if (slave_en) begin
+ slave_wr_req_xactions.get(xaction);
+ end
+ endtask : get_wr
+
+ // Get the next rd_xaction if there's one available and return 1. Return 0 if
+ // there's no xaction available.
+ function bit try_get_rd(output AxiLiteTransaction_t xaction);
+ if (master_en) begin
+ return master_rd_resp_xactions.try_get(xaction);
+ end else if (slave_en) begin
+ return slave_rd_req_xactions.try_get(xaction);
+ end
+ endfunction : try_get_rd
+
+ // Get the next wr_xaction if there's one available and return 1. Return 0 if
+ // there's no xaction available.
+ function bit try_get_wr(output AxiLiteTransaction_t xaction);
+ if (master_en) begin
+ return master_wr_resp_xactions.try_get(xaction);
+ end else if (slave_en) begin
+ return slave_wr_req_xactions.try_get(xaction);
+ end
+ endfunction : try_get_wr
+
+ // Get the next wr xaction when it becomes available (wait if necessary), but
+ // don't remove it from the receive queue.
+ task peek_rd(output AxiLiteTransaction_t xaction);
+ if (master_en) begin
+ master_rd_resp_xactions.peek(xaction);
+ end else if (slave_en) begin
+ slave_rd_req_xactions.peek(xaction);
+ end
+ endtask : peek_rd
+
+ // Get the next wr xaction when it becomes available (wait if necessary), but
+ // don't remove it from the receive queue.
+ task peek_wr(output AxiLiteTransaction_t xaction);
+ if (master_en) begin
+ master_wr_resp_xactions.peek(xaction);
+ end else if (slave_en) begin
+ slave_wr_req_xactions.peek(xaction);
+ end
+ endtask : peek_wr
+
+ // Get the next rd xaction if there's one available and return 1, but don't
+ // remove it from the receive queue. Return 0 if there's no xaction
+ // available.
+ function bit try_peek_rd(output AxiLiteTransaction_t xaction);
+ if (master_en) begin
+ return master_rd_resp_xactions.try_peek(xaction);
+ end else if (slave_en) begin
+ return slave_rd_req_xactions.try_peek(xaction);
+ end
+ endfunction : try_peek_rd
+
+ // Get the next wr xaction if there's one available and return 1, but don't
+ // remove it from the receive queue. Return 0 if there's no xaction
+ // available.
+ function bit try_peek_wr(output AxiLiteTransaction_t xaction);
+ if (master_en) begin
+ return master_wr_resp_xactions.try_peek(xaction);
+ end else if (slave_en) begin
+ return slave_wr_req_xactions.try_peek(xaction);
+ end
+ endfunction : try_peek_wr
+
+
+ // Return the number of xactions available in the receive queue
+ function int num_rd_pending();
+ if (master_en) begin
+ return master_rd_resp_xactions.num() +
+ master_rd_inflight_xactions.num() +
+ master_rd_req_xactions.num();
+ end else if (slave_en) begin
+ $fatal(1,"Slave AxiLite not yet implemented!");
+ end
+ endfunction
+
+ function int num_wr_pending();
+ if (master_en) begin
+ return master_wr_resp_xactions.num() +
+ master_wr_inflight_xactions.num() +
+ master_wr_req_xactions.num();
+ end else if (slave_en) begin
+ $fatal(1,"Slave AxiLite not yet implemented!");
+ end
+ endfunction
+
+ // Create separate processes for driving the master and slave interfaces
+ task run();
+ fork
+ if (master_en) master_body();
+ if (slave_en) slave_body();
+ join_none
+ endtask
+
+ //----------------
+ // Master Process
+ //----------------
+
+ // wait my_delay clocks - while not reset
+ local task master_wait(my_delay);
+ repeat(my_delay) begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end
+ endtask
+
+ // stall for a random delay - while not reset
+ local task master_stall(int my_stall_prob);
+ if ($urandom_range(99) < my_stall_prob) begin
+ do begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end while ($urandom_range(99) < my_stall_prob);
+ end
+ endtask
+
+ local task master_body();
+
+ // start idle
+ master.drive_w_idle();
+ master.drive_aw_idle();
+ master.bready = ready_idle_state;
+
+ master.drive_read_idle();
+ master.rready = ready_idle_state;
+
+ fork // write_req / write_resp / rd_req / rd_resp
+ //--------------------------------------
+ begin : write_req_thread
+ AxiLiteTransaction_t xaction;
+
+ forever begin
+ // add inter xaction gap
+ master_wait(inter_xaction_gap);
+
+ if (master_wr_req_xactions.try_get(xaction)) begin : req_transaction
+
+ //drive the write address+data channel
+ fork
+ begin
+ // randomly delay driving
+ master_stall(stall_prob);
+ master.drive_aw(xaction.addr);
+ // wait for ready
+ do begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end while (!master.awready);
+ master.drive_aw_idle();
+ end
+ begin // wait for data ready
+ // randomly delay driving
+ master_stall(stall_prob);
+ master.drive_w(xaction.data,xaction.strb);
+
+ // push to inflight xactions
+ master_wr_inflight_xactions.put(xaction);
+
+ // wait for ready
+ do begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end while (!master.wready);
+ master.drive_w_idle();
+ end
+ join
+
+
+ end else begin : no_req_transaction
+ @(posedge master.clk);
+ if (master.rst) continue;
+ end : no_req_transaction;
+ end //forever
+ end : write_req_thread;
+
+ //--------------------------------------
+ begin : write_resp_thread
+ AxiLiteTransaction_t xaction;
+
+ forever begin
+
+ if (master_wr_inflight_xactions.try_get(xaction)) begin : resp_transaction
+ // wait for a little bit of time and assert ready
+ if ($urandom_range(99) < 50) begin
+ if (master.bready == 0) begin
+ // randomly delay ready
+ master_stall(stall_prob);
+ master.bready = 1;
+ end
+ master.bready = 1;
+ // wait for valid
+ do begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end while (!master.bvalid);
+ //wait for valid then wait a bit of time and assert ready
+ end else begin
+ // wait for valid
+ do begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end while (!master.bvalid);
+
+ if (master.bready == 0) begin
+ // randomly delay ready while valid is true
+ master_stall(stall_prob);
+ master.bready = 1;
+ @(posedge master.clk);
+ end
+ end
+
+
+ // put the response and clear ready
+ master.bready = 0;
+ xaction.resp = master.bresp;
+ master_wr_resp_xactions.put(xaction);
+ // randomly keep ready low for awhile
+ master_stall(stall_prob);
+ master.bready = ready_idle_state;
+
+ end else begin : no_resp_transaction
+ @(posedge master.clk);
+ if (master.rst) continue;
+ end
+
+ end // forever
+ end : write_resp_thread;
+
+ begin : read_req_thread
+ AxiLiteTransaction_t xaction;
+
+ forever begin
+ // add inter xaction gap
+ master_wait(inter_xaction_gap);
+
+ if (master_rd_req_xactions.try_get(xaction)) begin : req_transaction
+ // randomly delay driving
+ master_stall(stall_prob);
+
+ //drive the read address channel
+ master.drive_read(xaction.addr);
+ // push to in-flight xactions
+ master_rd_inflight_xactions.put(xaction);
+
+ // wait for read address channel ready
+ do begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end while (!master.arready);
+ master.drive_read_idle();
+
+
+ end else begin : no_req_transaction
+ @(posedge master.clk);
+ if (master.rst) continue;
+ end
+ end // forever
+ end : read_req_thread;
+
+ //--------------------------------------
+ begin : read_resp_thread
+ AxiLiteTransaction_t xaction;
+
+ forever begin
+
+ if (master_rd_inflight_xactions.try_get(xaction)) begin : resp_transaction
+ if ($urandom_range(99) < 50) begin
+ if (master.rready == 0) begin
+ // randomly delay ready
+ master_stall(stall_prob);
+ master.rready = 1;
+ end
+ master.rready = 1;
+ // wait for valid
+ do begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end while (!master.rvalid);
+ // wait for valid then wait a bit of time and assert ready
+ end else begin
+ // wait for valid
+ do begin
+ @(posedge master.clk);
+ if (master.rst) break;
+ end while (!master.rvalid);
+
+ if (master.rready == 0) begin
+ // randomly delay ready while valid is true
+ master_stall(stall_prob);
+ master.rready = 1;
+ @(posedge master.clk);
+ end
+ end
+
+ // put the response and clear ready
+ master.rready = 0;
+ xaction.data = master.rdata;
+ xaction.resp = master.rresp;
+ master_rd_resp_xactions.put(xaction);
+ // randomly keep ready low for awhile
+ master_stall(stall_prob);
+ master.rready = ready_idle_state;
+
+ end else begin : no_resp_transaction
+ @(posedge master.clk);
+ if (master.rst) continue;
+ end
+
+ end // forever
+ end : read_resp_thread;
+
+ join_none
+ endtask : master_body
+
+
+ //---------------
+ // Slave Process
+ //---------------
+
+ local task slave_body();
+ AxiLiteTransaction_t xaction = new();
+
+ // start idle
+ slave.drive_write_resp_idle();
+ slave.awready = 0;
+ slave.wready = 0;
+
+ slave.drive_read_resp_idle();
+ slave.arready = 0;
+
+ forever begin
+ @(posedge slave.clk);
+ if (slave.rst) continue;
+
+ // not written!
+ $fatal(1,"Slave AxiLite not yet implemented!");
+
+ end
+ endtask : slave_body
+
+ endclass : AxiLiteBfm
+
+
+endpackage : PkgAxiLiteBfm