Start of public OpenTitan development history
Code contributors:
Alex Bradbury <asb@lowrisc.org>
Cindy Chen <chencindy@google.com>
Eunchan Kim <eunchan@google.com>
Gaurang Chitroda <gaurangg@google.com>
Mark Hayter <mark.hayter@gmail.com>
Michael Schaffner <msf@google.com>
Miguel Osorio <miguelosorio@google.com>
Nils Graf <nilsg@google.com>
Philipp Wagner <phw@lowrisc.org>
Pirmin Vogel <vogelpi@lowrisc.org>
Ram Babu Penugonda <rampenugonda@google.com>
Scott Johnson <scottdj@google.com>
Shail Kushwah <kushwahs@google.com>
Srikrishna Iyer <sriyer@google.com>
Steve Nelson <Steve.Nelson@wdc.com>
Tao Liu <taliu@google.com>
Timothy Chen <timothytim@google.com>
Tobias Wölfel <tobias.woelfel@mailbox.org>
Weicai Yang <weicai@google.com>
diff --git a/util/uvmdvgen/Makefile.tpl b/util/uvmdvgen/Makefile.tpl
new file mode 100644
index 0000000..cd358c8
--- /dev/null
+++ b/util/uvmdvgen/Makefile.tpl
@@ -0,0 +1,71 @@
+${'####################################################################################################'}
+${'## Copyright lowRISC contributors. ##'}
+${'## Licensed under the Apache License, Version 2.0, see LICENSE for details. ##'}
+${'## SPDX-License-Identifier: Apache-2.0 ##'}
+${'####################################################################################################'}
+${'## Entry point test Makefile forr building and running tests. ##'}
+${'## These are generic set of option groups that apply to all testbenches. ##'}
+${'## This flow requires the following options to be set: ##'}
+${'## DV_DIR - current dv directory that contains the test Makefile ##'}
+${'## DUT_TOP - top level dut module name ##'}
+${'## TB_TOP - top level tb module name ##'}
+${'## DOTF - .f file used for compilation ##'}
+${'## COMPILE_KEY - compile option set ##'}
+${'## TEST_NAME - name of the test to run - this is supplied on the command line ##'}
+${'####################################################################################################'}
+DV_DIR := ${'$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))'}
+export DUT_TOP := ${name}
+export TB_TOP := tb
+FUSESOC_CORE := lowrisc:dv:${name}_sim:0.1
+COMPILE_KEY ?= default
+
+UVM_TEST ?= ${name}_base_test
+UVM_TEST_SEQ ?= ${name}_base_vseq
+
+${'####################################################################################################'}
+${'## A D D I N D I V I D U A L T E S T S B E L O W ##'}
+${'####################################################################################################'}
+TEST_NAME ?= ${name}_sanity
+UVM_TEST ?= ${name}_base_test
+UVM_TEST_SEQ ?= ${name}_base_vseq
+
+ifeq (${'$'}{TEST_NAME},${name}_sanity)
+ UVM_TEST_SEQ = ${name}_sanity_vseq
+endif
+
+ifeq (${'$'}{TEST_NAME},${name}_csr_hw_reset)
+ UVM_TEST_SEQ = ${name}_csr_vseq
+ RUN_OPTS += +csr_hw_reset
+ RUN_OPTS += +en_scb=0
+endif
+
+ifeq (${'$'}{TEST_NAME},${name}_csr_rw)
+ UVM_TEST_SEQ = ${name}_csr_vseq
+ RUN_OPTS += +csr_rw
+ RUN_OPTS += +en_scb=0
+endif
+
+ifeq (${'$'}{TEST_NAME},${name}_csr_bit_bash)
+ UVM_TEST_SEQ = ${name}_csr_vseq
+ RUN_OPTS += +csr_bit_bash
+ RUN_OPTS += +en_scb=0
+endif
+
+ifeq (${'$'}{TEST_NAME},${name}_csr_aliasing)
+ UVM_TEST_SEQ = ${name}_csr_vseq
+ RUN_OPTS += +csr_aliasing
+ RUN_OPTS += +en_scb=0
+endif
+
+${'# TODO: remove this test if there are no memories in the DUT'}
+ ifeq (${'$'}{TEST_NAME},${name}_mem_walk)
+ UVM_TEST_SEQ = ${name}_csr_vseq
+ RUN_OPTS += +csr_mem_walk
+ RUN_OPTS += +en_scb=0
+endif
+
+${'####################################################################################################'}
+${'## Include the tool Makefile below ##'}
+${'## Dont add anything else below it! ##'}
+${'####################################################################################################'}
+include ${'$'}{DV_DIR}/../../../dv/tools/Makefile
diff --git a/util/uvmdvgen/README.md b/util/uvmdvgen/README.md
new file mode 100644
index 0000000..9bb701b
--- /dev/null
+++ b/util/uvmdvgen/README.md
@@ -0,0 +1,317 @@
+# 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.
diff --git a/util/uvmdvgen/README.md.tpl b/util/uvmdvgen/README.md.tpl
new file mode 100644
index 0000000..4164db7
--- /dev/null
+++ b/util/uvmdvgen/README.md.tpl
@@ -0,0 +1,3 @@
+{{% lowrisc-doc-hdr ${name.upper()} DV UVM Agent }}
+
+${name.upper()} DV UVM Agent is extended from DV library agent classes.
diff --git a/util/uvmdvgen/__init__.py b/util/uvmdvgen/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/util/uvmdvgen/__init__.py
diff --git a/util/uvmdvgen/agent.core.tpl b/util/uvmdvgen/agent.core.tpl
new file mode 100644
index 0000000..0acc9c8
--- /dev/null
+++ b/util/uvmdvgen/agent.core.tpl
@@ -0,0 +1,33 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:${name}_agent:0.1"
+description: "${name.upper()} DV UVM agent"
+filesets:
+ files_dv:
+ depend:
+ - lowrisc:dv:dv_utils
+ - lowrisc:dv:dv_lib
+ files:
+ - ${name}_if.sv
+ - ${name}_agent_pkg.sv
+ - ${name}_agent_cfg.sv: {is_include_file: true}
+ - ${name}_agent_cov.sv: {is_include_file: true}
+ - ${name}_item.sv: {is_include_file: true}
+% if has_separate_host_device_driver:
+ - ${name}_host_driver.sv: {is_include_file: true}
+ - ${name}_device_driver.sv: {is_include_file: true}
+% else:
+ - ${name}_driver.sv: {is_include_file: true}
+% endif
+ - ${name}_monitor.sv: {is_include_file: true}
+ - ${name}_agent.sv: {is_include_file: true}
+ - seq_lib/${name}_base_seq.sv: {is_include_file: true}
+ - seq_lib/${name}_seq_list.sv: {is_include_file: true}
+ file_type: systemVerilogSource
+
+targets:
+ default:
+ filesets:
+ - files_dv
diff --git a/util/uvmdvgen/agent.sv.tpl b/util/uvmdvgen/agent.sv.tpl
new file mode 100644
index 0000000..e6ac624
--- /dev/null
+++ b/util/uvmdvgen/agent.sv.tpl
@@ -0,0 +1,28 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class ${name}_agent extends dv_base_agent #(
+ .CFG_T (${name}_agent_cfg),
+ .DRIVER_T (${name}_driver),
+% if has_separate_host_device_driver:
+ .HOST_DRIVER_T (${name}_host_driver),
+ .DEVICE_DRIVER_T(${name}_device_driver),
+% endif
+ .SEQUENCER_T (${name}_sequencer),
+ .MONITOR_T (${name}_monitor),
+ .COV_T (${name}_agent_cov)
+ );
+
+ `uvm_component_utils(${name}_agent)
+
+ `uvm_component_new
+
+ function void build_phase(uvm_phase phase);
+ super.build_phase(phase);
+ // get ${name}_if handle
+ if (!uvm_config_db#(virtual ${name}_if)::get(this, "", "vif", cfg.vif))
+ `uvm_fatal(`gfn, "failed to get ${name}_if handle from uvm_config_db")
+ endfunction
+
+endclass
diff --git a/util/uvmdvgen/agent_cfg.sv.tpl b/util/uvmdvgen/agent_cfg.sv.tpl
new file mode 100644
index 0000000..f052017
--- /dev/null
+++ b/util/uvmdvgen/agent_cfg.sv.tpl
@@ -0,0 +1,15 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class ${name}_agent_cfg extends dv_base_agent_cfg;
+
+// interface handle used by driver, monitor & the sequencer, via cfg handle
+ virtual ${name}_if vif;
+
+ `uvm_object_utils_begin(${name}_agent_cfg)
+ `uvm_object_utils_end
+
+ `uvm_object_new
+
+endclass
diff --git a/util/uvmdvgen/agent_cov.sv.tpl b/util/uvmdvgen/agent_cov.sv.tpl
new file mode 100644
index 0000000..91e48d4
--- /dev/null
+++ b/util/uvmdvgen/agent_cov.sv.tpl
@@ -0,0 +1,18 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class ${name}_agent_cov extends dv_base_agent_cov #(${name}_agent_cfg);
+ `uvm_component_utils(${name}_agent_cov)
+
+ // the base class provides the following handles for use:
+ // ${name}_agent_cfg: cfg
+
+ // covergroups
+
+ function new(string name, uvm_component parent);
+ super.new(name, parent);
+ // instantiate all covergroups here
+ endfunction : new
+
+endclass
diff --git a/util/uvmdvgen/agent_pkg.sv.tpl b/util/uvmdvgen/agent_pkg.sv.tpl
new file mode 100644
index 0000000..e6630e2
--- /dev/null
+++ b/util/uvmdvgen/agent_pkg.sv.tpl
@@ -0,0 +1,49 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+package ${name}_agent_pkg;
+ // dep packages
+ import uvm_pkg::*;
+ import dv_utils_pkg::*;
+ import dv_lib_pkg::*;
+
+ // macro includes
+ `include "uvm_macros.svh"
+ `include "dv_macros.svh"
+
+ // parameters
+
+ // local types
+ // forward declare classes to allow typedefs below
+ typedef class ${name}_item;
+ typedef class ${name}_agent_cfg;
+
+% if has_separate_host_device_driver:
+ // add typedef for ${name}_driver which is dv_base_driver with the right parameter set
+ // ${name}_host_driver and ${name}_device_driver will extend from this
+ typedef dv_base_driver #(.ITEM_T (${name}_item),
+ .CFG_T (${name}_agent_cfg)) ${name}_driver;
+
+% endif
+ // reuse dv_base_seqeuencer as is with the right parameter set
+ typedef dv_base_sequencer #(.ITEM_T (${name}_item),
+ .CFG_T (${name}_agent_cfg)) ${name}_sequencer;
+
+ // functions
+
+ // package sources
+ `include "${name}_item.sv"
+ `include "${name}_agent_cfg.sv"
+ `include "${name}_agent_cov.sv"
+% if has_separate_host_device_driver:
+ `include "${name}_host_driver.sv"
+ `include "${name}_device_driver.sv"
+% else:
+ `include "${name}_driver.sv"
+% endif
+ `include "${name}_monitor.sv"
+ `include "${name}_agent.sv"
+ `include "${name}_seq_list.sv"
+
+ endpackage: ${name}_agent_pkg
diff --git a/util/uvmdvgen/base_seq.sv.tpl b/util/uvmdvgen/base_seq.sv.tpl
new file mode 100644
index 0000000..e3f523d
--- /dev/null
+++ b/util/uvmdvgen/base_seq.sv.tpl
@@ -0,0 +1,17 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class ${name}_base_seq extends dv_base_seq #(
+ .CFG_T (${name}_agent_cfg),
+ .SEQUENCER_T (${name}_sequencer)
+ );
+ `uvm_object_utils(${name}_base_seq)
+
+ `uvm_object_new
+
+ virtual task body();
+ `uvm_fatal(`gtn, "Need to override this when you extend from this class!")
+ endtask
+
+endclass
diff --git a/util/uvmdvgen/base_test.sv.tpl b/util/uvmdvgen/base_test.sv.tpl
new file mode 100644
index 0000000..d713bdf
--- /dev/null
+++ b/util/uvmdvgen/base_test.sv.tpl
@@ -0,0 +1,20 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class ${name}_base_test extends dv_base_test #(
+ .ENV_T(${name}_env),
+ .CFG_T(${name}_env_cfg)
+ );
+ `uvm_component_utils(${name}_base_test)
+ `uvm_component_new
+
+ // the base class dv_base_test creates the following instances:
+ // ${name}_env_cfg: cfg
+ // ${name}_env: env
+
+ // the base class also looks up UVM_TEST_SEQ plusarg to create and run that seq in
+ // the run_phase; as such, nothing more needs to be done
+
+endclass : ${name}_base_test
+
diff --git a/util/uvmdvgen/base_vseq.sv.tpl b/util/uvmdvgen/base_vseq.sv.tpl
new file mode 100644
index 0000000..4278bfc
--- /dev/null
+++ b/util/uvmdvgen/base_vseq.sv.tpl
@@ -0,0 +1,37 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+% if is_cip:
+class ${name}_base_vseq extends cip_base_vseq #(
+% else:
+class ${name}_base_vseq extends dv_base_vseq #(
+% endif
+ .CFG_T (${name}_env_cfg),
+ .RAL_T (${name}_reg_block),
+ .COV_T (${name}_env_cov),
+ .VIRTUAL_SEQUENCER_T (${name}_virtual_sequencer)
+ );
+ `uvm_object_utils(${name}_base_vseq)
+
+ // various knobs to enable certain routines
+ bit do_${name}_init = 1'b1;
+
+ `uvm_object_new
+
+ virtual task dut_init(string reset_kind = "HARD");
+ super.dut_init();
+ if (do_${name}_init) ${name}_init();
+ endtask
+
+ virtual task dut_shutdown();
+ // check for pending ${name} operations and wait for them to complete
+ // TODO
+ endtask
+
+ // setup basic ${name} features
+ virtual task ${name}_init();
+ `uvm_error(`gfn, "FIXME")
+ endtask
+
+endclass : ${name}_base_vseq
diff --git a/util/uvmdvgen/bind.sv.tpl b/util/uvmdvgen/bind.sv.tpl
new file mode 100644
index 0000000..9570e68
--- /dev/null
+++ b/util/uvmdvgen/bind.sv.tpl
@@ -0,0 +1,16 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+module ${name}_bind;
+% if is_cip:
+
+ bind ${name} tlul_assert tlul_assert (
+ .clk_i,
+ .rst_ni,
+ .h2d (tl_i),
+ .d2h (tl_o)
+ );
+% endif
+
+endmodule
diff --git a/util/uvmdvgen/csr_vseq.sv.tpl b/util/uvmdvgen/csr_vseq.sv.tpl
new file mode 100644
index 0000000..bbdce09
--- /dev/null
+++ b/util/uvmdvgen/csr_vseq.sv.tpl
@@ -0,0 +1,30 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class ${name}_csr_vseq extends ${name}_base_vseq;
+ `uvm_object_utils(${name}_csr_vseq)
+
+ constraint num_trans_c {
+ num_trans inside {[1:2]};
+ }
+ `uvm_object_new
+
+ virtual task body();
+ run_csr_vseq_wrapper(num_trans);
+ endtask : body
+
+ // function to add csr exclusions of the given type using the csr_excl_item item
+ virtual function void add_csr_exclusions(string csr_test_type,
+ csr_excl_item csr_excl,
+ string scope = "ral");
+
+ // write exclusions - these should not apply to hw_reset test
+ if (csr_test_type != "hw_reset") begin
+ // TODO: below is a sample
+ // status reads back unexpected values due to writes to other csrs
+ // csr_excl.add_excl({scope, ".", "status"}, CsrExclWriteCheck);
+ end
+ endfunction
+
+endclass
diff --git a/util/uvmdvgen/device_driver.sv.tpl b/util/uvmdvgen/device_driver.sv.tpl
new file mode 100644
index 0000000..ae46511
--- /dev/null
+++ b/util/uvmdvgen/device_driver.sv.tpl
@@ -0,0 +1,26 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class ${name}_device_driver extends ${name}_driver;
+ `uvm_component_utils(${name}_device_driver)
+
+ // the base class provides the following handles for use:
+ // ${name}_agent_cfg: cfg
+
+ `uvm_component_new
+
+ virtual task run_phase(uvm_phase phase);
+ // base class forks off reset_signals() and get_and_drive() tasks
+ super.run_phase(phase);
+ endtask
+
+ // reset signals
+ virtual task reset_signals();
+ endtask
+
+ // drive trans received from sequencer
+ virtual task get_and_drive();
+ endtask
+
+endclass
diff --git a/util/uvmdvgen/driver.sv.tpl b/util/uvmdvgen/driver.sv.tpl
new file mode 100644
index 0000000..074280c
--- /dev/null
+++ b/util/uvmdvgen/driver.sv.tpl
@@ -0,0 +1,37 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class ${name}_driver extends dv_base_driver #(${name}_item, ${name}_agent_cfg);
+ `uvm_component_utils(${name}_driver)
+
+ // the base class provides the following handles for use:
+ // ${name}_agent_cfg: cfg
+
+ `uvm_component_new
+
+ virtual task run_phase(uvm_phase phase);
+ // base class forks off reset_signals() and get_and_drive() tasks
+ super.run_phase(phase);
+ endtask
+
+ // reset signals
+ virtual task reset_signals();
+ endtask
+
+ // drive trans received from sequencer
+ virtual task get_and_drive();
+ forever begin
+ seq_item_port.get_next_item(req);
+ $cast(rsp, req.clone());
+ rsp.set_id_info(req);
+ `uvm_info(`gfn, $sformatf("rcvd item:\n%0s", req.sprint()), UVM_HIGH)
+ // TODO: do the driving part
+ //
+ // send rsp back to seq
+ `uvm_info(`gfn, "item sent", UVM_HIGH)
+ seq_item_port.item_done(rsp);
+ end
+ endtask
+
+endclass
diff --git a/util/uvmdvgen/env.core.tpl b/util/uvmdvgen/env.core.tpl
new file mode 100644
index 0000000..ecc6081
--- /dev/null
+++ b/util/uvmdvgen/env.core.tpl
@@ -0,0 +1,34 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:${name}_env:0.1"
+description: "${name.upper()} DV UVM environment"
+filesets:
+ files_dv:
+ depend:
+% if is_cip:
+ - lowrisc:dv:cip_lib
+% else:
+ - lowrisc:dv:dv_lib
+% endif
+% for agent in env_agents:
+ - lowrisc:dv:${agent}_agent
+% endfor
+ files:
+ - ${name}_env_pkg.sv
+ - ${name}_env_cfg.sv: {is_include_file: true}
+ - ${name}_env_cov.sv: {is_include_file: true}
+ - ${name}_env.sv: {is_include_file: true}
+ - ${name}_reg_block.sv: {is_include_file: true}
+% if env_agents != []:
+ - ${name}_virtual_sequencer.sv: {is_include_file: true}
+% endif
+ - ${name}_scoreboard.sv: {is_include_file: true}
+ - seq_lib/${name}_vseq_list.sv: {is_include_file: true}
+ file_type: systemVerilogSource
+
+targets:
+ default:
+ filesets:
+ - files_dv
diff --git a/util/uvmdvgen/env.sv.tpl b/util/uvmdvgen/env.sv.tpl
new file mode 100644
index 0000000..58773e9
--- /dev/null
+++ b/util/uvmdvgen/env.sv.tpl
@@ -0,0 +1,51 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+% if is_cip:
+class ${name}_env extends cip_base_env #(
+% else:
+class ${name}_env extends dv_base_env #(
+% endif
+ .CFG_T (${name}_env_cfg),
+ .COV_T (${name}_env_cov),
+ .VIRTUAL_SEQUENCER_T(${name}_virtual_sequencer),
+ .SCOREBOARD_T (${name}_scoreboard)
+ );
+ `uvm_component_utils(${name}_env)
+% if env_agents != []:
+
+% for agent in env_agents:
+ ${agent}_agent m_${agent}_agent;
+% endfor
+% endif
+
+ `uvm_component_new
+
+ function void build_phase(uvm_phase phase);
+ super.build_phase(phase);
+% for agent in env_agents:
+ m_${agent}_agent = ${agent}_agent::type_id::create("m_${agent}_agent", this);
+ uvm_config_db#(${agent}_agent_cfg)::set(this, "m_${agent}_agent*", "cfg", cfg.m_${agent}_agent_cfg);
+% endfor
+ endfunction
+
+ function void connect_phase(uvm_phase phase);
+ super.connect_phase(phase);
+% if env_agents != []:
+ if (cfg.en_scb) begin
+% endif
+% for agent in env_agents:
+ m_${agent}_agent.monitor.analysis_port.connect(scoreboard.${agent}_fifo.analysis_export);
+% endfor
+% if env_agents != []:
+ end
+% endif
+% for agent in env_agents:
+ if (cfg.is_active && cfg.m_${agent}_agent_cfg.is_active) begin
+ virtual_sequencer.${agent}_sequencer_h = m_${agent}_agent.sequencer;
+ end
+% endfor
+ endfunction
+
+endclass
diff --git a/util/uvmdvgen/env_cfg.sv.tpl b/util/uvmdvgen/env_cfg.sv.tpl
new file mode 100644
index 0000000..fb13359
--- /dev/null
+++ b/util/uvmdvgen/env_cfg.sv.tpl
@@ -0,0 +1,39 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+% if is_cip:
+class ${name}_env_cfg extends cip_base_env_cfg #(.RAL_T(${name}_reg_block));
+% else:
+class ${name}_env_cfg extends dv_base_env_cfg #(.RAL_T(${name}_reg_block));
+% endif
+
+ // ext component cfgs
+% for agent in env_agents:
+ rand ${agent}_agent_cfg m_${agent}_agent_cfg;
+% endfor
+
+ `uvm_object_utils_begin(${name}_env_cfg)
+% for agent in env_agents:
+ `uvm_field_object(m_${agent}_agent_cfg, UVM_DEFAULT)
+% endfor
+ `uvm_object_utils_end
+
+ `uvm_object_new
+
+ virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1,
+ bit [TL_AW-1:0] csr_addr_map_size = 2048);
+ super.initialize();
+% for agent in env_agents:
+ // create ${agent} agent config obj
+ m_${agent}_agent_cfg = ${agent}_agent_cfg::type_id::create("m_${agent}_agent_cfg");
+% endfor
+% if is_cip:
+
+ // set num_interrupts & num_alerts which will be used to create coverage and more
+ num_interrupts = ral.intr_state.get_n_used_bits();
+ num_alerts = 0;
+% endif
+ endfunction
+
+endclass
diff --git a/util/uvmdvgen/env_cov.sv.tpl b/util/uvmdvgen/env_cov.sv.tpl
new file mode 100644
index 0000000..c07b312
--- /dev/null
+++ b/util/uvmdvgen/env_cov.sv.tpl
@@ -0,0 +1,22 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+% if is_cip:
+class ${name}_env_cov extends cip_base_env_cov #(.CFG_T(${name}_env_cfg));
+% else:
+class ${name}_env_cov extends dv_base_env_cov #(.CFG_T(${name}_env_cfg));
+% endif
+ `uvm_component_utils(${name}_env_cov)
+
+ // the base class provides the following handles for use:
+ // ${name}_env_cfg: cfg
+
+ // covergroups
+
+ function new(string name, uvm_component parent);
+ super.new(name, parent);
+ // instantiate all covergroups here
+ endfunction : new
+
+endclass
diff --git a/util/uvmdvgen/env_pkg.sv.tpl b/util/uvmdvgen/env_pkg.sv.tpl
new file mode 100644
index 0000000..c2eea67
--- /dev/null
+++ b/util/uvmdvgen/env_pkg.sv.tpl
@@ -0,0 +1,59 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+package ${name}_env_pkg;
+ // dep packages
+ import uvm_pkg::*;
+ import top_pkg::*;
+ import dv_utils_pkg::*;
+ import csr_utils_pkg::*;
+ import tl_agent_pkg::*;
+% for agent in env_agents:
+ import ${agent}_agent_pkg::*;
+% endfor
+ import dv_lib_pkg::*;
+% if is_cip:
+ import cip_base_pkg::*;
+% endif
+
+ // macro includes
+ `include "uvm_macros.svh"
+ `include "dv_macros.svh"
+
+ // parameters
+
+ // types
+% if env_agents == []:
+ // forward declare classes to allow typedefs below
+ typedef class ${name}_env_cfg;
+ typedef class ${name}_env_cov;
+
+% endif
+% if env_agents == [] and is_cip:
+ // reuse cip_base_virtual_seqeuencer as is with the right parameter set
+ typedef class cip_base_virtual_sequencer #(
+% elif env_agents == [] and not is_cip:
+ // reuse dv_base_virtual_seqeuencer as is with the right parameter set
+ typedef class dv_base_virtual_sequencer #(
+% endif
+% if env_agents == []:
+ .CFG_T(${name}_env_cfg),
+ .COV_T(${name}_env_cov)
+ ) ${name}_virtual_sequencer;
+% endif
+
+ // functions
+
+ // package sources
+ `include "${name}_reg_block.sv"
+ `include "${name}_env_cfg.sv"
+ `include "${name}_env_cov.sv"
+% if env_agents != []:
+ `include "${name}_virtual_sequencer.sv"
+% endif
+ `include "${name}_scoreboard.sv"
+ `include "${name}_env.sv"
+ `include "${name}_vseq_list.sv"
+
+endpackage
diff --git a/util/uvmdvgen/gen_agent.py b/util/uvmdvgen/gen_agent.py
new file mode 100644
index 0000000..afb848a
--- /dev/null
+++ b/util/uvmdvgen/gen_agent.py
@@ -0,0 +1,59 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+"""Generate SystemVerilog UVM agent extended freom our DV lib
+"""
+
+import os
+
+from mako.template import Template
+from pkg_resources import resource_filename
+
+
+def gen_agent(name, has_separate_host_device_driver, root_dir):
+ # set sub name
+ agent_dir = root_dir + "/" + name + "_agent"
+
+ # yapf: disable
+ # 4-tuple - path, ip name, class name, file ext
+ agent_srcs = [(agent_dir, name + '_', 'if', '.sv'),
+ (agent_dir, name + '_', 'item', '.sv'),
+ (agent_dir, name + '_', 'agent_cfg', '.sv'),
+ (agent_dir, name + '_', 'agent_cov', '.sv'),
+ (agent_dir, name + '_', 'monitor', '.sv'),
+ (agent_dir, name + '_', 'driver', '.sv'),
+ (agent_dir, name + '_', 'host_driver', '.sv'),
+ (agent_dir, name + '_', 'device_driver', '.sv'),
+ (agent_dir, name + '_', 'agent_pkg', '.sv'),
+ (agent_dir, name + '_', 'agent', '.sv'),
+ (agent_dir, name + '_', 'agent', '.core'),
+ (agent_dir, "", 'README', '.md'),
+ (agent_dir + "/seq_lib", name + '_', 'seq_list', '.sv'),
+ (agent_dir + "/seq_lib", name + '_', 'base_seq', '.sv')]
+ # yapf: enable
+
+ for tup in agent_srcs:
+ path_dir = tup[0]
+ src_prefix = tup[1]
+ src = tup[2]
+ src_suffix = tup[3]
+
+ if has_separate_host_device_driver:
+ if src == "driver": continue
+ else:
+ if src == "host_driver": continue
+ if src == "device_driver": continue
+
+ ftpl = src + src_suffix + '.tpl'
+ fname = src_prefix + src + src_suffix
+
+ # read template
+ tpl = Template(filename=resource_filename('uvmdvgen', ftpl))
+
+ if not os.path.exists(path_dir): os.system("mkdir -p " + path_dir)
+ with open(path_dir + "/" + fname, 'w') as fout:
+ fout.write(
+ tpl.render(
+ name=name,
+ has_separate_host_device_driver=
+ has_separate_host_device_driver))
diff --git a/util/uvmdvgen/gen_env.py b/util/uvmdvgen/gen_env.py
new file mode 100644
index 0000000..a7b2437
--- /dev/null
+++ b/util/uvmdvgen/gen_env.py
@@ -0,0 +1,55 @@
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+"""Generate SystemVerilog UVM agent extended freom our DV lib
+"""
+
+import os
+
+from mako.template import Template
+from pkg_resources import resource_filename
+
+
+def gen_env(name, is_cip, env_agents, root_dir):
+ # yapf: disable
+ # 4-tuple - sub-path, ip name, class name, file ext
+ env_srcs = [('env', name + '_', 'env_cfg', '.sv'),
+ ('env', name + '_', 'env_cov', '.sv'),
+ ('env', name + '_', 'env_pkg', '.sv'),
+ ('env', name + '_', 'reg_block', '.sv'),
+ ('env', name + '_', 'scoreboard', '.sv'),
+ ('env', name + '_', 'virtual_sequencer', '.sv'),
+ ('env', name + '_', 'env', '.sv'),
+ ('env', name + '_', 'env', '.core'),
+ ('env/seq_lib', name + '_', 'base_vseq', '.sv'),
+ ('env/seq_lib', name + '_', 'sanity_vseq', '.sv'),
+ ('env/seq_lib', name + '_', 'csr_vseq', '.sv'),
+ ('env/seq_lib', name + '_', 'vseq_list', '.sv'),
+ ('tb', '', 'tb', '.sv'),
+ ('tb', name + '_', 'bind', '.sv'),
+ ('tests', name + '_', 'base_test', '.sv'),
+ ('tests', name + '_', 'test_pkg', '.sv'),
+ ('tests', name + '_', 'test', '.core'),
+ ('.', '', 'Makefile', ''),
+ ('.', '', 'plan', '.md'),
+ ('.', name + '_', 'sim', '.core')]
+ # yapf: enable
+
+ for tup in env_srcs:
+ path_dir = root_dir + '/' + tup[0]
+ src_prefix = tup[1]
+ src = tup[2]
+ src_suffix = tup[3]
+
+ if env_agents == [] and src == "virtual_sequencer": continue
+
+ ftpl = src + src_suffix + '.tpl'
+ fname = src_prefix + src + src_suffix
+
+ # read template
+ tpl = Template(filename=resource_filename('uvmdvgen', ftpl))
+
+ if not os.path.exists(path_dir): os.system("mkdir -p " + path_dir)
+ with open(path_dir + "/" + fname, 'w') as fout:
+ fout.write(
+ tpl.render(name=name, is_cip=is_cip, env_agents=env_agents))
diff --git a/util/uvmdvgen/host_driver.sv.tpl b/util/uvmdvgen/host_driver.sv.tpl
new file mode 100644
index 0000000..08103e0
--- /dev/null
+++ b/util/uvmdvgen/host_driver.sv.tpl
@@ -0,0 +1,37 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class ${name}_host_driver extends ${name}_driver;
+ `uvm_component_utils(${name}_host_driver)
+
+ // the base class provides the following handles for use:
+ // ${name}_agent_cfg: cfg
+
+ `uvm_component_new
+
+ virtual task run_phase(uvm_phase phase);
+ // base class forks off reset_signals() and get_and_drive() tasks
+ super.run_phase(phase);
+ endtask
+
+ // reset signals
+ virtual task reset_signals();
+ endtask
+
+ // drive trans received from sequencer
+ virtual task get_and_drive();
+ forever begin
+ seq_item_port.get_next_item(req);
+ $cast(rsp, req.clone());
+ rsp.set_id_info(req);
+ `uvm_info(`gfn, $sformatf("rcvd item:\n%0s", req.sprint()), UVM_HIGH)
+ // TODO: do the driving part
+ //
+ // send rsp back to seq
+ `uvm_info(`gfn, "item sent", UVM_HIGH)
+ seq_item_port.item_done(rsp);
+ end
+ endtask
+
+endclass
diff --git a/util/uvmdvgen/if.sv.tpl b/util/uvmdvgen/if.sv.tpl
new file mode 100644
index 0000000..5f15a32
--- /dev/null
+++ b/util/uvmdvgen/if.sv.tpl
@@ -0,0 +1,11 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+interface ${name}_if ();
+
+ // interface pins
+
+ // debug signals
+
+endinterface
diff --git a/util/uvmdvgen/item.sv.tpl b/util/uvmdvgen/item.sv.tpl
new file mode 100644
index 0000000..715c6d1
--- /dev/null
+++ b/util/uvmdvgen/item.sv.tpl
@@ -0,0 +1,14 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class ${name}_item extends uvm_sequence_item;
+
+ // random variables
+
+ `uvm_object_utils_begin(${name}_item)
+ `uvm_object_utils_end
+
+ `uvm_object_new
+
+endclass
diff --git a/util/uvmdvgen/monitor.sv.tpl b/util/uvmdvgen/monitor.sv.tpl
new file mode 100644
index 0000000..7366fc1
--- /dev/null
+++ b/util/uvmdvgen/monitor.sv.tpl
@@ -0,0 +1,43 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class ${name}_monitor extends dv_base_monitor #(
+ .ITEM_T (${name}_item),
+ .CFG_T (${name}_agent_cfg),
+ .COV_T (${name}_agent_cov)
+ );
+ `uvm_component_utils(${name}_monitor)
+
+ // the base class provides the following handles for use:
+ // ${name}_agent_cfg: cfg
+ // ${name}_agent_cov: cov
+ // uvm_analysis_port #(${name}_item): analysis_port
+
+ `uvm_component_new
+
+ function void build_phase(uvm_phase phase);
+ super.build_phase(phase);
+ endfunction
+
+ task run_phase(uvm_phase phase);
+ super.run_phase(phase);
+ endtask
+
+ // collect transactions forever - already forked in dv_base_moditor::run_phase
+ virtual protected task collect_trans(uvm_phase phase);
+ forever begin
+ // TODO: detect event
+
+ // TODO: sample the interface
+
+ // TODO: sample the covergroups
+
+ // TODO: write trans to analysis_port
+
+ // TODO: remove the line below: it is added to prevent zero delay loop in template code
+ #1us;
+ end
+ endtask
+
+endclass
diff --git a/util/uvmdvgen/plan.md.tpl b/util/uvmdvgen/plan.md.tpl
new file mode 100644
index 0000000..f7beb69
--- /dev/null
+++ b/util/uvmdvgen/plan.md.tpl
@@ -0,0 +1,116 @@
+<!-- Copy this file to hw/ip/${name}/dv/plan.md and make changes as needed. For
+convenience '${name}' in the document can be searched and replaced easily with the
+desired IP (with case sensitivity!). Also, use the testbench block diagram here:
+https://drive.google.com/open?id=1LfnTSutIW5E6zSCOCf4-scS8MQ8lXhPAPgSfFx2Aqh0
+as a starting point and modify it to reflect your ${name} testbench and save it
+to hw/ip/${name}/dv/tb.svg. It should get linked and rendered under the block
+diagram section below. Once done, remove this comment before making a PR. -->
+
+{{% lowrisc-doc-hdr Foo DV Plan }}
+
+{{% toc 3 }}
+
+## Current status
+* [${name.upper()} regression dashboard](../../../dv/regressions/weekly/${name}/dashboard.html)
+* Design milestone: D#
+* Verification milestone: [V#](v#_cl.md)
+
+## Design features
+For detailed information on ${name.upper()} design features, please see the
+[${name.upper()} design specification](../doc/${name}.md).
+
+## Testplan
+<!-- TODO add automation to get the testplan hjson to expand here -->
+{{% path to testplan hjson }}
+
+## Testbench architecture
+${name.upper()} testbench has been constructed based on the
+[CIP testbench architecture](../../../dv/sv/cip_lib/README.md).
+<!-- TODO if ${name.upper()} is not a CIP, then indicated that it is extended from DV
+library instead, if applicable. -->
+
+### Block diagram
+![Block diagram](tb.svg)
+
+### Testbench
+Top level testbench is located at `hw/ip/${name}/dv/tb/tb.sv`. It instantiates the
+${name.upper()} DUT module `hw/ip/${name}/rtl/${name}.sv`. In addition, it instantiates several
+interfaces for driving/sampling clock and reset, devmode, interrupts, alerts and
+tilelink host.
+
+### Common DV utility components
+* [common_ifs](../../../dv/sv/common_ifs/README.md)
+* [dv_utils_pkg](../../../dv/sv/dv_utils/README.md)
+* [csr_utils_pkg](../../../dv/sv/csr_utils/README.md)
+
+### Compile-time configurations
+[list compile time configurations, if any]
+
+### Local types & methods
+The following local types and methods defined in `foo_env_pkg` are in use:
+
+[list parameters, types & methods]
+
+### UVC/agent 1
+[Describe here or add link to its README]
+
+### UVC/agent 2
+[Describe here or add link to its README]
+
+### RAL
+The ${name.upper()} RAL model is constructed using the
+[regtool.py script](../../../../util/doc/rm/RegisterTool.md)
+and is placed at `env/foo_reg_block.sv`.
+
+### Reference models
+[Describe reference models in use if applicable, example: SHA256/HMAC]
+
+### Stimulus strategy
+#### Test sequences
+All test sequences reside in `hw/ip/${name}/dv/env/seq_lib`. The `foo_base_vseq`
+virtual sequence is extended from `cip_base_vseq` and serves as a starting point.
+All test sequences are extended from it. It provides commonly used handles,
+variables, functions and tasks that the test sequences can simple use / call.
+Some of the most commonly used tasks / functions are as
+follows:
+* task 1:
+* task 2:
+
+#### Functional coverage
+To ensure high quality constrained random stimulus, it is necessary to develop
+functional coverage model. The following covergroups have been developed to prove
+that the test intent has been adequately met:
+* cg1:
+* cg2:
+
+### Self-checking strategy
+#### Scoreboard
+The `foo_scoreboard` is primarily used for end to end checking. It creates the
+following analysis ports to retrieve the data monitored by corresponding
+interface agents:
+* analysis port1:
+* analysis port2:
+<!-- explain inputs monitored, flow of data and outputs checked -->
+
+#### Assertions
+* TLUL assertions: The `tb/foo_bind.sv` binds the `tlul_assert` assertions
+ to ${name} to ensure TileLink interface protocol compliance.
+* assert prop 1:
+* assert prop 2:
+
+## Building and running tests
+We are using our in-house developed
+[regression tool](../../../dv/tools/README.md)
+for building and running our tests and regressions. Please take a look at the link
+for detailed information on the usage, capabilities, features and known
+issues. Here's how to run a basic sanity test:
+```
+ $ cd hw/ip/${name}/dv
+ $ make TEST_NAME=foo_sanity
+```
+
+### Test list
+Tests developed towards executing the testplan are specifed in `hw/ip/${name}/dv/sim/tests`.
+
+### Regression list
+Regressions are specified in `hw/ip/${name}/dv/sim/regressions`.
diff --git a/util/uvmdvgen/reg_block.sv.tpl b/util/uvmdvgen/reg_block.sv.tpl
new file mode 100644
index 0000000..f06d9b3
--- /dev/null
+++ b/util/uvmdvgen/reg_block.sv.tpl
@@ -0,0 +1,16 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class ${name}_reg_block extends dv_base_reg_block;
+ `uvm_object_utils(${name}_reg_block)
+
+ function new(string name = "${name}_reg_block", int has_coverage = UVM_NO_COVERAGE);
+ super.new(name, has_coverage);
+ endfunction : new
+
+ virtual function void build(uvm_reg_addr_t base_addr);
+ `uvm_fatal(`gfn, "this file does not seem to be auto-generated!")
+ endfunction : build
+
+endclass : ${name}_reg_block
diff --git a/util/uvmdvgen/sanity_vseq.sv.tpl b/util/uvmdvgen/sanity_vseq.sv.tpl
new file mode 100644
index 0000000..7fbc61b
--- /dev/null
+++ b/util/uvmdvgen/sanity_vseq.sv.tpl
@@ -0,0 +1,15 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+// basic sanity test vseq
+class ${name}_sanity_vseq extends ${name}_base_vseq;
+ `uvm_object_utils(${name}_sanity_vseq)
+
+ `uvm_object_new
+
+ task body();
+ `uvm_error(`gfn, "FIXME")
+ endtask : body
+
+endclass : ${name}_sanity_vseq
diff --git a/util/uvmdvgen/scoreboard.sv.tpl b/util/uvmdvgen/scoreboard.sv.tpl
new file mode 100644
index 0000000..3a2f9ab
--- /dev/null
+++ b/util/uvmdvgen/scoreboard.sv.tpl
@@ -0,0 +1,113 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+% if is_cip:
+class ${name}_scoreboard extends cip_base_scoreboard #(
+% else:
+class ${name}_scoreboard extends dv_base_scoreboard #(
+% endif
+ .CFG_T(${name}_env_cfg),
+ .RAL_T(${name}_reg_block),
+ .COV_T(${name}_env_cov)
+ );
+ `uvm_component_utils(${name}_scoreboard)
+
+ // local variables
+
+ // TLM agent fifos
+% for agent in env_agents:
+ uvm_tlm_analysis_fifo #(${agent}_item) ${agent}_fifo;
+% endfor
+
+ // local queues to hold incoming packets pending comparison
+% for agent in env_agents:
+ ${agent}_item ${agent}_q[$];
+% endfor
+
+ `uvm_component_new
+
+ function void build_phase(uvm_phase phase);
+ super.build_phase(phase);
+% for agent in env_agents:
+ ${agent}_fifo = new("${agent}_fifo", this);
+% endfor
+ endfunction
+
+ function void connect_phase(uvm_phase phase);
+ super.connect_phase(phase);
+ endfunction
+
+ task run_phase(uvm_phase phase);
+ super.run_phase(phase);
+ fork
+% for agent in env_agents:
+ process_${agent}_fifo();
+% endfor
+ join_none
+ endtask
+% for agent in env_agents:
+
+ virtual task process_${agent}_fifo();
+ ${agent}_item item;
+ forever begin
+ ${agent}_fifo.get(item);
+ `uvm_info(`gfn, $sformatf("received ${agent} item:\n%0s", item.sprint()), UVM_HIGH)
+ end
+ endtask
+% endfor
+% if is_cip:
+
+ virtual task process_tl_access(tl_seq_item item, tl_channels_e channel = DataChannel);
+ uvm_reg csr;
+ bit do_read_check = 1'b1;
+ bit write = item.is_write();
+
+ // if access was to a valid csr, get the csr handle
+ if (item.a_addr inside {cfg.csr_addrs}) begin
+ csr = ral.default_map.get_reg_by_offset(item.a_addr);
+ `DV_CHECK_NE_FATAL(csr, null)
+ end
+ if (csr == null) begin
+ // we hit an oob addr - expect error response and return
+ `DV_CHECK_EQ(item.d_error, 1'b1)
+ return;
+ end
+
+ if (channel == AddrChannel) begin
+ // if incoming access is a write to a valid csr, then make updates right away
+ if (write) csr.predict(.value(item.a_data), .kind(UVM_PREDICT_WRITE), .be(item.a_mask));
+ end
+
+ // process the csr req
+ // for write, update local variable and fifo at address phase
+ // for read, update predication at address phase and compare at data phase
+ case (csr.get_name())
+ // add individual case item for each csr
+ default: begin
+ `uvm_fatal(`gfn, $sformatf("invalid csr: %0s", csr.get_full_name()))
+ end
+ endcase
+
+ // On reads, if do_read_check, is set, then check mirrored_value against item.d_data
+ if (!write && channel == DataChannel) begin
+ if (do_read_check) begin
+ `DV_CHECK_EQ(csr.get_mirrored_value(), item.d_data,
+ $sformatf("reg name: %0s", csr.get_full_name()))
+ end
+ csr.predict(.value(item.d_data), .kind(UVM_PREDICT_READ));
+ end
+ endtask
+% endif
+
+ virtual function void reset(string kind = "HARD");
+ super.reset(kind);
+ // reset local fifos queues and variables
+ endfunction
+
+ function void check_phase(uvm_phase phase);
+ super.check_phase(phase);
+ // post test checks - ensure that all local fifos and queues are empty
+ endfunction
+
+endclass
diff --git a/util/uvmdvgen/seq_list.sv.tpl b/util/uvmdvgen/seq_list.sv.tpl
new file mode 100644
index 0000000..9b51507
--- /dev/null
+++ b/util/uvmdvgen/seq_list.sv.tpl
@@ -0,0 +1,5 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+`include "${name}_base_seq.sv"
diff --git a/util/uvmdvgen/sim.core.tpl b/util/uvmdvgen/sim.core.tpl
new file mode 100644
index 0000000..740bf6a
--- /dev/null
+++ b/util/uvmdvgen/sim.core.tpl
@@ -0,0 +1,28 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:${name}_sim:0.1"
+description: "${name.upper()} DV sim target"
+filesets:
+ files_rtl:
+ depend:
+ - lowrisc:ip:${name}:0.1
+ files:
+ - tb/${name}_bind.sv
+ file_type: systemVerilogSource
+
+ files_dv:
+ depend:
+ - lowrisc:dv:${name}_test
+ files:
+ - tb/tb.sv
+ file_type: systemVerilogSource
+
+targets:
+ sim:
+ toplevel: tb
+ filesets:
+ - files_rtl
+ - files_dv
+ default_tool: vcs
diff --git a/util/uvmdvgen/tb.sv.tpl b/util/uvmdvgen/tb.sv.tpl
new file mode 100644
index 0000000..6a44017
--- /dev/null
+++ b/util/uvmdvgen/tb.sv.tpl
@@ -0,0 +1,67 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+module tb;
+ // dep packages
+ import uvm_pkg::*;
+ import dv_utils_pkg::*;
+ import ${name}_env_pkg::*;
+ import ${name}_test_pkg::*;
+
+ // macro includes
+ `include "uvm_macros.svh"
+ `include "dv_macros.svh"
+
+ wire clk, rst_n;
+% if is_cip:
+ wire [NUM_MAX_INTERRUPTS-1:0] interrupts;
+ wire [NUM_MAX_ALERTS-1:0] alerts;
+% endif
+
+ // interfaces
+ clk_rst_if clk_rst_if(.clk(clk), .rst_n(rst_n));
+% if is_cip:
+ pins_if #(NUM_MAX_INTERRUPTS) intr_if(interrupts);
+ pins_if #(NUM_MAX_ALERTS) alerts_if(alerts);
+ pins_if #(1) devmode_if();
+ tl_if tl_if(.clk(clk), .rst_n(rst_n));
+% endif
+% for agent in env_agents:
+ ${agent}_if ${agent}_if();
+% endfor
+
+ // dut
+ ${name} dut (
+ .clk_i (clk ),
+% if is_cip:
+ .rst_ni (rst_n ),
+
+ .tl_i (tl_if.h2d ),
+ .tl_o (tl_if.d2h )
+
+% else:
+ .rst_ni (rst_n )
+
+% endif
+ // TODO: add remaining IOs and hook them
+ );
+
+ initial begin
+ // drive clk and rst_n from clk_if
+ clk_rst_if.set_active();
+ uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "clk_rst_vif", clk_rst_if);
+% if is_cip:
+ uvm_config_db#(intr_vif)::set(null, "*.env", "intr_vif", intr_if);
+ uvm_config_db#(alerts_vif)::set(null, "*.env", "alerts_vif", alerts_if);
+ uvm_config_db#(devmode_vif)::set(null, "*.env", "devmode_vif", devmode_if);
+ uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent*", "vif", tl_if);
+% endif
+% for agent in env_agents:
+ uvm_config_db#(virtual ${agent}_if)::set(null, "*.env.m_${agent}_agent*", "vif", ${agent}_if);
+% endfor
+ $timeformat(-12, 0, " ps", 12);
+ run_test();
+ end
+
+endmodule
diff --git a/util/uvmdvgen/test.core.tpl b/util/uvmdvgen/test.core.tpl
new file mode 100644
index 0000000..905850b
--- /dev/null
+++ b/util/uvmdvgen/test.core.tpl
@@ -0,0 +1,19 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:${name}_test:0.1"
+description: "${name.upper()} DV UVM test"
+filesets:
+ files_dv:
+ depend:
+ - lowrisc:dv:${name}_env
+ files:
+ - ${name}_test_pkg.sv
+ - ${name}_base_test.sv: {is_include_file: true}
+ file_type: systemVerilogSource
+
+targets:
+ default:
+ filesets:
+ - files_dv
diff --git a/util/uvmdvgen/test_pkg.sv.tpl b/util/uvmdvgen/test_pkg.sv.tpl
new file mode 100644
index 0000000..3bd6ea5
--- /dev/null
+++ b/util/uvmdvgen/test_pkg.sv.tpl
@@ -0,0 +1,26 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+package ${name}_test_pkg;
+ // dep packages
+ import uvm_pkg::*;
+% if is_cip:
+ import cip_base_pkg::*;
+% else:
+ import dv_lib_pkg::*;
+% endif
+ import ${name}_env_pkg::*;
+
+ // macro includes
+ `include "uvm_macros.svh"
+ `include "dv_macros.svh"
+
+ // local types
+
+ // functions
+
+ // package sources
+ `include "${name}_base_test.sv"
+
+endpackage
diff --git a/util/uvmdvgen/virtual_sequencer.sv.tpl b/util/uvmdvgen/virtual_sequencer.sv.tpl
new file mode 100644
index 0000000..e4cd3c4
--- /dev/null
+++ b/util/uvmdvgen/virtual_sequencer.sv.tpl
@@ -0,0 +1,21 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+% if is_cip:
+class ${name}_virtual_sequencer extends cip_base_virtual_sequencer #(
+% else:
+class ${name}_virtual_sequencer extends dv_base_virtual_sequencer #(
+% endif
+ .CFG_T(${name}_env_cfg),
+ .COV_T(${name}_env_cov)
+ );
+ `uvm_component_utils(${name}_virtual_sequencer)
+
+% for agent in env_agents:
+ ${agent}_sequencer ${agent}_sequencer_h;
+% endfor
+
+ `uvm_component_new
+
+endclass
diff --git a/util/uvmdvgen/vseq_list.sv.tpl b/util/uvmdvgen/vseq_list.sv.tpl
new file mode 100644
index 0000000..18a18f9
--- /dev/null
+++ b/util/uvmdvgen/vseq_list.sv.tpl
@@ -0,0 +1,7 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+`include "${name}_base_vseq.sv"
+`include "${name}_sanity_vseq.sv"
+`include "${name}_csr_vseq.sv"