| # uvmdvgen: UVM agent & complete testbench boilerplate code auto-generation tool |
| |
| uvmdvgen is a python3 based tool to generate the boilerplate code for a UVM agent |
| as well as the complete UVM testbench for a given DUT. The tool generates all |
| the relevant UVM-based classes including the package and the fusesoc core file |
| to make it quickly plug-and-playable. The packages import the standard |
| utility and library packages wherever applicable, to conform to our existing |
| methodology and style. |
| |
| When starting with a new DV effort, user goes through a copy-paste exercise to |
| replicate an existing UVM testbench code to the current one and has to go though |
| several debug cycles to get it working. This tool aims to eliminate that. Also, |
| as a part of OpenTitan DV methodology, we have several utilities and base class |
| structures (such as DV lib and CIP lib) that share all of the common code. By |
| extending a new DV enviroment from the common code, the effort is drastically |
| reducecd. |
| |
| ### Setup |
| The tool uses the mako based templates, so the following tool is required as |
| dependency: |
| ``` |
| $ pip3 install --user mako |
| ``` |
| |
| ### Help switch (-h) |
| Running the tool with `-h` switch provides a brief description of all available |
| switches. |
| ``` |
| $ util/uvmdvgen.py -h |
| usage: uvmdvgen.py [-h] [-a] [-s] [-e] [-c] [-ea [name] [[name] ...]] |
| [-ao [hw/dv/sv]] [-eo [hw/ip/<ip>/dv]] |
| [ip/block name] |
| |
| Command-line tool to autogenerate boilerplate DV testbench code extended from dv_lib / cip_lib |
| |
| positional arguments: |
| [ip/block name] Name of the ip/block for which the UVM TB is being |
| auto-generated |
| |
| optional arguments: |
| -h, --help show this help message and exit |
| -a, --gen_agent Generate UVM agent code extended from DV library |
| -s, --has_separate_host_device_driver |
| IP / block agent creates a separate driver for host |
| and device modes. (ignored if -a switch is not passed) |
| -e, --gen_env Generate testbench UVM environment code |
| -c, --is_cip Is comportable IP - this will result in code being |
| extended from CIP library. If switch is not passed, |
| then the code will be extended from DV library |
| instead. (ignored if -e switch is not passed) |
| -ea agt1 agt2 [agt1 agt2 ...], --env_agents agt1 agt2 [agt1 agt2 ...] |
| Env creates an interface agent specified here. They are |
| assumed to already exist. Note that the list is space- |
| separated, and not comma-separated. (ignored if -e |
| switch is not passed) |
| -ao [hw/dv/sv], --agent_outdir [hw/dv/sv] |
| Path to place the agent code. A directory called |
| <name>_agent is created at this location. (default set |
| to './<name>') |
| -eo [hw/ip/<ip>/dv], --env_outdir [hw/ip/<ip>/dv] |
| Path to place the env code. 3 directories are created |
| - env, tb and tests. (default set to './<name>') |
| ``` |
| |
| ### Generating UVM agent |
| The boilerplate code for a UVM agent for an interface can be generated using the |
| `-a` switch. This results in the generation of complete agent with classes that |
| extend from the [dv library](../../hw/dv/sv/dv_lib/README.md). Please see |
| description for more details. |
| |
| The tool generates an interface, item, cfg, cov, monitor, driver and sequence |
| library classes. Let's take `jtag` as the argument passed for the name of the IP. |
| The following describes their contents in each source generated: |
| |
| * **jtag_if** |
| |
| This is an empty shell of an interface. User is required to add content. |
| |
| * **jtag_item** |
| |
| This is an empty transaction packet extended from `uvm_sequence_item`. |
| |
| * **jtag_agent_cfg** |
| |
| This is the agent configuration object, it contains the virtual interface |
| handle for `jtag_if` and is called `vif`. |
| |
| * **jtag_agent_cov** |
| |
| This is a coverage component extended from `dv_base_agent_cov`. |
| |
| * **jtag_monitor** |
| |
| This is the monitor component extended from `dv_base_monitor`. It provides |
| the following items: |
| * **virtual protected task collect_trans(uvm_phase phase)** |
| |
| This is a shell task within which user is required to add logic to detect |
| an event, sample the interface and create a transaction object and write |
| to the analysis port. This task is called in `dv_base_monitor::run_phase`. |
| |
| * **jtag_driver** |
| |
| This is the monitor component extended from `jtag_driver` which is typedef'ed |
| in the pkg to `dv_base_driver` with the right parameter set. It provides the |
| following items: |
| * **virtual task reset_signals()** |
| |
| This task is for resetting the initial value of the `vif` signals. |
| |
| * **virtual task get_and_drive()** |
| |
| This task is used to get the next item from the sequencer, apply it to the |
| interface and return the response back. This is again, an empty task at the |
| moment. |
| |
| If the `-s` switch is passed, the tool creates `jtag_host_driver` and |
| `jtag_device_driver` instead, and their contents are exactly the same. |
| |
| * **seq_lib/jtag_base_seq** |
| |
| This is extended from `dv_base_seq`. |
| |
| * **seq_lib/jtag_seq_list** |
| |
| This is a list of sequences included in one place. |
| |
| * **jtag_agent_pkg** |
| |
| This is the package file that includes all of the above sources and the imports |
| the dependent packages. |
| |
| * **jtag_agent.core** |
| |
| This is the fusesoc core file that is used to generate the filelist for |
| the build. |
| |
| The tool does not create `jtag_sequencer` or `jtag_agent` classes separetely. |
| Instead, it typedef's the `dv_base_sequencer` and `dv_base_agent` respectively |
| with the right type-parameters in the pkg. The reason for this is having a |
| dedicated sequencer and agent is not required since the `dv_base_agent` already |
| has all the sub-component instantiations and connections; and `dv_base_sequencer` |
| already has a handle to the agent cfg object and nothing more is typically needed. |
| |
| ### Generating UVM environment & testbench |
| The boilerplate code for a UVM environment and the testbench for a DUT can be |
| generated using the `-e` switch. This results in the generation of classes |
| that extend from [dv library](../../hw/dv/sv/dv_lib/README.md). If the `-c` |
| switch is passed, it extends from [cip library](../../hw/dv/sv/cip_lib/README.md). |
| With `-ea` switch, user can provide a list of downstream agents to create within |
| the environment. |
| Please see description for more details. |
| |
| The tool generates not only the UVM environment, but also the base test, |
| testbench, top level fusesoc core file with sim target, Makefile that already |
| includes the sanity and CSR test suite and more. With just a few tweaks, this |
| enables the user to reach the V1 milestone much quicker. Let's take `i2c_host` |
| as the argument passed for the name of the IP. The following is the list of |
| files generated with a brief description of their contents: |
| |
| * **env/i2c_host_env_cfg** |
| |
| This is the env cfg object. It creates the downstream agent cfg objects that |
| were passed using the `-ea` switch in the ``initialize()` function which is |
| called in the `dv_base_test::build_phase()`. Since the cfg handle is passed to |
| all env components, those downstream agent cfg objects can be hierarchically |
| referenced. |
| |
| * **env/i2c_host_env_cov** |
| |
| This is the coverage component class. A handle of this class is passed to the |
| scoreboard and the virtual sequencer so that covergroups can be sampled in the |
| scoreboard as well as sequences. |
| |
| * **env/i2c_host_reg_block** |
| |
| This is the UVM reg based RAL model. This is created for completeness. The |
| actual RAL model needs to be generated prior to running simulations using the |
| [regtool](../reggen/README.md). |
| |
| * **env/i2c_host_scoreboard** |
| |
| This is the scoreboard component that already creates the analysis fifos and |
| queues for the agents passed via `-ea` switch. It adds starter tasks for |
| processing each fifo in a forever loop and invokes them in the `run_phase` |
| using `fork-join` statement. If the `-c` switch is passed, it also adds a |
| `process_tl_access` task that is extended from `cip_base_scoreboard`. This |
| task provides a tilelink access packet for further processing. |
| |
| * **env/i2c_host_virtual_sequencer** |
| |
| This is the virtual sequencer used by all test sequences to run the traffic. |
| It adds handles to downstream agent sequencers passed via `-ea` switch. |
| Sub-sequences can be started on them via the `p_sequencer` handle. |
| |
| * **env/seq_lib/i2c_host_base_vseq** |
| |
| This is the base virtual sequence that user can use to add common tasks, |
| functions and variables that other extended test sequences can reuse. For |
| starters, it provides the `i2s_host_init()` task and `do_i2c_host_init` knob |
| for controllability. |
| |
| * **env/seq_lib/i2c_host_sanity_vseq** |
| |
| This is the basic sanity test sequence that user needs to develop as the first |
| test sequence. It extends from `i2s_host_base_vseq`. |
| |
| * **env/seq_lib/i2c_host_csr_vseq** |
| |
| This is the test sequence for the entire CSR suite of tests. It calls |
| `dv_base_vseq::run_csr_vseq_wrapper()` task which is a complete test sequence. |
| All the user needs to do is run the CSR tests and add exclusions if needed |
| using the `add_csr_exclusions()` function provided. |
| |
| * **env/seq_lib/i2c_host_vseq_list** |
| |
| This is a list of test sequences included in one place. |
| |
| * **env/i2c_host_env** |
| |
| This is the env class that creates the downstream agents passed via `-ea` |
| switch. It sets their correspodnding cfg objects (which are members of env cfg |
| object) into the `uvm_config_db`. It also makes the analysis port connections |
| in the `connect_phase` and sets the sequencer handles in the virtual |
| sequencer. |
| |
| * **env/i2c_host_env_pkg** |
| |
| This is the env pkg file which includes all env classes and imports the |
| dependent packages. |
| |
| * **env/i2c_host_env.core** |
| |
| This is the fusesoc core file for the env pkg compile unit. |
| |
| * **tests/i2c_host_base_test** |
| |
| This is the base test class. The base test class it extends from already |
| creates the `env` and `cfg` objects, which are available for manipulation in |
| UVM phases. This class's name would be supplied to UVM_TESTNAME plusarg to run |
| tests using the UVM methodology. |
| |
| * **tests/i2c_host_test_pkg** |
| |
| This is the test pkg file which includes all test classes and imports the |
| dependent packages. |
| |
| * **tests/i2c_host_test.core** |
| |
| This is the fusesoc core file for the test pkg compile unit. |
| |
| * **tb/i2c_host_bind** |
| |
| This is the assertion bind file that is compiled along with the testbench in a |
| multi-top architecture. If the `-c` switch is passed, it adds the `tlul_assert` |
| module bind to the `i2c_host` DUT. |
| |
| * **tb/tb** |
| |
| This is the top level testbench module that instantiates the DUT along with |
| some of the interfaces that are required to be instantiated and connected and |
| passed on the the `uvm_config_db` since the base DV/CIP library classes |
| retrieve them. The user needs to look through the RTL and make additional |
| connections as needed. |
| |
| * **i2c_host_sim.core** |
| |
| This is the top level fusesoc core file with the sim target. It adds the rtl |
| and dv dependencies to construct the complete filelist to pass to simulator's |
| build step. |
| |
| * **Makefile** |
| |
| This is the simulation Makefile that is used as the starting point for |
| building and running tests using the [make flow](../../hw/dv/tools/README.md). |
| It already includes the sanity and CSR suite of tests to allow users to start |
| running tests right away. |
| |
| * **plan.md** |
| |
| This is the empty DV plan document that will describe the entire testbench. A |
| template for this is available [here](../../hw/dv/doc/plan.tpl.md). |
| |
| #### Examples |
| ``` |
| util/uvmdvgen.py i2c -a |
| ``` |
| This will create `./i2c/i2c_agent` and place all sources there. |
| |
| ``` |
| util/uvmdvgen.py jtag -a -ao hw/dv/sv |
| ``` |
| This will create `hw/dv/sv/jtag_agent` directory and place all the sources |
| there. |
| |
| ``` |
| util/uvmdvgen.py i2c -a -s -ao hw/dv/sv |
| ``` |
| This will create the I2C agent with separate 'host' mode and 'device' mode drivers. |
| |
| ``` |
| util/uvmdvgen.py i2c_host -e -c -ea i2c -eo hw/ip/i2c_host/dv |
| ``` |
| This will create the complete i2c_host dv testbench extended from CIP lib and will |
| instantiate `i2c_agent`. |
| |
| ``` |
| util/uvmdvgen.py dma -e -eo hw/ip/dma/dv |
| ``` |
| This will create the complete dma dv testbench extended from DV lib. It does not |
| instantiate any downstream agents due to absence of `-ea` switch. |
| |
| ``` |
| util/uvmdvgen.py chip -e -ea uart i2c jtag -eo hw/top_earlgrey/dv |
| ``` |
| This will create the complete chip testbench DV lib and will instantiate `uart_agent`, |
| `i2c_agent` and `jtag_agent` in the env. |