diff options
Diffstat (limited to 'fpga/usrp3')
-rw-r--r-- | fpga/usrp3/lib/axi4lite_sv/AxiLiteIf.sv | 209 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi4lite_sv/Makefile.srcs | 13 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi4lite_sv/PkgAxiLite.sv | 21 | ||||
-rw-r--r-- | fpga/usrp3/lib/axi4lite_sv/axi_lite.vh | 106 | ||||
-rw-r--r-- | fpga/usrp3/sim/rfnoc/Makefile.srcs | 13 | ||||
-rw-r--r-- | fpga/usrp3/sim/rfnoc/PkgAxiLiteBfm.sv | 738 |
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 |