Source Code Structure - StanfordVLSI/Genesis2 GitHub Wiki

Table of Contents

Source Code Structure For Using Genesis2

The code structure for using Genesis2, just like in Genesis 1, is whatever target language your code should generate annotated with directives that tell Genesis2 how to expand the text.

In our case, the target language is Verilog or System Verilog. The meta language that is used on top is simply Perl. You now have the strength of Perl in your hands when you write verilog. Use it wisely.

Perl Escapes

There are two types of Perl escapes that can be used:

Full Line Escape ( //; Perl text 'til end of line )
This escape sequence tells Genesis2 that the entire line is Perl. To use it, simply type ' //; ' (i.e. line comment followed by a semi-colon) at the beginning of the line (white space before is also allowed).
  • Note that this would look like a comment to the xemacs's (or any other editor's) Verilog mode. Hence, coloring and indentations would not be influenced.
Descriptive example:
This is regular (though not legal Verilog) text that would go directly to output.
// This is also regular text that would go directly to the output as a Verilog comment.
//; This is text that would be evaluated as a Perl script (and generate a syntax error ;-))

Compilable example:

assign verilog_wire = some_other_verilog_wire;
// I am a verilog comment line
//; my $to_be_perl_var = "This is Perl";
Part-Of-Line Escape ( `Perl text between left-single-quotes` )
This escape sequence tells Genesis2 that a part of the line, which is delimited in-between two "`" (i.e. grave accent or tick-mark) signs, is to be evaluated using the Perl interpreter. Unlike the full line escape, in the partial line escape, the result of the Perl evaluation is to be printed to screen.
  • Note that this would look like a "tick-define" to the xemcas's (or any other editor's) Verilog mode. Hence, coloring and indentations would not be influenced.
Example:
//; my $width = 5;
assign some_wire[`$width-1`:0] = some_other_wire[`$width+9`:10];

//; foreach my $idx (0,1,2,3){
assign wire_`$idx` = wire_`($idx+1)%4`;
//; }

Which will produce:

assign some_wire[4:0] = some_other_wire[14:10];

assign wire_0 = wire_1;
assign wire_1 = wire_2;
assign wire_2 = wire_3;
assign wire_3 = wire_0;
  • Note About The Perl print Function: It is some times convenient to use the built-in Perl print function. Note that for convenience, printing is done by default to the output file (i.e. the Verilog modulename.v file). If you wish to print progress or debug statements that need to go to the screen use print STDOUT "your text here\n" or print STDERR "your text here\n".

Old Verilog Style Macros Escapes

Using old style tick macros from Verilog/System Verilog is highly un-recommended for many reasons. Instead one should either use variables or genesis2 parameters. If you still must use them, I guess you can but don't say I didn't warn you! Simply escape your tick as follows:

