| {{% lowrisc-doc-hdr Comportable IP Testbench Architecture }} |
| |
| Going along the lines of what it takes to design an IP that adheres to the |
| [Comportability Specifications](../../../../doc/rm/comportability_specification.md), |
| we attempt to standardize the DV methodology for developing the IP level |
| testbench environment as well by following the same approach. This document describes |
| the Comportable IP (CIP) library, which is a complete UVM enviromnent framework that |
| each IP level environment components can extend from to get started with DV. The goal |
| here is to maximize code reuse across all test benches so that we can improve the |
| efficiency and time to market. The features described here are not exhaustive, |
| so it is highly recommended to the reader that they examine the code directly. In |
| course of development, we also periodically identify pieces of verification logic that |
| might be developed for one IP but is actually a good candidate to be added to |
| these library classes instead. This doc is instead intended to provide the user |
| a foray into what these are and how are the meant to be used. |
| |
| {{% toc 3 }} |
| |
| |
| ## CIP environment block diagram |
|  |
| |
| ## CIP library classes |
| The CIP library includes the base ral model, env cfg object, coverage |
| object, virtual sequencer, scoreboard, env, base virtual sequence and finally |
| the test class. To achieve run-time polymorphism, these classes are type |
| parameterized to indicate what type of child objects are to be created. In the |
| IP environments, the extended classes indicate the correct type parameters. |
| |
| ### cip_base_env_cfg |
| This class is intended to contain all of the settings, knobs, features, interface |
| handles and downstream agent cfg handles. Features that are common to all IPs in |
| accordance with the comportability spec are made a part of this base class, while the |
| extended IP env cfg class will contain settings specific to that IP. An instance of |
| the env cfg class is created in `cip_base_test::build_phase` and the handle is |
| passed over uvm_config_db for the CIP env components to pick up. This allows |
| the handle to the env cfg object to be available in the env's build_phase. Settings |
| in the env cfg can then be used to configure the env based on the test needs. |
| |
| A handle to this class instance is passed on to the scoreboard, virtual |
| sequencer and coverage objects so that all such common settings and features |
| are instantly accessible everywhere. |
| |
| This class is type parameterized in the following way: |
| ``` |
| class cip_base_env_cfg #(type RAL_T = dv_base_reg_block) extends uvm_object; |
| ``` |
| The IP env cfg class will then extend from this class with the RAL_T parameter set |
| to the actual IP RAL model class. This results in IP RAL model getting factory |
| overridden automatically in the base env cfg itself during creation, so there is no |
| need for manual factory override. We follow the same philosophy in all CIP library |
| classes. |
| |
| The following is a list of common features and settings: |
| * **clk_rst_if**: A handle to the clk_rst_if that controls the main clk and reset |
| to the DUT. |
| * **intr_vif**: This is a handle to the `pins_if #(NUM_MAX_INTERRUPTS=64)` interface |
| instance created in the tb to hookup the DUT interrupts. The actual number of |
| interrupts might be much less than 64, but that is ok - we just connect as |
| many as the DUT provides. The reason for going with a fixed width pins_if is |
| to allow the intr_vif to be available in this base env cfg class (which does not |
| know how many interrupt each IP DUT provides). |
| * **alerts_vif**: This is a handle to the `pins_if #(NUM_MAX_ALERTS=64)` interface |
| instance created in the tb to hookup the DUT alerts, similar to intr_vif. |
| * **devmode_vif**: THis is a handle to the `pins_if #(1)` interface instance created |
| in the tb to hookup the DUT input `devmode`. |
| * **tl_agent_cfg**: The downstream TileLink host agent created in the cip_base_env |
| class requires the agent cfg handle to tell it how to configure the agent. |
| * **ral**: This is the instance to the auto-generated RAL model that is |
| extended from `dv_base_reg_block`. In the base class, this is created using |
| the RAL_T class parameter which the extended IP env cfg class sets correctly. |
| |
| Apart from these, there are several common settings such as `zero_delays`, |
| `clk_freq_mhz`, which are randomized as well as knobs such as `en_scb` and |
| `en_cov` to turn on/off scoreboard and coverage collection respectively. |
| |
| The base class provides a virtual method called `initialize()` which is called |
| in `cip_base_test::build_phase` to create some of the objects listed above. If |
| the extended IP env cfg class has more such objects added, then the `initialize()` |
| method is required to be overridden to create those objects as well. |
| |
| We make all downstream interface agent cfg handles as a part of IP extension of |
| cip_base_env_cfg so that all settings for the env and all downstream agents are |
| avaiable within the env cfg handle. Since the env cfg handle is passed to all cip |
| components, all those settings are also accesible. |
| |
| ### cip_base_env_cov |
| This is the base coverage object that contain all functional coverpoints and |
| covergroups. The main goal is to have all functional coverage elements |
| implemented in a single place. This class is extended from `uvm_component` |
| so that it allows items to be set via `'uvm_config_db` using the component's |
| hierarchy. This is created in cip_base_env and a handle to it is passed to the |
| scoreboard and the virtual sequencer. This allows coverage to be sampled in |
| scoreboard as well as the test sequences. |
| |
| This class is type parameterized with the env cfg class type `CFG_T` so that it |
| can derive coverage on some of the env cfg settings. |
| ``` |
| class cip_base_env_cov #(type CFG_T = cip_base_env_cfg) extends uvm_component; |
| ``` |
| |
| ### cip_base_virtual_sequencer |
| This is the base virtual sequencer class that contains a handle to the |
| `tl_sequencer` to allow layered test sequences to be created. The extended IP |
| virtual sequencer class will include handles to the IP specific agent |
| sequencers. |
| G |
| This class is type-parameterized with the env cfg class type `CFG_T` and coverage |
| class type `COV_T` so that all test sequences can access the env cfg settings and |
| sample the coverage via the `p_sequencer` handle. |
| ``` |
| class cip_base_virtual_sequencer #(type CFG_T = cip_base_env_cfg, |
| type COV_T = cip_base_env_cov) extends uvm_sequencer; |
| ``` |
| |
| ### cip_base_scoreboard |
| This is the base scoreboard component that already connects with the TileLink |
| agent monitor to grab tl packets via analysis port at the address and the data |
| phases. It provides a virtual task called `process_tl_access` that the extended |
| IP scoreboard needs to implement. Please see code for additional details. The |
| extended IP scoreboard class will connect with the IP-specific interface monitors |
| if applicable to grab items from those analysis ports. |
| |
| This class is type-parameterized with the env cfg class type `CFG_T`, ral class |
| type `RAL_T` and the coverage class type `COV_T`. |
| ``` |
| class cip_base_scoreboard #(type RAL_T = dv_base_reg_block, |
| type CFG_T = cip_base_env_cfg, |
| type COV_T = cip_base_env_cov) extends uvm_component; |
| ``` |
| There are several virtual tasks and functions that are to be overridden |
| in extended IP scoreboard class. Please take a look at the code for more |
| details. |
| |
| ### cip_base_env |
| This is the base UVM env that puts all of the above components together |
| and creates and makes connections across them. In the build phase, it retrieves |
| the env cfg class type handle from `uvm_config_db` as well as all the virtual |
| interfaces (which are actually part of the env cfg class). It then uses the env |
| cfg settings to modify the downstream agent cfg settings as required. All of |
| the above components are created based on env cfg settings, along with the TileLink |
| host agent. In the connect phase, the scoreboard connects with the monitor |
| within the TileLink agent to be able to grab packets from the TL interface |
| during address and the data phases. In the end of elaboration phase, the ral |
| model within the env cfg handle is locked and the ral sequencer and adapters are |
| set to be used with the TileLink interface. |
| |
| This class is type parameterized with env cfg class type CFG_T, coverage class type |
| `COV_T`, virtual sequencer class type `VIRTUAL_SEQUENCER_T` and scoreboard class |
| type `SCOREBOARD_T`. |
| ``` |
| class cip_base_env #(type CFG_T = cip_base_env_cfg, |
| type VIRTUAL_SEQUENCER_T = cip_base_virtual_sequencer, |
| type SCOREBOARD_T = cip_base_scoreboard, |
| type COV_T = cip_base_env_cov) extends uvm_env; |
| ``` |
| |
| ### cip_base_vseq |
| This is the base virtual sequence class that will run on the cip virtual |
| sequencer. This base class provides 'sequencing' set of tasks such as |
| `dut_init()` and `dut_shutdown()` which are called within `pre_start` and |
| `post_start` respectively. This sequence also provides an array of |
| sub-sequences some of which are complete tests within themselves, but |
| implemented as tasks. The reason for doing so is SystemVerilog does not |
| support multi-inheritance so all sub-sequences that are identified as being |
| common to all IP benches implemented as tasks in this base virtual sequence class. |
| Some examples: |
| * **task run_csr_vseq_wrapper**: This is a complete CSR test suite in itself - |
| Extended IP CSR vseq can simply call this in the body. This is paired with a |
| helper function `add_csr_exclusions`. |
| * **function add_csr_exclusions**: This is extended in the IP CSR vseq to add |
| exclusions when running the CSR suite of tests. |
| * **task tl_access**: This is a common generic task to create a read or a write |
| access over the TileLink host interface. |
| * **task cfg_interrupts, check_interrupts**: All interrupt CSRs are standardized |
| according to the comportability spec, which allows us to create common tasks |
| to turn on / off interrupts as well as check them. |
| |
| This class is type parameterized with the env cfg class type `CFG_T`, ral class type |
| `RAL_T` and the virtual sequencer class type `VIRTUAL_SEQUENCER_T` so that the |
| env cfg settings, the ral CSRs are accessible and the `p_sequencer` type can be |
| declared. |
| |
| ``` |
| class cip_base_vseq #(type RAL_T = dv_base_reg_block, |
| type CFG_T = cip_base_env_cfg, |
| type COV_T = cip_base_env_cov, |
| type VIRTUAL_SEQUENCER_T = cip_base_virtual_sequencer) extends uvm_sequence; |
| ``` |
| All virtual sequences in the extended IP will eventually extend from this class and |
| can hence, call these tasks and functions directly as needed. |
| |
| ### cip_base_test |
| This basically creates the IP UVM env and its env cfg class instance. Any env cfg |
| setting that may be required to be controlled externally via plusargs are looked |
| up here, before the env instance is created. This also sets a few variables that |
| pertain to how / when should the test exit on timeout or failure. In the run |
| phase, the test calls `run_seq` which basically uses factory to create the |
| virtual sequence instance using the `UVM_TEST_SEQ` string that is passed via |
| plusarg. As a style guide, it is preferred to encapsulate a complete test within |
| a virtual sequence and use the same `UVM_TEST` plusarg for all of the tests (which |
| points to the extended IP test class), and only change the `UVM_TEST_SEQ` plusarg. |
| |
| This class is type parameterized with the env cfg class type `CFG_T` and the env |
| class type `ENV_T` so that when extended IP test class creates the env and env cfg |
| specific to that IP. |
| ``` |
| class cip_base_test #(type CFG_T = cip_base_env_cfg, |
| type ENV_T = cip_base_env) extends uvm_test; |
| ``` |
| |
| # Extending from CIP library classes |
| Let's say we are verifying an actual comportable IP `uart` which has `uart_tx` |
| and `uart_rx` interface. User then develops the `uart_agent` to be able to talk |
| to that interface. User invokes the `ralgen` tool to generate the `uart_reg_block`, |
| and then starts developing UVM environment by extending from the CIP library |
| classes in the following way. |
| |
| ## uart_env_cfg |
| ``` |
| class uart_env_cfg extends cip_base_env_cfg #(.RAL_T(uart_reg_block)); |
| ``` |
| User adds the `uart_agent_cfg` object as a member so that it remains as a |
| part of the env cfg and can be accessed everywhere. In the base class's |
| `initialize()` function call, an instance of `uart_reg_block` is created, not |
| the `dv_base_reg_block`, since we override the `RAL_T` type. |
| |
| ## uart_env_cov |
| ``` |
| class uart_env_cov extends cip_base_env_cov #(.CFG_T(uart_env_cfg)); |
| ``` |
| User adds `uart` IP specific coverage items and uses the `cov` handle in |
| scoreboard and test sequences to sample the coverage. |
| |
| ## uart_virtual_sequencer |
| ``` |
| class uart_virtual_sequencer extends cip_base_virtual_sequencer #(.CFG_T(uart_env_cfg), |
| .COV_T(uart_env_cov)); |
| ``` |
| User adds the `uart_sequencer` handle to allow layered test sequences |
| to send traffic to / from TileLink as well as `uart` interfaces. |
| |
| ## uart_scoreboard |
| ``` |
| class uart_scoreboard extends cip_base_scoreboard #(.CFG_T(uart_env_cfg), |
| .RAL_T(uart_reg_block), |
| .COV_T(uart_env_cov)); |
| ``` |
| User adds analysis ports to grab packets from the `uart_monitor` to |
| perform end-to-end checking. |
| |
| ## uart_env |
| ``` |
| class uart_env extends cip_base_env #(.CFG_T (uart_env_cfg), |
| .COV_T (uart_env_cov), |
| .VIRTUAL_SEQUENCER_T (uart_virtual_sequencer), |
| .SCOREBOARD_T (uart_scoreboard)); |
| ``` |
| User creates `uart_agent` object in the env and use it to connect with the |
| virtual sequencer and the scoreboard. User also uses the env cfg settings to |
| manipulate the uart agent cfg settings if required. |
| |
| ## uart_base_vseq |
| ``` |
| class uart_base_vseq extends cip_base_vseq #(.CFG_T (uart_env_cfg), |
| .RAL_T (uart_reg_block), |
| .COV_T (uart_env_cov), |
| .VIRTUAL_SEQUENCER_T (uart_virtual_sequencer)); |
| ``` |
| User adds a base virtual sequence as a starting point and adds common tasks and |
| functions to perform `uart` specific operations. User then extends from |
| `uart_base_vseq` to add layered test sequences. |
| |
| ## uart_base_test |
| ``` |
| class uart_base_test extends cip_base_test #(.ENV_T(uart_env), .CFG_T(uart_env_cfg)); |
| ``` |
| User sets `UVM_TEST` plus arg to `uart_base_test` so that all tests create the UVM env |
| that is automatically tailored to UART IP. Each test then sets the |
| `UVM_TEST_SEQ` plusarg to run the specific test sequence, along with additional |
| plusargs as required. |
| |
| # CIP Testbench |
|  |
| The block diagram above shows the CIP testbench architecture, that puts |
| together the static side `tb` which instantiates the `dut`, and the dynamic |
| side, which is the UVM environment extended from CIP library. The diagram |
| lists some common items that need to be instantiated in `tb` |
| and set into `uvm_config_db` for the testbench to work. |