The Verilog to CvSDL translator, hdl2cvsdl, is the front-end tool to convert Verilog designs to CvSDL, essentially on the “as-is” basis.
In general, you need to translate all of the Verilog design and library files in an entire design at once:
hdl2cvsdl file1.v file2.v ... -v lib1.v -y libdir1
The file order is important if there are more than one timescale directive and/or there are more than one module with a same name.
If translation is successful, each Verilog file will have a CvSDL design unit comprising a header file and a source file. For example mod_a.v generates mod_a.h and mod_a.cpp.
If a design includes one or more defparam statements, they are collected into a single CvSDL design unit, named cv_defparams. It contains one CvSDL module called cv_defparams. The module needs to be registered with the CvSDL simulator before any other modules are registered.
In addition, hdl2cvsdl automatically generates a source file named cv_main.cpp that contains the main() function for a console application. The function creates a CvSDL simulator object and registers all the top-level modules including the optional cv_defparams module. Then it starts a simulation and at the end it deletes the simulator object.
You can simply compile cv_main.cpp and design units and run the resultant executable to simulate your design in a console window.
In case you need to debug your Verilog models in C++, the following will give you basic ideas on how Verilog objects and constructs are translated.
A Verilog name can be a simple sequence of printable characters or an escaped name that cannot be represented as a C++ name. CvSDL requires many objects (variables, modules, etc.) to be given a string name in addition to a C++ name. For example, a Verilog net, \\address , may be mapped to cv_esc_1 in C++ with the string name, “\\address “. Original Verilog names are simply put into such strings. If the names are compatible with C++, they are also used as C++ names; otherwise they are transformed into names that C++ can handle. Verilog module names are prefixed with cvm_ to avoid namespace conflict. In CvSDL, hierarchical references use the string names not the C++ names.
If there is no timescale directive in the design, the CvSDL models use 1s/1s as the timescale. If one or more timescale directives are found, the very first timescale encountered becomes the default timescale for the entire design. A subsequent timescale directive that is different from the default will put the equivalent timescale statement, cv_timescale(), in the constructor of each affected module until another timescale directive appears.
Each module in a Verilog file is transformed into a C++ class; its definition is placed in the header file and its constructor and function definitions in the source file. The class definition in the header file simply declares all module variables, functions (Verilog initial/always blocks and functions/tasks), and one constructor. The source file defines the constructor and functions.
The ports of a module are mapped as the arguments to the constructor function of the corresponding class. Parameters also appear as constructor arguments except for top-level modules. Parameter overriding when a module is instantiated is done by setting new values to parameter arguments of the constructor. If default values are used, the arguments are set to the NULL string (“”).
Any statements and declarations processed during the so-called elaboration time in Verilog are generally considered structural and, in CvSDL, their definitions are placed in the constructor, except for function definitions. They include the definitions of ports, parameters, nets, and variables, parameter assignments, continuous assignments, process declarations, gate/module instantiations, initial and always block declarations and generate constructs. Initial and always blocks are mapped into class member functions that are declared as processes. Functions and tasks are also mapped into class member functions, but not as processes.
Verilog integer and real constants are translated to C++ integer and double constants with little modifications. Based constants are simply enclosed in double quotes. Strings that appear to be numbers are prefixed by 'A. Currently constants are wrapped in TCvVar(...), which make expressions a bit hard to read.
There is only one data type, TCvVar, in CvSDL to represent Verilog nets and variables. Verilog strings are not the same as C++ 0-terminated strings, but in most situations, C++ strings are used (wrapped in TCvVar()). A TCvVar object is defined in the constructor in terms of the corresponding Verilog type.
Local variables in named blocks are converted to per-module persistent module variables with their names prefixed with hierarchical pathnames to the variables. The separator (.) is replaced by the underscore (_) in the prefix. Automatic variables introduced in Verilog-2001 are not yet supported.
In module constructors, continuous assignments are mapped to cv_assign(...) statements and the assignment of the form, A=B, is used either for a local variable assignment or variable initialization as in Verilog variable declaration-assignment statement.
Nonblocking assignments in CvSDL are indicated by “<<=” (C++ left-shift-assignment operator), not “<=” (less-than-or-equal operator) as used in Verilog.
Delays, be it delay3, delay2, etc. with/without min:typ:max, etc, are all reduced to single quantities by averaging.
The strengths, supply0, strong0, pull0, weak0, supply1, strong1, pull1 and weak1, are mapped to CV_STR_SUPPY0, CV_STR_STRONG0, CV_STR_PULL0, CV_STR_WEAK0, CV_STR_SUPPLY1, CV_STR_STRONG1, CV_STR_PULL1, and CV_WEAK1, respectively.
@ is usually mapped to the cv_at() function. The posedge and negedge prefixes become function calls, posedge() and negedge(). For example, posedge clk becomes posedge(clk). An event-or is replaced by a comma (,). The trigger notation (->) becomes a member function call, trigger() as, for example, my_event.trigger();.
# is usually mapped
to the cv_delay() function. For example,
#10 wait(a); // becomes
if (cv_delay(10)) wait(a);
Whenever a non-null statement follows @<event> or #(delay), hdl2cvsdl adds an if-statement.
Initial blocks are always implemented as threads; the stack size can be globally or individually modified from the default. Synthesizable always blocks are implemented as nonthreads; other always blocks will be threads. Nonthread processes have less memory overhead.
Most Verilog statements are translated to equivalent CvSDL statements with little or some syntactical changes. Forever becomes while(1) and repeat becomes for-loop. Most expressions are translated with very little modifications. Most operators are the same between Verilog and CvSDL; others are typically implemented as functions. CvSDL uses a pair of parentheses () for a concatenation instead of a pair of braces {}. The Verilog conditional expression (?:) is translated to the CvSDL function, cv_cond(), since the C++ conditional expression is not compatible with the Verilog conditional.
The dollar sign in front of a system task/function is replaced by the prefix, cv_. For example, $display() becomes cv_display().
Variable argument lists in Verilog constructs, such as @(event_expression), $display(list_of_arguments), etc. are enclosed in a pair of parentheses. For example, an event expression a or b or c (maybe a, b, c in Verilog-2001) will be (a, b, c) and $display(“%x”, a) will be cv_display( (“%x”, a) ).
Any primitive gate is mapped to the function, cv_gates(). The first argument to the function indicates the type of the gate. For example, cv_gate(CV_GATE_PULLUP, ...) is a pullup.
Trademarks
and registered trademarks are property of the respective
owners.
CvSDL is a trademark of Tenko Technologies Inc.
Copyright
© 2005 Tenko
Technologies Inc. All rights reserved. Last modified on