`this is a perl escape`
\`but this is a verilog old style tick

Special Built-in Methods

As mentioned before, the entire effort of creating a tool like this is to enable scopes, enhanced parameterization and most importantly uniquification of modules. For this reason, there are a handful of pre-built Perl methods that were defined.

There are no other directives you need to remember. It is all Verilog annotated with Perl from here on.

Data Structure Related Methods

sub get_parent: Returns a pointer to the parent instance
//; my $parent = $self->get_parent(); 
sub get_top: Returns a pointer to the top level of the hierarchy
//; my $top_module = $self->get_top(); 
sub get_subinst: Returns a pointer to the object of a sub instance (by name)
//; my $subinst_of_someinst = $someinst->get_subinst($subinst_name); 
sub exists_subinst: Returns a 1 if a sub instance (by name) exists. Zero otherwise.
//; my $subinst_exists = $someinst->exists_subinst($subinst_name); 
sub get_subinst_array: Returns a handle to an array of sub instance objects that match a pattern
//; my @subinsts_of_someinst = $someinst->get_subinst_array($pattern); 
sub search_subinst
API method for searching the entire design hierarchy or portions of it according to user defined criteria(s)
All criteria are optional. The returned value is a list of objects that matched ALL specified criteria.
From: Either pointer or text path to an instance work here (default is the design top)
Depth: How deep in the hierarchy should we search? (default is 10000 ;-)
PathRegex: Return only instances who's path matches some regular expression (e.g., '.*\.ahb0\..*')
INameRegex: Return only instances who's instance name matches a regular expression
MNameRegex: Return only instances who's finalized module name matches a regular expression
BNameRegex: Return only instances who's base module name (before uniquification) matches a regular expression
SNameRegex: Return only instances who's source file name matches a regular expression
HasParamRegex: Return only instances that has a parameter who's name matches the regular expression The HasParamRegex arg can be either a string (e.g., 'Width') or an a string array ref (e.g., ['Width',]). Note that in the string array case, we search for instances that has a param that matchs regex1 AND a param that matches regex2 AND...
ApplyMap: If you have some complex way of determining if an instance should be returned, you can create your own function that accept/reject an objects. Your function must return 0/1. E.g., sub func{ my $obj = shift; return ($obj-iname eq 'ofer'); }
Reverse: Search hierarchy in DFS or in Reverse DFS order
@subinst_arr = $anyObj->search_subinst(
                        From=>$ObjToStartFrom   OR  'path.to.objToStartFrom', 
                        Depth=>$HowDeepToSearch,
                        PathRegex=>'Path.to.Inst',  
                        INameRegex=>'InstanceName',
                        MNameRegex=>'ModuleName',
                        BNameRegex=>'BaseModuleName', 
                        SNameRegex=>'SourceTemplateName',
                        HasParamRegex=>'ParamName' OR \@ParamList,
                        ApplyMap=>\&func,
			Reverse=>0/1);
sub get_instance_path
API method that returns a complete path to the given instance object. An instance path has the strict format of <top_module></top_module>.<subinst></subinst>.<subsubinst></subsubinst>.... For example: top.dut.regfile.addr_flop.
//; my $inst_path = $inst_obj->get_instance_path();
get_instance_obj
API method that accepts an instance path (or an instance object) and returns the corresponding instance object. An instance path has the strict format of <top_module></top_module>.<subinst></subinst>.<subsubinst></subsubinst>.... For example: top.dut.regfile.addr_flop.
//; my $inst_obj = $self->get_instance_obj($inst_path);
synonym
API function/method call that helps you make fancy names for your module templates.
NOTE: This function manipulates the names of templates, and therefore the names of the generated modules and the generated verilog files). Not the names of instances of those modules.
//; synonym("sourceTemplateName", "renamedTemplateName");
For example, say you have addr.vp that has a bunch of parameters. And say you want to create multiple versions of it that you can easily grep for (e.g., in your physical design scripts). So you don't want those elaborated modules to be called adder_unq1, addr_unq2, and so on. Instead you want fancy_adder and simple_adder. For the case stated above this would be:
//; synonym("adder", "simple_adder");
//; synonym("adder", "fancy_adder");
OR as method call:
//; $self->synonym("adder", "simple_adder");
//; $self->synonym("adder", "fancy_adder");
A synonym of a synonym is also ok:
//; synonym("fancy_adder", "super_fancy_adder");
Therefore the following code will result in the generation the verilog modules adder_unq1, adder_unq2 but also simple_adder_unq1, super_fancy_adder_unq1 and super_fancy_adder_unq2, even though simple_adder_unq1 is functionally equivalent to adder_unq1 and super_fancy_adder_unq1 is functionally equivalent to adder_unq2:
//; my $obj1 = generate('adder', 'adder_u1', WIDTH=>4);
//; my $obj2 = generate('adder', 'adder_u2', WIDTH=>8);
//; my $obj3 = generate('simple_adder', 'adder_u3', WIDTH=>4);
//; my $obj4 = generate('super_fancy_adder', 'adder_u4', WIDTH=>8);
//; my $obj5 = generate('super_fancy_adder', 'adder_u5', WIDTH=>12);
Note that you could also create adder, simple_adder and so on (i.e., without the "_unq1" suffix) by using the generate_base call (see below), as long as you only generate those once in your design. Otherwise Genesis will through an error message and stop.
//; my $obj1 = generate_base('adder', 'adder_u1', WIDTH=>4);
//; my $obj2 = generate_base('simple_adder', 'adder_u2', WIDTH=>4);
//; my $obj3 = generate_base('super_fancy_adder', 'adder_u3', WIDTH=>4);
//; my $obj4 = generate_base('super_fancy_adder', 'adder_u4', WIDTH=>8); <-- This will create an ERROR message because generate_base does not create unique modules.

Parameterization Methods

sub parameter: This is the main call for defining a new parameter (just like defining a parameter in SystemVerilog), and specifying its default value, documentation and range. Note that using the parameter, parameters can only be defined inside the module to which they belong (i.e., a call to $someOtherInst->parameter(...arguments...) will cause a genesis generation error). Much like SystemVerilog, parameters can also be overridden at instantiation using the generate method as shown below. Definition at instantiation time overwrites definitions done within the module (just like in Verilog). As a middle ground, parameter definitions that are not bounded by instantiation can be set using the input XML configuration file. More details can be found here.
Notes:
  • The call to parameter can be done in either method- or function-call format.
  • This API method/function is in fact syntactic sugar for the older parameter definition methods $self->define_param, $self->force_param, $self->doc_param, $self->param_range.
  • List of older style parameter definition methods here.
//; my $prmVal = parameter(name=>'prmName', # required
//;                        val=>$prmVal,    # required
//;                        force=>0/1,      # Optional. Default is 0. param
//;                                         # Setting to 1 will create an immutable param, 
//;                                         # exactly like $self->force_param
//;                        doc=>'message'   # Optional
//;                        min=>$minVal, max=>$maxVal, step=>$step # Optional. Can also use min only, 
//;                                                                # max only, min and step only or
//;                                                                # max and step only.
//;                        OR 
//;                        list=>[$valA, $valB, ...],
//;			   Opt=>'Yes'/'No'/'Try');                 # Optional -- Will pass info to external optimizer

Or
//; my $prmVal = $self->parameter(name=>'prmName', 
//;                               val=>$prmVal,
//;                               force=>0/1,
//;                               doc=>'message' 
//;                               min=>$minVal, max=>$maxVal, step=>$step OR list=>[$valA, $valB, ...],
//;			          Opt=>'Yes'/'No'/'Try');
Style tip: Often, we would like to declare a parameter that MUST be overridden at instantiation or from external configuration. One way to do that is to provide a default value which is out of range. If the parameter value is not overridden, Genesis will issue an error. For example:
//; my $width = parameter(Name=>'BitWidth', Val=>-1, Min=>0, Doc=>'...');
//; my $enc = parameter(Name=>'Encrypt ', Val=>'', List=>['Yes', 'No', 'Maybe'], Doc=>'...');
For compound structures and/or pointers, were simple range limitations could not apply, the following is useful:
//; my $cpu_ref = parameter(Name=>'CPU_ObjRef', Val=>undef, Doc=>'...') or error ("Parameter CPU_ObjRef must be specified");
sub exists_param: API method for checking whether a certain parameter has been defined in a module (without defining it). Can operate on $self or any template $obj that was previously generated. Note that specifying a parameter within a generate call, from the XML, or configuration file, is not the same as defining it, and exists_param will evaluate to false in that case.
//; my $exists = $self->exists_param('SomePrmName');
sub list_params: API method for extracting a list of params defined in a module. Can operate on $self or any template $obj that was previously generated.
//; my @list = $self->list_params();
sub get_param: API method for extracting a parameter's value from the parameter's registry. This sort of definition is useful if your module needs to read a parameter from a different module:
//; my $val = $other_module->get_param('prm_name');
It should be defined with 'parameter' call (not just in the XML) or you will get an error.
sub get_top_param: API method for extracting a parameter's value from the top level parameter's registry.
//; my $val = $self->get_top_param('prm_name');
This is equivalent (but much shorter) to:
//; $tmp = $self;
//; while (defined $tmp1){
//;   $tmp2=$tmp1;
//;   $tmp1=$tmp1->get_parent();
//; }
//; my $val = $tmp2->get_param('prm_name');

Module Instantiation Methods

sub generate
The main function call for generating (and later instantiating) a new module. Note that this call on its own would not print anything to the output module. Rather, it will return a pointer to the instance module ($newObj in the code bellow). Use the $newObj->instantiate() and other methods as described above to query this new module and then decide what to print to the generated module code.
Note: This function is syntactic sugar for $self->unique_inst(...)---the main method call for generating (and later instantiating) a new module.
//; my $newObj = generate(base_module_name, inst_name, prm1 => val1, prm2 => val2, ...);

Example: Before (SystemVerilog)

Adder#(.w(8),.n(4)) MyAdder(.in1(a),.in2(b),.out(c));

Example: After (Genesis2)

//; my $my_adder = generate('Adder', 'MyAdder', w=>8, n=>4);
`$my_adder->instantiate` (.in1(a), .in2(b), .out(c));
sub clone
This is syntactic sugar for $self->clone_inst(...)---A method for replicating a module based on an existing instance.
//; my $clonedObj = clone($src_inst, 'new_inst_name');
sub generate_base
It turns out that some people want to generate only the base module. For example, Mrs. F. in her mixed signal chip wanted to generate only one type of her analog.vp module as that module needs to be replaced with an analog macro at PNR. Furthermore, she prefers if it remains with the name analog and not be renamed to analog_unq1 as genesis generally does at elaboration. To facilitate that, we created the new generate_base function. generate_base will generate the base module and not anything else.
Notes:
  • If you generate multiple instances of a module using generate_base, genesis is still smart enough to make sure that you are always generating exactly the same module, and otherwise through an error that you can't generate the same un-uniquified module twice in two different ways.
  • You CAN use both the unique instantiation (i.e., generate) and the non-unique instantiation (i.e., generate_base) in the same code. No contradictions here.
//; my $MyAnalog_obj = generate_base('Analog', 'MyAnalog', w=>8, n=>4);
`$MyAnalog_obj ->instantiate` (.in1(a), .in2(b), .out(c));

Auxiliary Methods

sub include: includes a (header) file inline with your text
//; include("some_header_file.vph");
sub iname: Returns the name of the current instance. Syntactic sugar for the older style get_instance_name()
//; my $inst_name = iname();
OR
//; my $someObj_inst_name = $someObj->iname();

Example for using iname to instantiate a module. In SystemVerilog we might do something like:

Adder#(.w(8),.n(4)) MyAdder(.in1(a),.in2(b),.out(c));

In Genesis2 we can do something like this:

//; my $my_adder = generate('Adder', 'MyAdder', w=>8, n=>4);
`$my_adder->mname()` `$my_adder->iname()` (.in1(a), .in2(b), .out(c));

But it is actually better to use instantiate. See sub instantiate, below.

sub mname: Returns the uniquified module name. This task is especially important since whenever we declare a new module we don't really know whether or not it is going to be uniquified, and how many uniquifations of this module already happened. This enables us to leave the dirty work for Genesis. Note that this is syntactic sugar for the older style method get_module_name
module `mname` (input logic Clk, ... );

// parameterized module code comes here 
endmodule
sub instantiate: Syntactic sugar for $obj->mname() obj->iname() --- I.e., the module and instance name of $obj for the purpose of instantiating that module.
module `mname`(input clk, ...);
// some parameterized module code comes here 

// Let's generate and instantiate an ALU module:
//; my $ALU = generate('ALU', 'ALU_U', param1=>val1, param2=>val2,...);
  `$ALU->instantiate` (.clk(clk), 
                       .arg1(vector1), 
                       .arg2(vector2), 
                       .cmd(operation),
                       .result(result));

// more parameterized module code comes here 
endmodule: `mname`
sub bname: Returns the base module name from which an object was generated. This is the name of the template, before uniquification. Note that this is syntactic sugar for the older style method get_base_name
//; my $BaseName = bname();
//; my $SomeObj_BaseName = $SomeObj->bname();
sub sname: Returns the source file name from which an object was generated. This is the name of the template, before uniquification and before synonyms were applied. Note that this is syntactic sugar for the older style method get_source_name
//; my $SourceName = sname();
//; my $SomeObj_SourceName = $SomeObj->sname();
sub to_string
Returns a nicely formatted string that represents a Perl object.
//; my $variable = {key1=>'val1', key2=>[1..13], key3=>'val3'};
//; my $str = $self->to_string($variable);
sub error
Prints an error message and exits with a printout of the current file and line number. Can be used as either function or method.
//; $self->error("some error message");
//; error("some error message");
sub warning
Prints a warning message and a printout of the current file and line. Does NOT exit. Can be used as either function or method.
//; $self->warning("some message");
//; warning("some message");

Useful Debug Hints

Debug level
In order to see more verbose messages from Genesis during elaboration use the flag -debug n where n is the verbosity level.
Printing objects
The built-in method to_string returns a nicely formatted string that represents a Perl object.
Error and warning messages
It is always a good habit to check the input (that can many times come from a user filling an xml form), and printing errors or warnings accordingly. See the section about Auxiliary Methods for the use of the error and warning predefined methods.
Debug messages to the verilog file
If you want to print debug messages during elaboration, such that they go to the output verilog file, one way is to just use simple text with inline Perl escapes, since simple text is printed to the verilog file by default. You can make these statements a verilog comment so they don't disturb compilation.
 1. This text goes as is to the verilog file... but would cause a verilog compile error since it's not legal verilog
 // 2. This text also goes to the verilog file... but no compile errors this time since for verilog it's a comment
 //; print "3. This is a Perl print command that prints this line to the verilog file... expect verilog compile errors...\n";
 //; print "// 4. This is also a Perl print command. This text also goes to the verilog file... no compile error this time\n";
Debug messages to the screen
If you want to print a debug message to the screen (printed during elaboration time), use one of the following...
 //; print STDOUT "This message goes to standard output. It does NOT go to the verilog file\n";
 //; print STDERR "This message goes to standard error output. It does NOT go to the verilog file\n";
⚠️ **GitHub.com Fallback** ⚠️