diff options
Diffstat (limited to 'fpga')
| -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 | 
