blob: 9bb701b6a71a02c82971d0cd74e2c664080a8dd3 [file] [log] [blame] [view]
# 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.