- Auto generate a concrete C++ implementation of the SystemVerilog (VHDL in future) Object Model following the IEEE standard object model
- Auto generate a standard VPI interface as a facade to the C++ model
- Auto generate a serialization/deserialization of the data model
- Auto generate a Visitor (Walker) function that exercise the entire VPI interface (used in uhdm-dump executable)
- Auto generate a C++ Listener Design Pattern that traverse the entire VPI data model (used in uhdm-listener executable)
- Auto generate an Elaborator that uniquifies nets, variables...
- The generated Object Model can, for a given design, be:
* git clone https://github.com/alainmarcel/UHDM.git
* cd UHDM
* git submodule update --init --recursive
* make
- All SystemVerilog models are expressed in a Yaml type syntax (One file per Verilog Object Model)
- From this Yaml description, all the code (C++ headers, VPI Interface, Serialization) is automatically generated.
- Model inheritance and object/class grouping is supported (To follow the IEEE standard)
- Supports the concept of "design" on top of the IEEE standard to support partitioning and multi-language (SystemVerilog - VHDL)
- Any deviation/addition from the standard is cleary indicated by a uhdm prefix, IEEE standard API is either prefixed by vpi (Verilog) or vhpi (VHDL).
- The model is captured in .yaml files, one per object models detailed pages 976-1050 of the SystemVerilog 2017 IEEE standard.
- To match the standard, several concepts are observed in the model:
- obj_def: A leaf object specification (Object can be allocated and persisted)
- class_def: A virtual class specification (Class is used either with inheritance - extends:, or as composition of a - class_ref)
- property: Typically an int, bool, string property with a name and a vpi access type (ie: vpiModule) accessed by the vpi_get function
- obj_ref: A reference to one (accessed by vpi_handle) or many (accessed by vpi_iterate) leaf objects
- class_ref: A reference to one or many virtual class, actual objects returned will be of a leaf type
- extends: Class inheritance specified by the extends keyword
- group_def: Grouping of objects in a named or unnamed group (We actually give a representative name to unnamed groups)
- group_ref: A reference to one or many members of a group of objects
- Keywords used to capture the model in Yaml
- all of the above keywords (obj_def...group_ref),
- For each reference (obj_def, class_def, group_def) and property, the following sub fields:
- name: the name of the field (spaces accepted), verbatim from the standard
- vpi: the name of the VPI access type to access this object member (Has to match a defined value in vpi_user.h or sv_vpi_user.h)
- type: the formal type of the field:
- obj_ref
- class_ref
- group_ref
- int
- unsigned int
- bool
- string
- value (VPI s_vpi_value)
- delay (VPI s_vpi_delay)
- card: cardinality of the field
- 1
- any (0 or more)
- The Standard VPI Data Model is Fully Elaborated, in contrast:
- When created by Surelog, the UHDM/VPI Data Model is a Folded Model that we found most suitable for applications like Yosys and Verilator:
- The Instance tree contains the Design Hierarchy and Elaborated Nets/Ports with High conn and Low conn connections done.
- The module definitions contain the logic elements (non-elaborated, and only outside generate statements)
- Generate statements and underlying logic are only visible in the elaborated model (topModules)
- To get the complete picture of the design one has to use both views (Example in
listener_elab_test.cpp
) - Applications where the UHDM data model is used as a precursor to another internal datastructure like a Synthesis or Simulator tool will prefer using the Folded Model.
- Nets, Ports, Variables in the flat module list (allModules) don't necessary have the correct data type as not enough elaboration steps were performed on them
- On the other hand, Nets, Ports, Variables have the correct type in the elaborated view (topModules)
- Lhs vs Rhs expression padding is not performed at this point (We welcome PR contributions)
- UHDM offers an optional Elaboration step that uniquifies nets, ports, variables and function by performing a deep cloning and ref_obj binding.
- See
full_elab_test.cpp
anduhdm-dump.cpp
- Applications where the UHDM data model is free standing and is the sole data structure for the design representation will prefer the Fully Elaborated Data Model, examples: Linters or Code Analyzers.
- At this point, UHDM does not offer:
- the full bit blasted model available in the commercial EDA applications (We welcome contributions).
- an expression evaluator that operates on the UHDM expression tree (We welcome contribuitons).
- Issue 319 discusses more on the topic of elaboration
- See
- The model creation task consists in converting the Object Model diagrams into their Yaml representation and invoking the creation of the concrete C++ classes, iterators, serialization code by invoking "make"
- How to create the model (presentation)
- The design creation task consists in invoking:
- the proper concrete object factory methods to get serializable objects
- populate the properties to the obtained objects
- assemble the model by creating legal object relations (compile time and runtime checking) following the IEEE standard
- invoking the serialization call
- Read
module-port_test.cpp
- After Deserialization of the persisted design (elaborated or not) (Read
module-port_test.cpp
) - Client applications can elaborate optionally and use the VPI interface to navigate the Object Model and create their own internal data structures (Read
tests/listener_elab_test.cpp
) - Or use the Visitor (More like a Walker)
- An example Visitor is auto-generated to print the content of the data model
vpi_visitor.cpp
- An example Visitor is auto-generated to print the content of the data model
- Or use the Listener Design Pattern
- Examples can be found in tests/vpi_listener.cpp or tests/uhdm_listener.cpp
- The listener enables client application development with minimum disruption while the data model evolves.
- An Custom Elaborator example code uses the Listener Design Pattern in
listener_elab_test.cpp
- A Full Elaboration example is demonstrated in
full_elab_test.cpp
anduhdm-dump.cpp
- The uhdm-dump
uhdm-dump
executable creates a human readable view of the UHDM serialized data model using the visitorvisitor.cpp
. - An optional linter (Listener) that warns about non-Synthesizable constructs can be found here:
SynthSubset.cpp
- An optional linter (Listener) that warns about diverse Verilog compliances post-elaboration can be found here:
UhdmLint.cpp
- An optionnal expression evaluator can be found here:
ExprEval.cpp
- The Yosys-UHDM plugin code (most comprehensive open-source usage of UHDM) can be found here: https://github.com/chipsalliance/yosys-f4pga-plugins/tree/main/systemverilog-plugin
- The Verilator-UHDM plugin code can be found here: https://github.com/antmicro/verilator/blob/uhdm-verilator/src/UhdmAst.cpp
- After instaling (
make install
), create your own executable (ReadMakefile
) , ie: $(CXX) -std=c++17 tests/test1.cpp -I/usr/local/include/uhdm -I/usr/local/include/uhdm/include /usr/local/lib/libuhdm.a /usr/local/lib/libcapnp.a /usr/local/lib/libkj.a -ldl -lutil -lm -lrt -lpthread -o test_inst
- Surelog generates natively UHDM databases (surelog.uhdm)
- Other parsers are welcome to generate UHDM databases
- When uhdm is compiled as a shared library and the UHDM_WITH_PYTHON is set, it also builds a swig wrapper for python (
-DUHDM_WITH_PYTHON=ON
usingcmake
command, ormake release-shared UHDM_WITH_PYTHON=ON
, also make sure your python executable is built with shared libraries enabled: env PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install -verbose 3.9.11). The python wrapper implements almost all the VPI getter API from systemVerilog. See chapter 38. VPI routine definitions of Ieee1800-2017 for details. - Find here a short example that assumes an existing database. It will print all module names existing in the first design :
import uhdm
#build uhdm Serializer object
s = uhdm.Serializer()
#Read and uhdm database
data = s.Restore('surelog.uhdm')
#Your specific application
#Here create an iterator on all module in the first design
module_iterator = uhdm.vpi_iterate(uhdm.uhdmallModules,data[0])
#iterate on all module
while(True):
vpiObj_module = uhdm.vpi_scan(module_iterator)
if vpiObj_module is None:
break
#print the string pointed by vpiName attribut of vpiObj_module
print(uhdm.vpi_get_str(uhdm.vpiName,vpiObj_module))
- Verilog_Object_Model.pdf - Object Model section of the IEEE_Std1800-2017_8299595.pdf (Practical for searches)
- SystemVerilog 2017 - System Verilog Standard
- Surelog - Surelog parser
- Verible - Verible linter
- capnproto - Cap'n Proto serialization