# CSR utilities

This csr_utils folder intends to implement CSR related methods and test sequences for DV
to share across all testbenches.

### CSR utility package
`csr_utils_pkg` provides common methods and properties to support and manage CSR accesses
and CSR related test sequences.

#### Global types and variables
All common types and variables are defined at this package level. Examples are:
```systemverilog
  uint       outstanding_accesses        = 0;
  uint       default_timeout_ns          = 1_000_000;
```

##### Outstanding_accesses
`csr_utils_pkg` used an internal variable to store the number of accesses
(read or write) that have not yet completed. This variable is shared among all methods of
register reading and writing. Directly accessing this variable is discouraged. Instead,
the following methods are used to control this variable to keep track of non-blocking
accesses made in the testbench:
```systemverilog
  function automatic void increment_outstanding_access();
    outstanding_accesses++;
  endfunction

  function automatic void decrement_outstanding_access();
    outstanding_accesses--;
  endfunction

  task automatic wait_no_outstanding_access();
    wait(outstanding_accesses == 0);
  endtask

  function automatic void clear_outstanding_access();
    outstanding_accesses = 0;
  endfunction
```

##### CSR spinwait
One of the commonly used tasks in `csr_utils_pkg` is `csr_spinwait`. This task
can poll a CSR or CSR field continuously or periodically until it reads out the
expected value. This task also has a timeout check in case due to DUT or testbench
issue, the CSR or CSR field never returns the expected value.
Example below uses the `csr_spinwait` to wait until the CSR `fifo_status` field
`fifo_full` reaches value bit 1:
```systemverilog
csr_spinwait(.ptr(ral.status.fifo_full), .exp_data(1'b0));
```

##### Read and check all CSRs
The purpose of the `read_and_check_all_csrs` task is to read all valid CSRs from
the given `uvm_reg_block` and check against their expected values from RAL. This
task is primarily implemented to use after reset, to make sure all the CSRs are
being reset to the default value.

##### Under_reset
Due to `csr_utils_pkg` is not connected to any interface, methods inside
this package are not able to get reset information. Current the `under_reset`
bit is declared with two functions:
```systemverilog
function automatic void reset_asserted();
  under_reset = 1;
endfunction

function automatic void reset_deasserted();
  under_reset = 0;
endfunction
```
This reset information is updated in `dv_lib/dv_base_vseq.sv`. When the
`apply_reset` task is triggered, it will set and reset the `under_reset` bit
via the functions above.

#### Global CSR util methods
##### Global methods for CSR and MEM attributes
This package provides methods to access CSR or Memory attributes, such as address,
value, etc. Examples are:
 * `get_csr_addrs`
 * `get_mem_addr_ranges`
 * `decode_csr_or_field`

##### Global methods for CSR access
The CSR access methods are based on `uvm_reg` methods, such as `uvm_reg::read()`,
`uvm_reg::write()`, `uvm_reg::update()`. For all CSR methods, user can
pass either a register or a field handle. Examples are:
 * `csr_rd_check`: Given the uvm_reg or uvm_reg_field object, this method will
   compare the CSR value with the expected value (given as an input) or with
   the RAL mirrored value
 * `csr_update`: Given the uvm_reg object, this method will update the value of the
   register in DUT to match the desired value

To enhance the usability, these methods support CSR blocking, non-blocking
read/write, and a timeout checking.
 * A blocking thread will not execute the next sequence until the current CSR
   access is finished
 * A non-blocking thread allows multiple CSR accesses to be issued back-to-back
   without waiting for the response
 * A timeout check will discard the ongoing CSR access by disabling the forked
   thread and will throw a UVM_ERROR once the process exceeds the max timeout setting

### CSR sequence library
`csr_seq_lib.sv` provides common CSR related test sequences to share across all testbenches.
These test sequences are based off the standard sequences provided in UVM1.2 RAL.
The parent class (DUT-specific test or sequence class) that creates them needs to provide them
with the DUT RAL model. The list of CSRs are then extracted from the RAL model to performs the checks.
In addition, the test sequences provide an ability to exclude a CSR from writes or reads (or both)
depending on the behavior of the CSR in the design. This is explained more in the
[CSR exclusion methodology](#csr-exclusion-methodology) section below.
All CSR accesses in these sequences are made non-blocking to ensure back-to-back scenarios
are exercised.
Supported CSR test sequences are:
 * `csr_hw_reset`: Write all CSRs with random values and then reset the DUT.
   After reset, read all CSRs and compare with expected values
 * `csr_rw`: Write a randomly selected CSRs, then read out the updated
   CSR or CSR field and compare with expected value
 * `csr_bit_bash`: Randomly select a CSR and write 1's and 0's to
   every bit, then read the CSR to compare with expected value
 * `csr_aliasing`: Randomly write a CSR, then read all CSRs to
   verify that only the CSR that was written was updated
 * `mem_walk`: Write and read all valid addresses in the memory. Compare
   the read results with the expected values

### CSR exclusion methodology
The CSR test sequences listed above intend to perform a basic check to CSR
read/write accesses, but do not intend to check specific DUT functionalities. Thus the
sequences might need to exclude reading or writing certain CSRs depending on the
specific testbench.
`csr_excl_item` is a class that supports adding exclusions to CSR test sequences.
Examples of useful functions in this class are:
* `add_excl`: Add exclusions to the CSR test sequences. This function has two inputs:
  - Exclusion scope: A hierarchical path name at all levels including block,
    CSR, and field. This input supports * and ? wildcards for glob style matching
  - CSR_exclude type: An enumeration defined as below:
    ```systemverilog
    typedef enum bit[2:0] {
      CsrNoExcl         = 3'b000, // no exclusions
      CsrExclInitCheck  = 3'b001, // exclude csr from init val check
      CsrExclWriteCheck = 3'b010, // exclude csr from write-read check
      CsrExclCheck      = 3'b011, // exclude csr from init or write-read check
      CsrExclWrite      = 3'b100, // exclude csr from write
      CsrExclAll        = 3'b111  // exclude csr from init or write or write-read check
    } csr_excl_type_e;
    ```

  One example to use this function in HMAC to exclude all CSRs or fields with
  names starting with "key":
  ```systemverilog
  csr_excl.add_excl({scope, ".", "key?"}, CsrExclWrite);
  ```

* `has_excl`: Check if the CSR has a match in the existing exclusions lookup,
  and is not intended to use externally

### CSR sequence framework
The [cip_lib](../cip_lib/README.md) includes a virtual sequence named `cip_base_vseq`,
that provides a common framework for all testbenches to run these CSR test sequences and
add exclusions.
