Surelog
is a super interesting project for parsing and elaborating SystemVerilog. Here is the blurb from their GitHub:
SystemVerilog 2017 Pre-processor, Parser, Elaborator, UHDM Compiler. Provides IEEE Design/TB C/C++ VPI and Python AST API.
What I found most interesting is that Surelog can dump UHDM
, which is a standard database representation (think SNPS KDB)
Linter, Simulator, Synthesis tool, Formal tools can use this front-end. They either can be developed as plugins (linked with) or use this front-end as an intermediate step of their compilation flows using the on-disk serialized models (UHDM).
So, what is UHDM
? It’s a library and APIs to create, process, and dump SystemVerilog. Apparently, it implements VPI interaction from 1800 SystemVerilog.
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 exercises the entire VPI interface (used in uhdm-dump executable) Auto generate a C++ Listener Design Pattern that traverses 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: Populated by parsers like Surelog or Verible Consumed by tools like Yosys or Verilator
Compilation Link to heading
The first step is compiling Surelog
and UHDM
.
sudo apt-get install build-essential cmake git pkg-config tclsh swig uuid-dev libgoogle-perftools-dev python3 python3-orderedmultidict python3-psutil python3-dev default-jre lcov zlib1g-dev
git clone https://github.com/alainmarcel/Surelog.git
cd Surelog
export SURELOG=$PWD
git submodule update --init --recursive
make
git clone https://github.com/alainmarcel/UHDM.git
cd UHDM
export SURELOG=$UHDM
git submodule update --init --recursive
The binaries can be found at $SURELOG/build/bin
and $UHDM/build/bin
.
Surelog Link to heading
The first example uses a file list to run parse
and force full UHDM elaboration.
surelog -f flist.f -parse -d uhdm -elabuhdm
This the documentation of the 2 options used to parse and elaborate the design. It’s also dumps uhdm.
-parse Parse/Compile/Elaborate the files after
-elabuhdm Forces UHDM/VPI Full Elaboration, default is the
Folded Model
This is simple enough verilog to show some serious stats from uhdm.
module top;
wire a, b, c;
assign a = 1'b0;
assign b = 1'b1;
// This is a simple AND gate instantiation
and1 m(a, b, c);
always @(*) begin
$display("a = %b, b = %b, c = %b", a, b, c);
end
endmodule
module and1(input wire a, input wire b, output wire c);
assign c = a & b;
endmodule
Finally, we have the output from Surelog
command.
COMMAND: -f flist.f -parse -elabuhdm
[INF:CM0023] Creating log file "slpp_all/surelog.log".
[WRN:PA0205] top.sv:1:1: No timescale set for "top".
[WRN:PA0205] top.sv:14:1: No timescale set for "and1".
[INF:CP0300] Compilation...
[INF:CP0303] top.sv:14:1: Compile module "work@and1".
[INF:CP0303] top.sv:1:1: Compile module "work@top".
[INF:CP0302] Compile class "work@mailbox".
[INF:CP0302] Compile class "work@process".
[INF:CP0302] Compile class "work@semaphore".
[INF:EL0526] Design Elaboration...
[NTE:EL0503] top.sv:1:1: Top level module "work@top".
[NTE:EL0508] Nb Top level modules: 1.
[NTE:EL0509] Max instance depth: 2.
[NTE:EL0510] Nb instances: 2.
[NTE:EL0511] Nb leaf instances: 1.
[INF:UH0706] Creating UHDM Model...
[INF:UH0708] Writing UHDM DB: /slpp_all/surelog.uhdm ...
[ FATAL] : 0
[ SYNTAX] : 0
[ ERROR] : 0
[WARNING] : 2
[ NOTE] : 5
********************************************
* End SURELOG SVerilog Compiler/Linter *
UHDM Link to heading
Naturally, the next step is using UHDM APIs to load uhdm fille and print it’s statistics.
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <regex>
#include <sstream>
#include <string>
#include <iostream>
using namespace std;
#include <uhdm/ElaboratorListener.h>
#include <uhdm/VpiListener.h>
#include <uhdm/uhdm-version.h>
#include <uhdm/uhdm.h>
#include <uhdm/vpi_visitor.h>
#include <uhdm/Serializer.h>
using namespace UHDM;
int32_t main(int32_t argc, char **argv)
{
if (argc < 2)
{
std::cerr << "Usage: " << argv[0] << " <uhdm_file>" << std::endl;
return 1;
}
std::string uhdmFile = argv[1];
std::unique_ptr<UHDM::Serializer> serializer(new UHDM::Serializer);
std::vector<vpiHandle> designs = serializer->Restore(uhdmFile);
serializer->PrintStats(std::cout, uhdmFile);
return 0;
};
Compilation can be a little involved, but these are the required static libs.
g++ -I${UHDM}/build/generated/ read_uhdm.cc \
${UHDM}/build/lib/libuhdm.a \
${UHDM}/build/third_party/capnproto/c++/src/capnp/libcapnp.a \
${UHDM}/build/third_party/capnproto/c++/src/kj/libkj.a \
-o read_uhdm -ldl -lutil -lm -lrt -lpthread
./read_uhdm ./slpp_all/surelog.uhdm
Initially, I was confused why the stats have so many constructs such as class_typespec
. Then I realized Surelog
has some implementation for built-in classes (semaphore, etc).
=== UHDM Object Stats Begin (./slpp_all/surelog.uhdm) ===
always 2
begin 2
class_defn 8
class_typespec 3
class_var 3
constant 8
cont_assign 8
design 1
enum_const 10
enum_typespec 2
enum_var 1
event_control 2
function 18
int_typespec 9
int_var 4
io_decl 17
logic_net 12
logic_typespec 13
logic_var 1
module_inst 4
operation 2
package 2
port 6
ref_obj 27
ref_typespec 31
sys_func_call 2
task 9
=== UHDM Object Stats End ===