package Verilog
::CodeGen
;
#################################################################################
# Copyright (C) 2002,2003 Wim Vanderbauwhede. All rights reserved. #
# This program is free software; you can redistribute it and/or modify it #
# under the same terms as Perl itself. #
#################################################################################
#print STDOUT "//Package Verilog::CodeGen loaded\n";
use sigtrap qw(die untrapped normal-signals
stack-trace any error-signals);
################################################################################
@Verilog::CodeGen
::ISA
= qw(Exporter);
@Verilog::CodeGen
::EXPORT
=qw(
#Modify this to use different compiler/simulator/viewer
my $compiler="/usr/bin/iverilog";
my $simulator="/usr/bin/vvp";
my $vcdviewer="/usr/local/bin/gtkwave";
# to store the module code for all modules
# for print configuration
my %printcfg=(_fh
=>*STDOUT
,_fn
=>'');
#------------------------------------------------------------------------------
#next 2 lines are fine in general, but for me a fixed class is better (saves typing)
#my $class=ref($invocant) || $invocant;
my $class="Verilog::CodeGen";
if ($keysvals[0] ne 'type'){unshift @keysvals,'type';unshift @_,'type'}
push @keys, shift @keysvals;
push @args, shift @keysvals;
#this is extremely redundant: the hash contains an array with its keys and an array with its values, so everything is there twice!!
my $self= { '_keys'=>[@keys],'_args'=>[@args],@_ };
my $modulekey=join('_',@args);
$self->{modulename
}=$modulekey;
$self->{code
}=&$sub($self);
#eval never works as it should for me
#eval('$self->{code}= &'.$sub.'($self);');
$modules{$modulekey}=$self->{code
};
#===============================================================================
# this is a class method to set the print options
if($invocant=~/=HASH\(0x/) {
if(!$arg || $arg!~/\n|\s/m) { # store the attributes
} elsif (scalar($arg)!~/^\*/ ) {
$printcfg{_fn
}=$filename;
} else { # print the string
my $fh=$printcfg{_fh
}||*STDOUT
;
my $filename=$printcfg{_fn
};
#===============================================================================
#this is a class method to print all currently used modules
my $fh=$printcfg{_fh
}||*STDOUT
;
my $filename=$printcfg{_fn
};
foreach my $key (keys %modules) {
print $fh $modules{$key};
//==============================================================================
#===============================================================================
$objref->output($objref->{code
});
#===============================================================================
# this is what the enduser uses to print instances
my $suffix=shift ; # throw away 'suffix'
my $modpins=$objref->{pins
};
my @modpins=split(',',$modpins);
# assign to nets with same name as default
foreach my $modpin (@modpins) {
$pinlist{$modpin}='.'.$modpin.'('.$modpin.')';
$pinlist{$pin}='.'.$pin.'('.$net.')';
foreach my $key (keys %pinlist) {
push @pinlist,$pinlist{$key};
} else {$pins=$pinlist[0]}
my @args=@
{$objref->{'_args'}};
my $args=join('_',@args);
my $instlabel="x_${args}_$suffix";
my $instline= "$args $instlabel ($pins);\n";
# this is fancy and unnecessary, but anyway
# all instances of a given object
$objref->{_instances
}->{$suffix}=$instline;
$objref->{$suffix}=$instlabel;
# we need: $objname->{$suffix} => $instlabel
$objref->output($instline);
#===============================================================================
# this is for use inside modules
# no print, just return the string
my $suffix=shift ; # throw away 'suffix'
my $modpins=$objref->{pins
};
my @modpins=split(',',$modpins);
# assign to nets with same name as default
foreach my $modpin (@modpins) {
$pinlist{$modpin}='.'.$modpin.'('.$modpin.')';
$pinlist{$pin}='.'.$pin.'('.$net.')';
foreach my $key (keys %pinlist) {
push @pinlist,$pinlist{$key};
} else {$pins=$pinlist[0]}
my @args=@
{$objref->{'_args'}};
my $args=join('_',@args);
my $instlabel="x_${args}_$suffix";
my $instline= "$args $instlabel ($pins);\n";
# this is fancy and unnecessary, but anyway
$objref->{_instances
}->{$suffix}=$instline;
$objref->{$suffix}=$instlabel;
#===============================================================================
my @code=split("\n",$objref->{code
});
foreach my $line (@code){
#===============================================================================
sub find_inst
{ # returns an array ref if multiple instances!
my @code=split("\n",$objref->{code
});
foreach my $line (@code){
if($line=~/$pattern.*$pattern/) {
push @result, $instlabel;
#===============================================================================
# a class method to run the netlist through Icarus Verilog
if(scalar($netlist)=~/=HASH\(0x/){
#$netlist=~/\.v$/ || $netlist.='.v';
system("$compiler -o${netlist}vp $netlist");
system("$simulator ${netlist}vp");
} else {print STDERR
"The run() method only works if the netlist is printed to a file.\n"}
#===============================================================================
# a class method to plot the results with GTKWave
if(scalar($netlist)=~/=HASH\(0x/){
#$netlist=~/\.v$/ || $netlist.='.v';
# send output to /dev/null to avoid blocking the socket!
system("$vcdviewer ${netlist}cd >& /dev/null &");
} else {print STDERR
"The plot() method only works if the netlist is printed to a file.\n"}
################################################################################
#function to convert decimal to binary
for my $nr (0..$nbits-1) {
#MSB=left unshift @Q,'0';
#===============================================================================
# bus[n0:0] => a[n0a:0],b[n0b:0],...
# sum of all widths=width of original bus
my $buswidth=shift @nets;
# an addition for the frequent case of equidistant split:
foreach my $i (0..$n-1) {
$nets[2*$i+1]=$buswidth/$n;
foreach my $i (0..@nets/2-1) {
$fullwidth+=$nets[2*$i+1];
my $code="//generated with splitbus() function\n";
if($fullwidth>$buswidth){
$code="//sum of width exceeds original bus width\n";
if($fullwidth<$buswidth){
$code="//sum of width is smaller than original bus width\n";
foreach my $i (0..@nets/2-1) {
foreach my $b (1 ..$width) {
my $bb=$buswidth-($begin-$b)-1;
$code .="buf xBUF$name$b ($name\[$i\],$busname\[$bb\]);\n";
#===============================================================================
# bus[n0:0] => a[n0a:0],b[n0b:0],...
# sum of all widths=width of original bus
my $buswidth=shift @nets;
# an addition for the frequent case of equidistant split:
foreach my $i (0..$n-1) {
$nets[2*$i+1]=$buswidth/$n;
foreach my $i (0..@nets/2-1) {
$fullwidth+=$nets[2*$i+1];
my $code="//generated with combinebus() function\n";
if($fullwidth>$buswidth){
$code="//sum of width exceeds destination bus width\n";
if($fullwidth<$buswidth){
$code="//sum of width is smaller than destination bus width\n";
foreach my $i (0..@nets/2-1) {
foreach my $b (1 ..$width) {
my $bb=$buswidth-($begin-$b)-1;
$code .="buf xBUF$name$b ($busname\[$bb\],$name\[$i\]);\n";
#===============================================================================
my $design=shift||'Verilog';
if($design eq 'Verilog') {
#we assume that a chdir to the design dir has been done
if($dir ne 'Objects') {$design=$dir; $up='../'}
my $moduledir='DeviceLibs';
$moduledir=($design ne 'Verilog')?
'../..':'../';
system("cp $up../*.v ../DeviceLibs");
# Generated using Verilog::CodeGen::make_module
if (($moduledir!~/\.\./)&& (not -d
"$moduledir")){mkdir "$moduledir", 0755;}
open(OUT
,">$moduledir/$design.pm"); # .. ,../.. or DeviceLibs
my $modulepath=$INC{'Verilog/CodeGen.pm'};
s/Verilog::CodeGen/DeviceLibs::$design/;
/\s+\&make_module/ && next;
/\s+\&create_objtest_code/ && next;
/\s+\&create_code_template/ && do {
foreach my $obj (@objects) {
#===============================================================================
#===============================================================================
sub create_code_template
{
my $design=shift||'Verilog';
if($design eq 'Verilog') {
if($dir ne 'Objects') {$design=$dir; }
#-------------------------------------------------------------------------------
my $varname=$objref->{varname}||'DEFAULT';
my $modname=$objref->{modulename};
} # END of gen_code_template
#-------------------------------------------------------------------------------
$templ=~s/code_template/$objname/gms;
$templ=~s/DesignName/$design/gms;
open(OBJ
,">$objname.pl");
} # END of create_code_template
#===============================================================================
sub create_objtest_code
{
my $design=shift||'Verilog';
if($design eq 'Verilog') {
if($dir ne 'Objects') {$design=$dir; }
#-------------------------------------------------------------------------------
###############################################################################
### This part makes it possible to test the object. ###
if(-d "../$design"){$up='../'}
&make_module('code_template','DesignName');
use DeviceLibs::DesignName;
($design eq 'Verilog') && ($design='');
chdir("$up../../TestObj/$design");
open (VER,">${obj}_default.v");
package DeviceLibs::DesignName;
###############################################################################
### The actual object code starts here ###
#-------------------------------------------------------------------------------
$templ=~s/code_template/$objname/gms;
$templ=~s/DesignName/$design/gms;
open(OBJ
,"<$objname.pl");
open(OBJ
,">$objname.tb");
} # END of create_objtest_code
#===============================================================================
################################################################################
B<Verilog::CodeGen> - Verilog code generator
mkdir 'DeviceLibs/Objects/YourDesign', 0755;
chdir 'DeviceLibs/Objects/YourDesign';
# if the directory YourDesign exists, the second argument can be omitted
# create YourModule.pl in YourDesign
&create_template_file('YourModule','YourDesign');
# create a device library for testing in DeviceLibs/Objects/DeviceLibs
&make_module('YourModule','YourDesign');
# create the final device library in DeviceLibs (once YourModule code is clean)
&make_module('','YourDesign');
The most efficient way to use the code generator is using the GUI (L<scripts/gui.pl> in the distribution). Read the documentation in L<Verilog::CodeGen::Gui.pm>). Alternatively, you can use the scripts that the GUI uses to do the work (in the scripts/GUI folder). If you want to make your own, follow the L<SYNOPSIS>.
Then edit the file YourModule.pl in the folder DeviceLibs/Objects/YourDesign.
my $par=$objref->{parname}||1;
my $submodule=new('SubModule',parname1=>$par);
my $modname=$objref->{modulename};
$code.=$submodule->inst('suffix',P1=>'A');
} # END of gen_YourModule
Then run C<perl YourModule.pl> to check if the code produces valid a Verilog module.
If this is the case, add YourModule to the device library with C<&make_module()>
Next, create a testbench test_YourModule.pl in a directory on the same level as DeviceLibs (TestObj if you use the GUI):
use DeviceLibs::YourDesign;
my $device=new("S_buffer_demux",depth=>7,);
open (VER,">test_S_buffer_demux.v");
module test_S_buffer_demux;
\$display(\" \%0d \%b \%b \",\$time,$x. Z,$x. D);
run("test_S_buffer_demux.v");
#plot("test_S_buffer_demux.v");
Execute the testbench script with C<perl test_YourModule.pl>.
Provides an object-oriented environment to generate Verilog code for modules and testbenches. The Verilog::CodeGen module provides two functions, one to create a code template and another to create a Perl module which contains the device library. This module , DeviceLibs::YourDesign, provides the class methods and contains the objects for every Verilog module; the objects are created based on a fixed template.
The purpose of this module is to allow the generation of customized Verilog modules. A Verilog module can have a large number of parameters like input and output bus width, buffer depth, signal delay etc. The code generator allows to create an object that will generate the Verilog module code for arbitraty values of the parameters.
With the Perl module distribution come a number of utility scripts. The most important one is gui.pl, a GUI frontend for Verilog development using the code generator.
=head2 B<new>(I<$object_name>[,%attributes]);
Create a new Verilog module object. The object attributes are optional, the object should provide reasonable defaults.
=head2 B<output([*filehandle_ref||$filename])>
output() takes a reference to a filehandle or a filename as argument. These are stored in the global %printcfg. Without arguments, this defaults to STDOUT.
If output() is called with as argument a string containing \n and/or \s, this string is printed on the current filehandle.
The code generator stores all submodules of a given module in the global %modules. Calling modules() prints the code for these modules on the current filehandle.
=head2 B<instance([$instance_suffix,%connectivity])>
The instance() method will print the code for the instantiation of the object on the current filehandle. An optional instance suffix can be specified (to distinguish between different instances of the same module), as well as the pin connectivity. If the connectivity for a pin is not specified, it defaults to the pin name.
=head2 B<inst([$instance_suffix,%connectivity])>
The inst() method will return the code for the instantiation of the object as a string. An optional instance suffix can be specified (to distinguish between different instances of the same module), as well as the pin connectivity. If the connectivity for a pin is not specified, it defaults to the pin name.
=head2 B<run([$filename])>
Run the netlist through the Icarus Verilog (http://www.icarus.com) open source verilog simulator. The filename is optional if it was specified with the output() method.
=head2 B<plot([$filename])>
Plot the result of the simulation with gtkwave. For this purpose, the \$dumpvar and \$dumpfile compiler directives must be present in the testbench code. The filename is optional if it was specified with the output() method.
=head2 B<module('modulename')>
This method can be used to print the code for a specified module on the current filehandle.
=head2 B<search(/pattern/)>
Search the verilog code for a given pattern.
=head2 B<find_inst(/pattern/)>
Find all instances matching /pattern/ in the netlist.
=head2 B<{$instance_suffix}>
Returns the full instance name of the object.
$x=$object->{$instance_suffix};
Convert the utility scripts to functions to be called from Verilog::CodeGen.
Put the GUI scripts in a module Gui.pm.
Separate the code for testing purposes from the module object code.
Icarus Verilog L<http://icarus.com/eda/verilog/index.html>
W. Vanderbauwhede B<wim@motherearth.org>.
L<http://www.comms.eee.strath.ac.uk/~wim>
Copyright (c) 2002 Wim Vanderbauwhede. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.