2020-01-10 01:01:12 +00:00
#!/usr/bin/env perl
2009-05-04 21:07:57 +00:00
# See copyright, etc in below POD section.
2006-08-26 11:35:28 +00:00
######################################################################
require 5.006_001 ;
2020-01-10 01:01:12 +00:00
use warnings ;
2006-08-26 11:35:28 +00:00
use Getopt::Long ;
use IO::File ;
use Pod::Usage ;
use Data::Dumper ; $ Data:: Dumper:: Indent = 1 ;
use Bit::Vector ;
use strict ;
2019-05-08 02:34:09 +00:00
use vars qw( $Debug ) ;
2006-08-26 11:35:28 +00:00
our @ Orig_ARGV = @ ARGV ;
our $ Rerun_Args = $ 0 . " " . join ( ' ' , @ Orig_ARGV ) ;
2017-09-11 23:18:58 +00:00
$ Rerun_Args =~ s/\s+$// ;
2006-08-26 11:35:28 +00:00
2019-05-08 02:34:09 +00:00
use vars qw( @Blocks
% Vars
% VarAttrs
% VarsBlock
% Tree
@ Commit
$ Depth
% IdWidth
% Ops ) ;
2006-08-26 11:35:28 +00:00
#======================================================================
2019-05-08 02:34:09 +00:00
# width=> Number of bits the output size is, 0=you tell me.
# func=> What to put in output file
# signed=> 0=unsigned output, 1=signed output, '%1'=signed if op1 signed
# lsb=> LSB for variable declarations
# em=> How to calculate emulated return value
# %w Width of this output op ($treeref->{width})
# %v Output value ($treeref->{val})
# %1r First operand ($treeref->{op1})
# %1v First operand value ($treeref->{op1}{val})
# %1w First operand width ($treeref->{op1}{width})
2006-08-26 11:35:28 +00:00
our $ Raise_Weight_Max = 50 ;
% Ops =
(
2019-05-08 02:34:09 +00:00
'VCONST' = > { weight = > 1 && 20 , width = > 0 , sc = > 1 , terminal = > 1 , v = > '%v' , } ,
'VIDNEW' = > { weight = > 1 && 10 , width = > 0 , sc = > 1 , terminal = > 0 , v = > '%i' , } ,
'VIDOLD' = > { weight = > 1 && 20 , width = > 0 , sc = > 1 , terminal = > 0 , v = > '%i' , } ,
'VIDSAME' = > { weight = > 1 && 20 , width = > 0 , sc = > 1 , terminal = > 0 , v = > '%i' , } ,
'VRANGE' = > { weight = > 1 && 30 , width = > 0 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '%i[%2:%3]' , } ,
'VBITSEL' = > { weight = > 1 && 10 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '%i[%2]' , } ,
'VBITSELP' = > { weight = > 1 && 10 , width = > 0 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '%i[%2+:%3]' , } ,
'VBITSELM' = > { weight = > 1 && 10 , width = > 0 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '%i[%2-:%3]' , } ,
2006-08-26 11:35:28 +00:00
# Unary
2019-05-08 02:34:09 +00:00
'VEXTEND' = > { weight = > 1 && 3 , width = > - 2 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '{%xd\'h0,%1}' , } ,
'VLOGNOT' = > { weight = > 1 && 1 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(! %1)' , } ,
'VREDAND' = > { weight = > 1 && 1 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(& %1)' , } ,
'VREDOR' = > { weight = > 1 && 1 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(| %1)' , } ,
'VREDNAND' = > { weight = > 1 && 1 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(~& %1)' , } ,
'VREDNOR' = > { weight = > 1 && 1 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(~| %1)' , } ,
'VREDXNOR' = > { weight = > 1 && 1 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(^~ %1)' , } ,
'VREDXOR' = > { weight = > 1 && 1 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(^ %1)' , } ,
'VNOT' = > { weight = > 1 && 3 , width = > 0 , sc = > 1 , terminal = > 0 , v = > '(~ %1)' , } ,
'VNEGATE' = > { weight = > 1 && 2 , width = > 0 , sc = > 1 , terminal = > 0 , v = > '(- %1)' , } ,
'VCOUNTONES' = > { weight = > 0 && 2 , width = > 32 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '\$countones(%1)' , } , # No ncv support
'VONEHOT' = > { weight = > 0 && 2 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '\$onehot(%1)' , } , # No ncv support
'VONEHOT0' = > { weight = > 0 && 2 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '\$onehot0(%1)' , } , # No ncv support
2006-08-26 11:35:28 +00:00
# Binary
2019-05-08 02:34:09 +00:00
'VAND' = > { weight = > 1 && 2 , width = > 0 , sc = > 1 , terminal = > 0 , v = > '(%1 & %2)' , } ,
'VOR' = > { weight = > 1 && 2 , width = > 0 , sc = > 1 , terminal = > 0 , v = > '(%1 | %2)' , } ,
'VNAND' = > { weight = > 1 && 0 , width = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 ~& %2)' , } , #FIX vcs bug!
'VNOR' = > { weight = > 1 && 0 , width = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 ~| %2)' , } , #FIX vcs bug!
'VXOR' = > { weight = > 1 && 2 , width = > 0 , sc = > 1 , terminal = > 0 , v = > '(%1 ^ %2)' , } ,
'VXNOR' = > { weight = > 1 && 0 , width = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 ^~ %2)' , } , #FIX vcs bug!
'VEQ' = > { weight = > 1 && 2 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 == %2)' , } ,
'VNEQ' = > { weight = > 1 && 2 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 != %2)' , } ,
'VGT' = > { weight = > 1 && 2 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 > %2)' , } ,
'VGTE' = > { weight = > 1 && 2 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 >= %2)' , } ,
'VLT' = > { weight = > 1 && 2 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 < %2)' , } ,
'VLTE' = > { weight = > 1 && 2 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 <= %2)' , } ,
'VEQCASE' = > { weight = > 1 && 2 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 === %2)' , } , # FIX just a = for now
'VNEQCASE' = > { weight = > 1 && 2 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 !== %2)' , } , # FIX just a != for now
'VLOGOR' = > { weight = > 1 && 2 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 || %2)' , } ,
'VLOGAND' = > { weight = > 1 && 2 , width = > 1 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 && %2)' , } ,
'VADD' = > { weight = > 1 && 10 , width = > 0 , sc = > 1 , terminal = > 0 , v = > '(%1 + %2)' , } ,
'VSUB' = > { weight = > 1 && 10 , width = > 0 , sc = > 1 , terminal = > 0 , v = > '(%1 - %2)' , } ,
'VMUL' = > { weight = > 1 && 15 , width = > 0 , sc = > 1 , terminal = > 0 , v = > '(%1 * %2)' , } , # High % as rarely applyable
2017-06-20 23:10:18 +00:00
# Unspecified behavior with == (a-signed / b) -- see t_math_signed5.v test
2019-05-08 02:34:09 +00:00
'VDIV' = > { weight = > 1 && 8 , width = > 0 , signed = > 0 , sc = > 1 , terminal = > 0 , v = > '((%2)==%xw\'h0 ? %xw\'%xsh0:(%1 / %2))' , } ,
'VMODDIV' = > { weight = > 1 && 8 , width = > 0 , signed = > 0 , sc = > 1 , terminal = > 0 , v = > '((%2)==%xw\'h0 ? %xw\'%xsh0:(%1 %% %2))' , } ,
#'VPOW'=> {weight=>2&&0,width=>-64, sc=>0, terminal=>0, v=>'(%1 ** %2)', },
'VSHIFTL' = > { weight = > 1 && 8 , width = > 0 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 << %2)' , } ,
'VSHIFTLS' = > { weight = > 1 && 8 , width = > 0 , signed = > 1 , sc = > 0 , terminal = > 0 , v = > '(%1 <<< %2)' , } ,
'VSHIFTR' = > { weight = > 1 && 8 , width = > 0 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 >> %2)' , } ,
'VSHIFTRS' = > { weight = > 1 && 15 , width = > 0 , signed = > 1 , sc = > 0 , terminal = > 0 , v = > '(%1 >>> %2)' , } , # ShiftR seems to sign extend differently for <=32 and >32 bits
'VCONCAT' = > { weight = > 1 && 4 , width = > - 2 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '{%1,%2}' , } ,
'VREPLIC' = > { weight = > 1 && 2 , width = > 0 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '{%1{%2}}' , } ,
'VREPLIC1W' = > { weight = > 1 && 2 , width = > 0 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '{%1{%2}}' , } ,
'VSIGNED' = > { weight = > 1 && 2 , width = > 0 , signed = > 1 , sc = > 0 , terminal = > 0 , v = > '\$signed(%1)' , } ,
'VUNSIGNED' = > { weight = > 1 && 2 , width = > 0 , signed = > 0 , sc = > 0 , terminal = > 0 , v = > '\$unsigned(%1)' , } ,
2006-08-26 11:35:28 +00:00
# Triops
2019-05-08 02:34:09 +00:00
'VCOND' = > { weight = > 1 && 4 , width = > 0 , sc = > 0 , terminal = > 0 , v = > '(%1 ? %2 : %3)' , } ,
2006-08-26 11:35:28 +00:00
# Control flow
#VIF
#VFOR
#VCASE
#VCASEX
#VCASEZ
) ;
my % ops2 =
(
2019-05-08 02:34:09 +00:00
'VCONST' = > { pl = > '' , rnd = > 'rnd_const(%tr);' } ,
'VIDNEW' = > { pl = > '%tv=$Vars{%i}{val};' ,
rnd = > '%i=next_id(%tw);'
. ' $Vars{%i}=gen_leaf(width=>%tw,trunc=>1,signed=>%tg);'
. ' $VarAttrs{%i}{lsb} = rnd_lsb();'
. ' id_commit(%tr,"%i");1;' , } ,
'VIDOLD' = > { pl = > '%tv=$Vars{%i}{val};' , rnd = > '%i=id_old(%tr);' , ok_id_width = > 1 , } ,
'VIDSAME' = > { pl = > '%tv=$Vars{%i}{val};' , rnd = > '%i=id_same(%tr);' , ok_id_width = > 1 , } ,
2008-10-06 13:59:22 +00:00
# These create IDs they then extract from
2019-05-08 02:34:09 +00:00
'VRANGE' = > { pl = > 'VRANGE(%tr,$Vars{%i}{val},%2v,%3v,$VarAttrs{%i}{lsb});' ,
rnd = > '%i=next_id(%tw); $VarAttrs{%i}{lsb} = 0&&rnd_lsb();'
. ' my $lsb=rnd(128-%tw); my $msb=$lsb+%tw-1;'
. ' %2r=val_leaf($msb); %3r=val_leaf($lsb);'
. ' $Vars{%i}=gen_leaf(width=>($msb+1));' } ,
'VBITSEL' = > { pl = > 'VRANGE(%tr,$Vars{%i}{val},%2v,%2v,$VarAttrs{%i}{lsb});' ,
rnd = > '%i=next_id(%tw); $VarAttrs{%i}{lsb} = 0&&rnd_lsb();'
. ' my $wid=min(128,rnd_width()|3);'
. ' %2r=gen_leaf(width=>(log2($wid)-1),signed=>0);'
. ' $Vars{%i}=gen_leaf(width=>$wid);' } ,
'VBITSELP' = > { pl = > 'VBITSELP(%tr,$Vars{%i}{val},%2v,%3v,$VarAttrs{%i}{lsb});' ,
rnd = > '%i=next_id(%tw); $VarAttrs{%i}{lsb} = 0&&rnd_lsb();'
. ' my $wid=min(128,(%tw+rnd_width()|3)); %3r=val_leaf(%tw); my $maxval = $wid-%tw; %2r=(($maxval<4)?val_leaf($maxval):gen_leaf(width=>(log2($maxval)-1),signed=>0));'
. ' $Vars{%i}=gen_leaf(width=>$wid);' } ,
'VBITSELM' = > { pl = > 'VBITSELM(%tr,$Vars{%i}{val},%2v,%3v,$VarAttrs{%i}{lsb});' ,
rnd = > '%i=next_id(%tw); $VarAttrs{%i}{lsb} = 0&&rnd_lsb();'
. ' my $wid=min(128,(%tw+rnd_width()|3)); %3r=val_leaf(%tw); my $maxval = $wid-1; my $minval=%tw-1; %2r=val_leaf(rnd($maxval-$minval)+$minval);'
. ' $Vars{%i}=gen_leaf(width=>$wid);' } , # No easy way to make expr with specified minimum
2006-08-26 11:35:28 +00:00
# Unary
2019-05-08 02:34:09 +00:00
'VEXTEND' = > { pl = > 'VRESIZE (%tr,%1v);' , rnd = > '%1r=gen_leaf(width=>rnd_width(%tw-1));' } ,
'VLOGNOT' = > { pl = > 'VLOGNOT (%tr,%1v);' , rnd = > '%1r=gen_leaf(width=>0);' } ,
'VREDAND' = > { pl = > 'VREDAND (%tr,%1v);' , rnd = > '%1r=gen_leaf(width=>0);' } ,
'VREDOR' = > { pl = > 'VREDOR (%tr,%1v);' , rnd = > '%1r=gen_leaf(width=>0);' } ,
'VREDNAND' = > { pl = > 'VREDNAND (%tr,%1v);' , rnd = > '%1r=gen_leaf(width=>0);' } ,
'VREDNOR' = > { pl = > 'VREDNOR (%tr,%1v);' , rnd = > '%1r=gen_leaf(width=>0);' } ,
'VREDXOR' = > { pl = > 'VREDXOR (%tr,%1v);' , rnd = > '%1r=gen_leaf(width=>0);' } ,
'VREDXNOR' = > { pl = > 'VREDXNOR (%tr,%1v);' , rnd = > '%1r=gen_leaf(width=>0);' } ,
'VNOT' = > { pl = > 'VNOT (%tr,%1v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg);' } ,
'VNEGATE' = > { pl = > 'VNEGATE (%tr,%1v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg);' } ,
'VCOUNTONES' = > { pl = > 'VCOUNTONES(%tr,%1v);' , rnd = > '%1r=gen_leaf(width=>0);' } ,
'VONEHOT' = > { pl = > 'VONEHOT (%tr,%1v);' , rnd = > '%1r=gen_leaf(width=>0);' } ,
'VONEHOT0' = > { pl = > 'VONEHOT0 (%tr,%1v);' , rnd = > '%1r=gen_leaf(width=>0);' } ,
2006-08-26 11:35:28 +00:00
# Binary
2019-05-08 02:34:09 +00:00
'VAND' = > { pl = > 'VAND (%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);' } ,
'VOR' = > { pl = > 'VOR (%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);' } ,
'VNAND' = > { pl = > 'VNAND (%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);' } ,
'VNOR' = > { pl = > 'VNOR (%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);' } ,
'VXOR' = > { pl = > 'VXOR (%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);' } ,
'VXNOR' = > { pl = > 'VXNOR (%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);' } ,
'VEQ' = > { pl = > 'VEQ (%tr,%1r,%2r);' , rnd = > '%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);' } ,
'VNEQ' = > { pl = > 'VNE (%tr,%1r,%2r);' , rnd = > '%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);' } ,
'VGT' = > { pl = > 'VGT (%tr,%1r,%2r);' , rnd = > '%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);' } ,
'VGTE' = > { pl = > 'VGE (%tr,%1r,%2r);' , rnd = > '%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);' } ,
'VLT' = > { pl = > 'VLT (%tr,%1r,%2r);' , rnd = > '%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);' } ,
'VLTE' = > { pl = > 'VLE (%tr,%1r,%2r);' , rnd = > '%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);' } ,
'VEQCASE' = > { pl = > 'VEQ (%tr,%1r,%2r);' , rnd = > '%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);' } ,
'VNEQCASE' = > { pl = > 'VNE (%tr,%1r,%2r);' , rnd = > '%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);' } ,
'VLOGOR' = > { pl = > 'VLOGOR (%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>0);' } ,
'VLOGAND' = > { pl = > 'VLOGAND(%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>0);' } ,
'VADD' = > { pl = > 'VADD (%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);' , trunc = > 1 , } ,
'VSUB' = > { pl = > 'VSUB (%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);' , trunc = > 1 , } ,
'VMUL' = > { pl = > 'VMUL (%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);' , trunc = > 1 , } , # Multiply generates larger width, so need truncate for safety
'VDIV' = > { pl = > 'VDIV (%tr,%1r,%2r,0);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);' } ,
'VMODDIV' = > { pl = > 'VDIV (%tr,%1r,%2r,1);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);' } ,
#'VPOW'=> {pl=>'VPOW (%tr,%1r,%2r);', rnd=>'%1r=gen_leaf(width=>min(%tw,6),signed=>%tg); %2r=gen_leaf(width=>min(%tw,8),signed=>%tg);', trunc=>1,}, # Generates larger width, so need truncate for safety
'VSHIFTL' = > { pl = > 'VSHIFTL(%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>log2(%tw)+1,signed=>%tg);' } ,
'VSHIFTLS' = > { pl = > 'VSHIFTL(%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>log2(%tw)+1,signed=>%tg);' } ,
'VSHIFTR' = > { pl = > 'VSHIFTR(%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>log2(%tw)+1,signed=>%tg);' } ,
'VSHIFTRS' = > { pl = > 'VSHIFTRS(%tr,%1v,%2v);' , rnd = > '%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>log2(%tw)+1,signed=>%tg);' } ,
'VCONCAT' = > { pl = > 'VCONCAT(%tr,%1v,%2v);' , rnd = > 'my $d=(rnd(%tw-2)+1); %1r=gen_leaf(width=>$d,signed=>0); %2r=gen_leaf(width=>(%tw-$d),signed=>0);' } ,
'VREPLIC' = > { pl = > 'VREPLIC(%tr,%1v,%2v);' , rnd = > 'my $d=rnd_rep_width(%tw); %1r=val_leaf($d); %2r=gen_leaf(width=>(%tw/$d),signed=>0);' } ,
'VREPLIC1W' = > { pl = > 'VREPLIC(%tr,%1v,%2v);' , rnd = > '%1r=val_leaf(%tw); %2r=gen_leaf(width=>1,signed=>0);' } ,
'VSIGNED' = > { pl = > 'VCLONE (%tr,%1v,0);' , rnd = > '%1r=gen_leaf(width=>%tw);' } ,
'VUNSIGNED' = > { pl = > 'VCLONE (%tr,%1v,0);' , rnd = > '%1r=gen_leaf(width=>%tw);' } ,
2006-08-26 11:35:28 +00:00
# Triops
2019-05-08 02:34:09 +00:00
'VCOND' = > { pl = > 'VCOND(%tr,%1v,%2v,%3v);' , rnd = > '%1r=gen_leaf(width=>1); %2r=gen_leaf(width=>%tw,signed=>%tg); %3r=gen_leaf(width=>%tw,signed=>%tg);' } ,
2006-08-26 11:35:28 +00:00
) ;
foreach my $ op ( keys % ops2 ) {
while ( ( my $ key , my $ val ) = each % { $ ops2 { $ op } } ) {
2019-05-08 02:34:09 +00:00
$ Ops { $ op } { $ key } = $ val ;
2006-08-26 11:35:28 +00:00
}
}
#======================================================================
# main
#Bit::Vector->Configuration("ops=arithmetic");
my $ opt_seed = 5 ;
2016-07-22 03:03:54 +00:00
our $ Opt_NumOps = 30 ;
2006-08-26 11:35:28 +00:00
our $ Opt_Depth = 4 ;
2017-09-23 14:49:29 +00:00
our $ Opt_Output ;
2006-08-26 11:35:28 +00:00
our $ Opt_Signed = 1 ;
our $ Opt_Raise ;
our $ Opt_BlockStmts = 2 ;
our $ Signed_Pct = 60 ;
$ Debug = 0 ;
if ( ! GetOptions (
2019-05-08 02:34:09 +00:00
"help" = > \ & usage ,
"debug" = > \ & debug ,
"depth=i" = > \ $ Opt_Depth ,
"blockstmts=i" = > \ $ Opt_BlockStmts ,
"numops=i" = > \ $ Opt_NumOps ,
"o=s" = > \ $ Opt_Output ,
"raise=i" = > \ $ Opt_Raise ,
"seed=i" = > \ $ opt_seed ,
"signed!" = > \ $ Opt_Signed ,
"<>" = > \ & parameter ,
) ) {
2006-08-26 11:35:28 +00:00
usage ( ) ;
}
if ( $ opt_seed == 0 ) {
srand ( ) ;
$ opt_seed = rnd ( 1 << 20 ) + 1 ;
$ Rerun_Args =~ s/-seed[= ]+0/-seed=$opt_seed/ ;
print " $Rerun_Args\n" ;
}
srand ( $ opt_seed ) ;
init ( ) ;
2009-10-27 00:12:09 +00:00
selftest ( ) ;
2006-08-26 11:35:28 +00:00
gentest ( ) ;
2017-09-23 14:49:29 +00:00
$ Opt_Output or die "%Error: Need -o option," ;
write_output_v ( $ Opt_Output ) ;
2006-08-26 11:35:28 +00:00
#----------------------------------------------------------------------
sub usage {
2019-10-01 03:15:10 +00:00
pod2usage ( - verbose = > 2 , - exitval = > 0 , - output = > \ * STDOUT ) ;
exit ( 1 ) ; # Unreachable
2006-08-26 11:35:28 +00:00
}
sub debug {
$ Debug = 1 ;
}
sub parameter {
my $ param = shift ;
die "%Error: Unknown parameter: $param\n" ;
}
2008-06-10 01:25:10 +00:00
2006-08-26 11:35:28 +00:00
#######################################################################
#######################################################################
#######################################################################
#######################################################################
# Global Functions
sub init {
for my $ op ( keys % Ops ) {
2019-05-08 02:34:09 +00:00
my $ opref = $ Ops { $ op } ;
$ opref - > { name } = $ op ;
gen_v ( $ opref ) ;
gen_pl ( $ opref ) ;
gen_rnd ( $ opref ) ;
2006-08-26 11:35:28 +00:00
}
raise ( ) ;
}
sub raise {
for ( my $ i = 0 ; $ i < ( $ Opt_Raise || 0 ) ; $ i + + ) {
2019-05-08 02:34:09 +00:00
my @ ops = ( values % Ops ) ;
while ( 1 ) {
my $ rndop = $ ops [ rnd ( $# ops + 1 ) ] ;
next if ! $ rndop - > { weight } ; # Don't turn on disabled ops
$ rndop - > { weight } += rnd ( $ Raise_Weight_Max ) ;
printf "\tWeight %-15s +%d\n" , $ rndop - > { name } , $ rndop - > { weight } ;
last ;
}
2006-08-26 11:35:28 +00:00
}
}
sub gentest {
for ( my $ opn = 0 ; $ opn < $ Opt_NumOps / $ Opt_BlockStmts ; $ opn + + ) {
2019-05-08 02:34:09 +00:00
do_a_test ( ) ;
2006-08-26 11:35:28 +00:00
}
}
#######################################################################
# Randomization
sub _rnd_op_ok {
my $ opref = shift ;
my $ paramref = shift ;
return ( ( $ opref - > { width } == 0
2019-05-08 02:34:09 +00:00
|| $ opref - > { width } == $ paramref - > { width }
# Note -2 means >, while -32 means <!
|| ( $ opref - > { width } == - 31 && $ paramref - > { width } <= 31 ) # -31... must be <31 bits
|| ( $ opref - > { width } == - 32 && $ paramref - > { width } <= 32 ) # -32... must be <32 bits
|| ( $ opref - > { width } == - 63 && $ paramref - > { width } <= 63 ) # -63... must be <63 bits
|| ( $ opref - > { width } == - 64 && $ paramref - > { width } <= 64 ) # -64... must be <64 bits
|| ( $ opref - > { width } == - 2 && $ paramref - > { width } >= 2 ) # -2... must be >2 bits
)
&& ( ! $ opref - > { ok_id_width } || $ IdWidth { $ paramref - > { width } } { $ paramref - > { signed } || 0 } )
&& ( ! defined $ opref - > { signed } || ( $ opref - > { signed } == ( $ paramref - > { signed } || 0 ) ) )
&& ( ! $ opref - > { trunc } || $ paramref - > { trunc } )
&& ( ! $ opref - > { opt_signed } || $ Opt_Signed )
&& ( ( $ Depth < $ Opt_Depth && ! $ paramref - > { need_terminal } )
|| $ opref - > { terminal } ) ) ;
2006-08-26 11:35:28 +00:00
}
sub rnd_op {
my $ paramref = shift ;
my $ totweight = 0 ;
foreach my $ opref ( values % Ops ) {
2019-05-08 02:34:09 +00:00
if ( _rnd_op_ok ( $ opref , $ paramref ) ) {
$ totweight += $ opref - > { weight } ;
}
2006-08-26 11:35:28 +00:00
}
my $ chooseweight = rnd ( $ totweight ) ;
$ totweight = 0 ;
foreach my $ opref ( values % Ops ) {
2019-05-08 02:34:09 +00:00
if ( _rnd_op_ok ( $ opref , $ paramref ) ) {
$ totweight += $ opref - > { weight } ;
if ( $ chooseweight < $ totweight ) {
return $ opref ;
}
}
2006-08-26 11:35:28 +00:00
}
die "%Error: No instructions match," ;
}
sub rnd_width {
my $ max = shift ;
my $ v = rnd ( 100 ) ;
my $ n = ( 0
2019-05-08 02:34:09 +00:00
|| ( ( $ v < 20 ) && 1 )
|| ( ( $ v < 25 ) && 2 )
|| ( ( $ v < 30 ) && 31 )
|| ( ( $ v < 35 ) && 32 )
|| ( ( $ v < 40 ) && 63 )
|| ( ( $ v < 45 ) && 64 )
|| ( ( $ v < 50 ) && 95 )
|| ( ( $ v < 55 ) && 96 )
|| ( rnd ( 128 ) + 1 ) ) ;
2006-08-26 11:35:28 +00:00
if ( $ max && $ n >= $ max ) { $ n = rnd ( $ max - 1 ) + 1 ; }
return $ n ;
}
sub rnd_rep_width {
my $ out = shift ;
return 1 if $ out == 1 ;
# We'd like to pick any divisor that works.
my @ factors ;
for ( my $ div = 1 ; $ div < $ out ; $ div + + ) {
2019-05-08 02:34:09 +00:00
if ( int ( $ out /$div)==($out/ $ div ) ) {
push @ factors , $ div ;
}
2006-08-26 11:35:28 +00:00
}
my $ fac = $ factors [ rnd ( $# factors + 1 ) ] ;
#print "RND REP $out -> $fac (@factors)\n" if $Debug;
return $ fac ;
}
sub rnd_const {
my $ treeref = shift ;
my $ width = $ treeref - > { width } or die ;
my $ v = rnd ( 100 ) ;
my $ val = Bit::Vector - > new ( $ width ) ;
2019-05-08 02:34:09 +00:00
if ( $ v < 25 ) { # zero
} elsif ( $ v < 50 ) { # ones
for ( my $ w = 0 ; $ w <$val-> Word_Size ; + + $ w ) {
$ val - > Word_Store ( 0 , ~ 0 ) ;
}
} elsif ( $ v < 60 ) { # one
$ val - > Word_Store ( 0 , 1 ) ;
} else { # random
for ( my $ w = 0 ; $ w <$val-> Word_Size ; + + $ w ) {
$ val - > Word_Store ( $ w , rnd_int ( ) ) ;
}
2006-08-26 11:35:28 +00:00
}
$ treeref - > { val } = $ val ;
}
sub rnd_int {
my $ v = rnd ( 100 ) ;
return 0 if ( $ v < 25 ) ;
return ~ 0 if ( $ v < 50 ) ;
return 1 if ( $ v < 60 ) ;
return rnd32 ( ) ;
}
2008-06-10 01:25:10 +00:00
2008-10-06 13:59:22 +00:00
sub rnd_lsb {
return 0 ;
#return rnd(8)-4; # Not working yet
}
2006-08-26 11:35:28 +00:00
sub rnd {
return ( int ( rand ( $ _ [ 0 ] ) ) ) if ( $ _ [ 0 ] < ( 1 << 15 ) ) ;
return ( rnd32 ( ) % $ _ [ 0 ] ) ;
}
sub rnd32 {
my $ vp = int ( rand ( 1 << 16 ) ) ;
2019-05-08 02:34:09 +00:00
$ vp ^= ( int ( rand ( 1 << 8 ) ) ) << 16 ; # Single 1<<16 doesn't work
2006-08-26 11:35:28 +00:00
$ vp ^= ( int ( rand ( 1 << 8 ) ) ) << 24 ;
return ( $ vp ) ;
}
#######################################################################
our $ Next_Id = 0 ;
sub next_id {
# Note width hasn't been determined yet
$ Next_Id + + ;
my $ id = sprintf ( "W%04d" , $ Next_Id ) ;
return $ id ;
}
sub id_commit {
my $ treeref = shift ;
my $ width = $ treeref - > { width } ;
my $ signed = $ treeref - > { signed } ;
my $ id = shift ;
push @ Commit , sub {
2019-05-08 02:34:09 +00:00
$ IdWidth { $ width } { $ signed } = [] if ! $ IdWidth { $ width } { $ signed } ;
push @ { $ IdWidth { $ width } { $ signed } } , $ id ;
$ VarsBlock { $ id } { set } = 1 ;
1 ;
2006-08-26 11:35:28 +00:00
} ;
}
2006-09-27 18:00:53 +00:00
sub id_old {
2006-08-26 11:35:28 +00:00
my $ treeref = shift ;
my $ width = $ treeref - > { width } ;
my $ signed = $ treeref - > { signed } ;
my $ n = $# { $ IdWidth { $ width } { $ signed } } + 1 ;
my $ idn = rnd ( $ n ) ;
my $ id = $ IdWidth { $ width } { $ signed } [ $ idn ] ;
$ VarsBlock { $ id } { used } = 1 ;
return $ id ;
}
2006-09-27 18:00:53 +00:00
sub id_same {
my $ treeref = shift ;
my $ width = $ treeref - > { width } ;
my $ signed = $ treeref - > { signed } ;
my @ possible ;
foreach my $ id ( keys % VarsBlock ) {
2019-05-08 02:34:09 +00:00
next if ! $ VarsBlock { $ id } { used } ;
my $ varref = $ Vars { $ id } ;
next if $ varref - > { signed } != $ signed ;
next if $ varref - > { width } != $ width ;
push @ possible , $ id ;
2006-09-27 18:00:53 +00:00
}
my $ n = $# possible + 1 ;
2019-05-08 02:34:09 +00:00
if ( $ n < 1 ) { # Nothing, grab another!
return id_old ( $ treeref , $ width , $ signed ) ;
2006-09-27 18:00:53 +00:00
}
my $ idn = rnd ( $ n ) ;
my $ id = $ possible [ $ idn ] ;
$ VarsBlock { $ id } { used } = 1 ;
return $ id ;
}
2006-08-26 11:35:28 +00:00
sub write_output_v {
my $ filename = shift ;
my $ fh = IO::File - > new ( $ filename , "w" ) or die ( "%Error: $! $filename,\n" ) ;
print $ fh "// Created by: $Rerun_Args\n" ;
2017-09-23 14:49:29 +00:00
print $ fh "module vgen (clk);\n" ;
2006-08-26 11:35:28 +00:00
print $ fh " input clk;\n" ;
2017-09-23 14:49:29 +00:00
print $ fh " reg check; initial check = '0;\n" ;
2006-08-26 11:35:28 +00:00
print $ fh ' initial $write("\n*** Vgen.v starting, seed = ' , $ opt_seed , '\n");' , "\n" ;
print $ fh " // verilator lint_off UNSIGNED\n" ;
print $ fh " // verilator lint_off CMPCONST\n" ;
print $ fh " // verilator lint_off WIDTH\n" ;
print $ fh "\n" ;
my $ cycles = 2 ;
foreach my $ var ( sort ( keys % Vars ) ) {
2019-05-08 02:34:09 +00:00
print $ fh "" , decl_text ( $ var ) , "\n" ;
2006-08-26 11:35:28 +00:00
}
foreach my $ block ( @ Blocks ) {
2019-05-08 02:34:09 +00:00
print $ fh "\t//" . ( '=' x60 ) . "\n" ;
my $ style = rnd ( 100 ) ;
if ( $ style < 15 ) {
# This allows statements to get split up, and constants to propagate
print $ fh " always @(" , join ( " or " , ( 'check' , @ { $ block - > { inputs } } ) ) ;
print $ fh ") begin : $block->{name}\n" ;
print $ fh @ { $ block - > { preass } } ;
print $ fh " end\n" ;
print $ fh " always @(posedge clk) begin : $block->{name}Check\n" ;
print $ fh @ { $ block - > { body } } ;
print $ fh " end\n" ;
}
elsif ( $ style < 40 ) {
print $ fh " always @(" , join ( " or " , ( 'check' , @ { $ block - > { inputs } } ) ) ;
print $ fh ") begin : $block->{name}\n" ;
print $ fh @ { $ block - > { preass } } ;
print $ fh @ { $ block - > { body } } ;
print $ fh " end\n" ;
}
else {
foreach my $ stmt ( @ { $ block - > { preass } } ) {
$ cycles + + ;
print $ fh " always @(posedge clk) begin\n" ;
$ stmt =~ s/ = / <= /mg ;
print $ fh $ stmt ;
print $ fh " end\n" ;
}
print $ fh " always @(posedge clk) begin\n" ;
print $ fh @ { $ block - > { body } } ;
print $ fh " end\n" ;
}
2006-08-26 11:35:28 +00:00
}
2017-09-23 14:49:29 +00:00
print $ fh "\n" ;
print $ fh " parameter [31:0] CYCLES /*verilator public*/ = $cycles;\n" ;
print $ fh "\n" ;
print $ fh " integer cyc; initial cyc = 0;\n" ;
2006-08-26 11:35:28 +00:00
print $ fh " always @(posedge clk) begin\n" ;
2017-09-23 14:49:29 +00:00
print $ fh "`ifdef TEST_VERBOSE\n" ;
print $ fh ' $write("[%0t] cyc=%0d check=%d\n", $time, cyc, check);' , "\n" ;
print $ fh "`endif\n" ;
print $ fh " cyc <= cyc + 1;\n" ;
print $ fh " if (cyc < CYCLES) begin\n" ;
print $ fh " check <= 1'b0;\n" ;
2006-08-26 11:35:28 +00:00
print $ fh " end\n" ;
2017-09-23 14:49:29 +00:00
print $ fh " else if (cyc >= CYCLES) begin\n" ;
print $ fh " check <= 1'b1;\n" ;
print $ fh " if (cyc >= (CYCLES+10)) begin\n" ;
print $ fh ' $write("*-* All Finished *-*\n");' , "\n" ;
print $ fh ' $finish;' , "\n" ;
print $ fh " end\n" ;
2006-08-26 11:35:28 +00:00
print $ fh " end\n" ;
print $ fh " end\n" ;
print $ fh "endmodule\n" ;
$ fh - > close ( ) ;
}
######################################################################
sub callers {
for ( my $ i = 0 ; ; $ i + + ) {
2019-05-08 02:34:09 +00:00
my @ c = caller ( $ i ) ;
last if ! $ c [ 0 ] ;
print "Caller $i: " , join ( ' ' , @ c [ 0 .. 3 ] ) , "\n" ;
2006-08-26 11:35:28 +00:00
}
}
#######################################################################
#######################################################################
#######################################################################
#######################################################################
# Code generation/emitting Functions
sub do_a_test {
local $ Depth = 0 ;
@ Commit = ( ) ;
% VarsBlock = ( ) ;
my $ block = {
2019-05-08 02:34:09 +00:00
name = > "Block" . ( $# Blocks + 2 ) ,
body = > [] ,
preass = > [] ,
inputs = > [] ,
outputs = > [] ,
2006-08-26 11:35:28 +00:00
} ;
for ( my $ i = 0 ; $ i < $ Opt_BlockStmts ; $ i + + ) {
2019-05-08 02:34:09 +00:00
my $ treeref = gen_leaf ( width = > 0 ) ;
push @ { $ block - > { body } } ,
"\tif ($treeref->{text} != " . $ treeref - > val_to_text ( ) . ") if (check) " . stop_text ( ) . ";\n" ;
2006-08-26 11:35:28 +00:00
}
foreach my $ var ( keys % VarsBlock ) {
2019-05-08 02:34:09 +00:00
push @ { $ block - > { inputs } } , $ var
if $ VarsBlock { $ var } { used } && ! $ VarsBlock { $ var } { set } ;
2006-08-26 11:35:28 +00:00
}
foreach my $ var ( reverse ( sort ( keys % Vars ) ) ) {
2019-05-08 02:34:09 +00:00
my $ varref = $ Vars { $ var } ;
next if $ varref - > { printedit } ;
$ varref - > { printedit } = 1 ;
push @ { $ block - > { outputs } } , $ var ;
push @ { $ block - > { preass } } , sprintf ( "\t$var = %s;\n"
, $ varref - > { text } ) ;
2006-08-26 11:35:28 +00:00
}
foreach my $ com ( @ Commit ) {
2019-05-08 02:34:09 +00:00
& { $ com } or die "%Error: Can't eval:\n$com\n $@ " ;
2006-08-26 11:35:28 +00:00
}
push @ Blocks , $ block ;
}
sub gen_leaf {
my $ inforef = { width = > 0 , # Anything
2019-05-08 02:34:09 +00:00
need_terminal = > 0 ,
#trunc=>undef, # Allow multiply op
@ _ } ;
2006-08-26 11:35:28 +00:00
$ inforef - > { width } || = rnd_width ( ) ;
$ inforef - > { signed } = ( $ Opt_Signed && $ inforef - > { width } > 1 && ( rnd ( 100 ) < $ Signed_Pct ) ) ? 1 : 0
2019-05-08 02:34:09 +00:00
if ! defined $ inforef - > { signed } ;
2006-08-26 11:35:28 +00:00
print + ( ( " " x $ Depth ) . "Leaf of width $inforef->{width}\n" ) if $ Debug ;
my $ op = rnd_op ( $ inforef ) ;
my $ treeref = new Vg:: Base ;
while ( ( my $ key , my $ val ) = each % { $ op } ) {
2019-05-08 02:34:09 +00:00
$ treeref - > { $ key } = $ val ;
2006-08-26 11:35:28 +00:00
}
while ( ( my $ key , my $ val ) = each % { $ inforef } ) {
2019-05-08 02:34:09 +00:00
$ treeref - > { $ key } = $ val ;
2006-08-26 11:35:28 +00:00
}
local $ Depth = $ Depth + 1 ;
print "RndSub $treeref->{rnd_sub_text}\n" if $ Debug ;
$ treeref - > { rnd_sub } ( $ treeref ) ;
$ treeref - > tree_dump ( ) if $ Debug ;
print "RndPl\n" if $ Debug ;
$ treeref - > { pl_sub } ( $ treeref ) ;
print "RndV\n" if $ Debug ;
$ treeref - > { text } = $ treeref - > { v_sub } ( $ treeref ) ;
print "Done\n" if $ Debug ;
print " Value " , $ treeref - > { val } , " = " , $ treeref - > val_to_text ( ) , "\n" if $ Debug ;
#$treeref->tree_dump() if $Debug;
2019-05-08 02:34:09 +00:00
$ treeref - > { val_size } = $ treeref - > { val } - > Size ; # Debugging
$ treeref - > { val_text } = $ treeref - > { val } - > to_Hex ; # Debugging
2006-08-26 11:35:28 +00:00
2009-10-27 00:12:09 +00:00
( $ treeref - > { val } - > Size == $ treeref - > { width } )
2019-05-08 02:34:09 +00:00
or die "%Error: Size mismatch " , $ treeref - > { val } - > Size , "!=" , $ treeref - > { width } , "\n" , Dumper ( $ treeref ) ;
2006-08-26 11:35:28 +00:00
return $ treeref ;
}
sub gen_v {
my $ opref = shift ;
my $ fmt = $ opref - > { v } ;
$ fmt =~ s/%1/%s/g ;
$ fmt =~ s/%2/%s/g ;
$ fmt =~ s/%3/%s/g ;
$ fmt =~ s/%v/%s/g ;
$ fmt =~ s/%i/%s/g ;
2009-10-27 00:12:09 +00:00
$ fmt =~ s/%x[wds]/%s/g ;
2006-08-26 11:35:28 +00:00
my $ argl = $ opref - > { v } ;
my @ args ;
2009-10-27 00:12:09 +00:00
while ( $ argl =~ s/(%x.|%.)// ) {
2019-05-08 02:34:09 +00:00
my $ arg = $ 1 ;
push @ args , '$treeref->{op1}{text}' if $ arg =~ /%1/ ;
push @ args , '$treeref->{op2}{text}' if $ arg =~ /%2/ ;
push @ args , '$treeref->{op3}{text}' if $ arg =~ /%3/ ;
push @ args , '$treeref->val_to_text' if $ arg =~ /%v/ ;
push @ args , '$treeref->{id}' if $ arg =~ /%i/ ;
push @ args , '$treeref->{signed}?"s":""' if $ arg =~ /%xs/ ;
push @ args , '$treeref->{width}' if $ arg =~ /%xw/ ;
push @ args , '$treeref->{width}-$treeref->{op1}{width}' if $ arg =~ /%xd/ ;
2006-08-26 11:35:28 +00:00
}
my $ func = ( "sub { "
2019-05-08 02:34:09 +00:00
. " my \$treeref = shift;"
. " sprintf(\"$fmt\"," . join ( ',' , @ args ) . ");"
. "}" ) ;
2006-08-26 11:35:28 +00:00
my $ set = ( "\$opref->{v_sub} = $func; 1;" ) ;
2019-05-08 02:34:09 +00:00
$ opref - > { v_sub_text } = $ func ; # For seeing it in debugging dumps
2006-08-26 11:35:28 +00:00
#print "Op V $opref->{name} $set\n";
eval ( $ set ) or die "%Error: Can't eval:\n$set\n $@ " ;
}
sub escapes {
my $ str = shift ;
my $ cmt = shift ;
$ str =~ s/%tr/\$treeref/g ;
$ str =~ s/%tg/\$treeref->{signed}/g ;
$ str =~ s/%tv/\$treeref->{val}/g ;
$ str =~ s/%tw/\$treeref->{width}/g ;
#
$ str =~ s/%1r/\$treeref->{op1}/g ;
2014-05-04 00:11:38 +00:00
$ str =~ s/%1g/\$treeref->{op1}{signed}/g ;
2006-08-26 11:35:28 +00:00
$ str =~ s/%1n/(\$treeref->{op1}{val}->Word_Read(0))/g ;
$ str =~ s/%1v/\$treeref->{op1}{val}/g ;
$ str =~ s/%1w/\$treeref->{op1}{width}/g ;
#
$ str =~ s/%2r/\$treeref->{op2}/g ;
2014-05-04 00:11:38 +00:00
$ str =~ s/%2g/\$treeref->{op2}{signed}/g ;
2006-08-26 11:35:28 +00:00
$ str =~ s/%2n/(\$treeref->{op2}{val}->Word_Read(0))/g ;
$ str =~ s/%2v/\$treeref->{op2}{val}/g ;
$ str =~ s/%2w/\$treeref->{op2}{width}/g ;
#
$ str =~ s/%3r/\$treeref->{op3}/g ;
2014-05-04 00:11:38 +00:00
$ str =~ s/%3g/\$treeref->{op3}{signed}/g ;
2006-08-26 11:35:28 +00:00
$ str =~ s/%3n/(\$treeref->{op3}{val}->Word_Read(0))/g ;
$ str =~ s/%3v/\$treeref->{op3}{val}/g ;
$ str =~ s/%3w/\$treeref->{op3}{width}/g ;
#
$ str =~ s/%i/\$treeref->{id}/g ;
( $ str !~ /%/ ) or die "%Error: $cmt: Unknown %% escape in $str," ;
return $ str ;
}
sub gen_pl {
my $ opref = shift ;
my $ str = escapes ( $ opref - > { pl } , $ opref - > { name } ) ;
my $ func = ( "sub { "
2019-05-08 02:34:09 +00:00
. " my \$treeref = shift;"
. " $str;"
. "}" ) ;
2006-08-26 11:35:28 +00:00
my $ set = ( "\$opref->{pl_sub} = $func; 1;" ) ;
2019-05-08 02:34:09 +00:00
$ opref - > { pl_sub_text } = $ func ; # For seeing it in debugging dumps
2006-08-26 11:35:28 +00:00
#print "Op PL $opref->{name} $set\n";
eval ( $ set ) or die "%Error: Can't eval:\n$set\n $@ " ;
}
sub gen_rnd {
my $ opref = shift ;
my $ str = escapes ( $ opref - > { rnd } , $ opref - > { name } ) ;
my $ func = ( "sub { "
2019-05-08 02:34:09 +00:00
. " my \$treeref = shift;"
. " $str;"
. "}" ) ;
2006-08-26 11:35:28 +00:00
my $ set = ( "\$opref->{rnd_sub} = $func; 1;" ) ;
2019-05-08 02:34:09 +00:00
$ opref - > { rnd_sub_text } = $ func ; # For seeing it in debugging dumps
2006-08-26 11:35:28 +00:00
#print "Op RND $opref->{name} $set\n";
eval ( $ set ) or die "%Error: Can't eval:\n$set\n $@ " ;
}
sub stop_text {
2017-09-08 01:08:49 +00:00
return '$stop' ;
2006-08-26 11:35:28 +00:00
}
sub decl_text {
my $ var = shift ;
my $ decl_with = shift ;
my $ varref = $ Vars { $ var } ;
2019-05-08 02:34:09 +00:00
return sprintf ( " reg %s [%3d:%3d] %s %s; //=%d'h%s"
, ( $ varref - > { signed } ? "signed" : " " )
, ( $ varref - > { val } - > Size ) - 1 + $ VarAttrs { $ var } { lsb } ,
, $ VarAttrs { $ var } { lsb }
, $ var
, ( rnd ( 100 ) < 30 ? "/*verilator public*/" : ( " " x length ( "/*verilator public*/" ) ) )
, $ varref - > { val } - > Size
, lc $ varref - > { val } - > to_Hex ) ;
2006-08-26 11:35:28 +00:00
}
#######################################################################
#######################################################################
#######################################################################
#######################################################################
# Math Functions
2009-10-27 00:12:09 +00:00
sub selftest {
my $ o = { } ;
VDIV ( $ o , { val = > Bit::Vector - > new_Dec ( 8 , 0xff ) } , { val = > Bit::Vector - > new_Dec ( 8 , 0x13 ) } , 0 ) ;
( $ o - > { val } - > Word_Read ( 0 ) == 0x0d ) or die ;
VDIV ( $ o , { val = > Bit::Vector - > new_Dec ( 8 , 0xff ) } , { val = > Bit::Vector - > new_Dec ( 8 , 0x13 ) } , 1 ) ;
( $ o - > { val } - > Word_Read ( 0 ) == 0x08 ) or die ;
VDIV ( $ o , { val = > Bit::Vector - > new_Dec ( 8 , 0xff ) , signed = > 1 } , { val = > Bit::Vector - > new_Dec ( 8 , 0x13 ) , signed = > 1 } , 0 ) ;
( $ o - > { val } - > Word_Read ( 0 ) == 0x00 ) or die ;
VDIV ( $ o , { val = > Bit::Vector - > new_Dec ( 8 , 0xff ) , signed = > 1 } , { val = > Bit::Vector - > new_Dec ( 8 , 0x13 ) , signed = > 1 } , 1 ) ;
( $ o - > { val } - > Word_Read ( 0 ) == 0xff ) or die ;
VDIV ( $ o , { val = > Bit::Vector - > new_Dec ( 8 , 0xff ) , signed = > 1 } , { val = > Bit::Vector - > new_Dec ( 8 , 0xdb ) , signed = > 1 } , 1 ) ;
( $ o - > { val } - > Word_Read ( 0 ) == 0xff ) or die ;
VDIV ( $ o , { val = > Bit::Vector - > new_Dec ( 8 , 0x72 ) , signed = > 1 } , { val = > Bit::Vector - > new_Dec ( 8 , 0xdb ) , signed = > 1 } , 1 ) ;
( $ o - > { val } - > Word_Read ( 0 ) == 0x3 ) or die ;
}
2006-08-26 11:35:28 +00:00
sub val_leaf { return { width = > 32 , signed = > 0 , val = > Bit::Vector - > new_Dec ( 32 , $ _ [ 0 ] ) , text = > $ _ [ 0 ] , } ; }
sub makebool { return ( Bit::Vector - > new_Dec ( 1 , $ _ [ 0 ] ) ) ; }
sub newsized { return ( Bit::Vector - > new ( $ _ [ 0 ] - > Size ) ) ; }
sub max { return $ _ [ 0 ] < $ _ [ 1 ] ? $ _ [ 1 ] : $ _ [ 0 ] ; }
sub min { return $ _ [ 0 ] > $ _ [ 1 ] ? $ _ [ 1 ] : $ _ [ 0 ] ; }
sub log2 {
for ( my $ i = 31 ; $ i >= 0 ; $ i - - ) {
2019-05-08 02:34:09 +00:00
return $ i + 1 if $ _ [ 0 ] > ( 1 << $ i ) ;
2006-08-26 11:35:28 +00:00
}
return 0 ;
}
sub countones {
my $ out = 0 ;
for ( my $ bit = 0 ; $ bit < $ _ [ 0 ] - > Size ; $ bit + + ) {
2019-05-08 02:34:09 +00:00
$ out + + if $ _ [ 0 ] - > bit_test ( $ bit ) ;
2006-08-26 11:35:28 +00:00
}
return $ out ;
}
2011-07-08 10:03:07 +00:00
sub VLOGNOT { $ _ [ 0 ] { val } = makebool ( ( $ _ [ 1 ] - > is_empty ) ? 1 : 0 ) ; }
sub VNEGATE { $ _ [ 0 ] { val } = my $ o = newsized ( $ _ [ 1 ] ) ; $ o - > Negate ( $ _ [ 1 ] ) ; }
2006-08-26 11:35:28 +00:00
sub VCOUNTONES { $ _ [ 0 ] { val } = Bit::Vector - > new_Dec ( 32 , countones ( $ _ [ 1 ] ) ) ; }
sub VONEHOT { $ _ [ 0 ] { val } = makebool ( ( countones ( $ _ [ 1 ] ) == 1 ) ? 1 : 0 ) ; }
sub VONEHOT0 { $ _ [ 0 ] { val } = makebool ( ( countones ( $ _ [ 1 ] ) <= 1 ) ? 1 : 0 ) ; }
sub VLOGAND { $ _ [ 0 ] { val } = makebool ( ( ! ( $ _ [ 1 ] - > is_empty ) && ! ( $ _ [ 2 ] - > is_empty ) ) ? 1 : 0 ) ; }
sub VLOGOR { $ _ [ 0 ] { val } = makebool ( ( ! ( $ _ [ 1 ] - > is_empty ) || ! ( $ _ [ 2 ] - > is_empty ) ) ? 1 : 0 ) ; }
sub VCOND { if ( ! ( $ _ [ 1 ] - > is_empty ) ) { $ _ [ 0 ] { val } = $ _ [ 2 ] - > Clone ; } else { $ _ [ 0 ] { val } = $ _ [ 3 ] - > Clone ; } }
sub VREDAND { $ _ [ 0 ] { val } = makebool ( ( $ _ [ 1 ] - > is_full ) ? 1 : 0 ) ; }
sub VREDOR { $ _ [ 0 ] { val } = makebool ( ( $ _ [ 1 ] - > is_empty ) ? 0 : 1 ) ; }
sub VREDNAND { $ _ [ 0 ] { val } = makebool ( ( $ _ [ 1 ] - > is_full ) ? 0 : 1 ) ; }
sub VREDNOR { $ _ [ 0 ] { val } = makebool ( ( $ _ [ 1 ] - > is_empty ) ? 1 : 0 ) ; }
sub VREDXOR {
my $ out = 0 ;
for ( my $ bit = 0 ; $ bit < $ _ [ 1 ] - > Size ; $ bit + + ) {
2019-05-08 02:34:09 +00:00
$ out ^= $ _ [ 1 ] - > bit_test ( $ bit ) ;
2006-08-26 11:35:28 +00:00
}
$ _ [ 0 ] { val } = makebool ( $ out ) ;
}
sub VREDXNOR {
my $ out = 1 ;
for ( my $ bit = 0 ; $ bit < $ _ [ 1 ] - > Size ; $ bit + + ) {
2019-05-08 02:34:09 +00:00
$ out ^= $ _ [ 1 ] - > bit_test ( $ bit ) ;
2006-08-26 11:35:28 +00:00
}
$ _ [ 0 ] { val } = makebool ( $ out ) ;
}
sub eithercompare { ( $ _ [ 1 ] - > { signed } && $ _ [ 2 ] - > { signed } )
2019-05-08 02:34:09 +00:00
? $ _ [ 1 ] { val } - > Compare ( $ _ [ 2 ] { val } )
: $ _ [ 1 ] { val } - > Lexicompare ( $ _ [ 2 ] { val } ) ; }
2006-08-26 11:35:28 +00:00
sub VEQ { $ _ [ 0 ] { val } = makebool ( ( eithercompare ( $ _ [ 0 ] , $ _ [ 1 ] , $ _ [ 2 ] ) == 0 ) ? 1 : 0 ) ; }
sub VNE { $ _ [ 0 ] { val } = makebool ( ( eithercompare ( $ _ [ 0 ] , $ _ [ 1 ] , $ _ [ 2 ] ) != 0 ) ? 1 : 0 ) ; }
sub VLT { $ _ [ 0 ] { val } = makebool ( ( eithercompare ( $ _ [ 0 ] , $ _ [ 1 ] , $ _ [ 2 ] ) < 0 ) ? 1 : 0 ) ; }
sub VLE { $ _ [ 0 ] { val } = makebool ( ( eithercompare ( $ _ [ 0 ] , $ _ [ 1 ] , $ _ [ 2 ] ) <= 0 ) ? 1 : 0 ) ; }
sub VGT { $ _ [ 0 ] { val } = makebool ( ( eithercompare ( $ _ [ 0 ] , $ _ [ 1 ] , $ _ [ 2 ] ) > 0 ) ? 1 : 0 ) ; }
sub VGE { $ _ [ 0 ] { val } = makebool ( ( eithercompare ( $ _ [ 0 ] , $ _ [ 1 ] , $ _ [ 2 ] ) >= 0 ) ? 1 : 0 ) ; }
sub VSHIFTLxx {
print "$Vars{vq}->ShiftL($_[0],$_[1]);\n" ;
print " " , $ _ [ 0 ] - > to_Hex , " " , $ _ [ 1 ] - > to_Hex , ";\n" ;
my $ out = $ _ [ 0 ] - > Clone ;
$ out - > Move_Left ( $ _ [ 1 ] - > Word_Read ( 0 ) ) ;
print $ out - > to_Hex , "\n" ;
return $ out ; }
sub VAND { $ _ [ 0 ] { val } = my $ o = newsized ( $ _ [ 1 ] ) ; $ o - > Intersection ( $ _ [ 1 ] , $ _ [ 2 ] ) ; }
sub VOR { $ _ [ 0 ] { val } = my $ o = newsized ( $ _ [ 1 ] ) ; $ o - > Union ( $ _ [ 1 ] , $ _ [ 2 ] ) ; }
sub VNAND { $ _ [ 0 ] { val } = my $ o = newsized ( $ _ [ 1 ] ) ; $ o - > Intersection ( $ _ [ 1 ] , $ _ [ 2 ] ) ; $ o - > Complement ( $ o ) ; }
sub VNOR { $ _ [ 0 ] { val } = my $ o = newsized ( $ _ [ 1 ] ) ; $ o - > Union ( $ _ [ 1 ] , $ _ [ 2 ] ) ; $ o - > Complement ( $ o ) ; }
sub VXOR { $ _ [ 0 ] { val } = my $ o = newsized ( $ _ [ 1 ] ) ; $ o - > ExclusiveOr ( $ _ [ 1 ] , $ _ [ 2 ] ) ; }
sub VXNOR { $ _ [ 0 ] { val } = my $ o = newsized ( $ _ [ 1 ] ) ; $ o - > ExclusiveOr ( $ _ [ 1 ] , $ _ [ 2 ] ) ; $ o - > Complement ( $ o ) ; }
sub VNOT { $ _ [ 0 ] { val } = my $ o = newsized ( $ _ [ 1 ] ) ; $ o - > Complement ( $ _ [ 1 ] ) ; }
sub VSHIFTL { $ _ [ 0 ] { val } = my $ o = $ _ [ 1 ] - > Clone ; $ o - > Move_Left ( $ _ [ 2 ] - > Word_Read ( 0 ) ) ; }
sub VSHIFTR { $ _ [ 0 ] { val } = my $ o = $ _ [ 1 ] - > Clone ; $ o - > Move_Right ( $ _ [ 2 ] - > Word_Read ( 0 ) ) ; }
sub VSHIFTRS { $ _ [ 0 ] { val } = my $ o = $ _ [ 1 ] - > Clone ; $ o - > Move_Right ( $ _ [ 2 ] - > Word_Read ( 0 ) ) ;
2019-05-08 02:34:09 +00:00
if ( $ _ [ 1 ] - > msb ( ) && $ _ [ 2 ] - > Word_Read ( 0 ) > 0 ) { $ o - > Interval_Fill ( max ( 0 , $ o - > Size - 1 - $ _ [ 2 ] - > Word_Read ( 0 ) ) , $ o - > Size - 1 ) ; }
#print (" SHI ",$_[0]{val}->to_Hex,' = ',$_[1]->to_Hex,' >>> ',$_[2]->Word_Read(0),"\n");
2006-08-26 11:35:28 +00:00
}
sub VCLONE { $ _ [ 0 ] { val } = $ _ [ 1 ] - > Clone ; }
sub VRESIZE {
$ _ [ 0 ] { val } = $ _ [ 1 ] - > Clone ;
$ _ [ 0 ] { val } - > Resize ( $ _ [ 0 ] { width } ) ;
}
sub VADD { $ _ [ 0 ] { val } = my $ o = newsized ( $ _ [ 1 ] ) ; $ o - > add ( $ _ [ 1 ] , $ _ [ 2 ] , 0 ) ; }
sub VSUB { $ _ [ 0 ] { val } = my $ o = newsized ( $ _ [ 1 ] ) ; $ o - > subtract ( $ _ [ 1 ] , $ _ [ 2 ] , 0 ) ; }
2009-10-27 00:12:09 +00:00
sub VMUL {
# Multiply is signed, so need an additional sign bit
my $ a = $ _ [ 1 ] - > Clone ; $ a - > Resize ( $ a - > Size + 1 ) ;
my $ b = $ _ [ 2 ] - > Clone ; $ b - > Resize ( $ b - > Size + 1 ) ;
my $ mo = Bit::Vector - > new ( $ _ [ 1 ] - > Size + $ _ [ 2 ] - > Size + 1 ) ;
$ mo - > Multiply ( $ a , $ b ) ;
my $ o = newsized ( $ _ [ 1 ] ) ; $ o - > Interval_Copy ( $ mo , 0 , 0 , $ _ [ 1 ] - > Size ) ;
$ _ [ 0 ] { val } = $ o ;
}
sub VDIV {
my $ is_mod = $ _ [ 3 ] ;
if ( $ _ [ 2 ] { val } - > is_empty ) { # Avoid divide by zero
2019-05-08 02:34:09 +00:00
$ _ [ 0 ] { val } = newsized ( $ _ [ 1 ] { val } ) ;
return ;
2009-10-27 00:12:09 +00:00
}
my $ a = $ _ [ 1 ] { val } - > Clone ; if ( ! $ _ [ 1 ] - > { signed } ) { $ a - > Resize ( $ a - > Size + 1 ) ; }
my $ b = $ _ [ 2 ] { val } - > Clone ; if ( ! $ _ [ 2 ] - > { signed } ) { $ b - > Resize ( $ b - > Size + 1 ) ; }
#print ("//DIVpp ",$_[1]->to_Hex,' ',$_[2]->to_Hex,' ',$_[1]->Size,'.',$_[2]->Size," \n");
#print ("//DIVpp ",$a->to_Hex,' ',$b->to_Hex,' ',$a->Size,'.',$b->Size," \n");
my $ quo = newsized ( $ a ) ; my $ rem = newsized ( $ a ) ;
2019-05-08 02:34:09 +00:00
$ quo - > Divide ( $ a , $ b , $ rem ) ; # No division by zero - handled by if above
2009-10-27 00:12:09 +00:00
my $ o = newsized ( $ _ [ 1 ] { val } ) ;
$ o - > Interval_Copy ( $ is_mod ? $ rem : $ quo , 0 , 0 , $ _ [ 1 ] { val } - > Size ) ;
#print "//DIV",($_[1]->{signed}?"S":" "),' w',$a->Size,' ',$_[1]{val}->to_Hex,' ',$_[2]{val}->to_Hex,' =',$quo->to_Hex,'.',$rem->to_Hex," \n";
$ _ [ 0 ] { val } = $ o ;
}
2019-05-08 02:34:09 +00:00
sub VPOW { # Power is a signed operation
2009-10-27 00:12:09 +00:00
my $ a = $ _ [ 1 ] { val } - > Clone ; if ( ! $ _ [ 1 ] - > { signed } ) { $ a - > Resize ( $ _ [ 1 ] { val } - > Size + 1 ) ; }
my $ b = $ _ [ 2 ] { val } - > Clone ; if ( ! $ _ [ 2 ] - > { signed } ) { $ b - > Resize ( $ _ [ 2 ] { val } - > Size + 1 ) ; }
2006-08-26 11:35:28 +00:00
print "VVpow = " , $ _ [ 1 ] { val } - > to_Hex , " ** " , $ _ [ 2 ] { val } - > to_Hex , "\n" ;
my $ mo = Bit::Vector - > new ( $ _ [ 1 ] { val } - > Size + 1 ) ;
$ mo - > Power ( $ a , $ b ) ;
my $ o = Bit::Vector - > new ( $ _ [ 0 ] { width } ) ; $ o - > Interval_Copy ( $ mo , 0 , 0 , $ _ [ 1 ] { val } - > Size ) ;
$ _ [ 0 ] { val } = $ o ;
print "VV = $o\n" ;
}
2019-05-08 02:34:09 +00:00
sub VRANGE {
#print "RANGE ",$_[1]->to_Hex,' ',$_[2]->to_Hex,' ',$_[3]->to_Hex," \n";
return VRANGE_CONST ( $ _ [ 0 ] , $ _ [ 1 ] , $ _ [ 2 ] - > Word_Read ( 0 ) ,
$ _ [ 3 ] - > Word_Read ( 0 ) , $ _ [ 4 ] ) ;
}
2006-08-26 11:35:28 +00:00
sub VBITSELP {
2019-05-08 02:34:09 +00:00
return VRANGE_CONST ( $ _ [ 0 ] , $ _ [ 1 ] , $ _ [ 2 ] - > Word_Read ( 0 ) + $ _ [ 3 ] - > Word_Read ( 0 ) - 1 ,
$ _ [ 2 ] - > Word_Read ( 0 ) , $ _ [ 4 ] ) ;
}
2006-08-26 11:35:28 +00:00
sub VBITSELM {
2019-05-08 02:34:09 +00:00
return VRANGE_CONST ( $ _ [ 0 ] , $ _ [ 1 ] , $ _ [ 2 ] - > Word_Read ( 0 ) ,
$ _ [ 2 ] - > Word_Read ( 0 ) - $ _ [ 3 ] - > Word_Read ( 0 ) + 1 , $ _ [ 4 ] ) ;
}
2008-10-06 13:59:22 +00:00
sub VRANGE_CONST {
# to, from, msb, lsb, variable_lsb_to_subtract
#print "RANGE ",$_[1]->to_Hex,' ',$_[2],' ',$_[3],' ',$_[4]," \n";
my $ size = $ _ [ 2 ] - $ _ [ 3 ] + 1 ;
my $ o = Bit::Vector - > new ( $ size ) ;
if ( $ _ [ 3 ] < $ _ [ 1 ] - > Size ) {
2019-05-08 02:34:09 +00:00
$ o - > Interval_Copy ( $ _ [ 1 ] , 0 , $ _ [ 3 ] - $ _ [ 4 ] , $ size ) ;
2008-10-06 13:59:22 +00:00
}
$ _ [ 0 ] { val } = $ o ; }
sub VCONCAT {
my $ o = Bit::Vector - > new ( $ _ [ 1 ] - > Size + $ _ [ 2 ] - > Size ) ;
$ o - > Interval_Copy ( $ _ [ 1 ] , $ _ [ 2 ] - > Size , 0 , $ _ [ 1 ] - > Size ) ;
$ o - > Interval_Copy ( $ _ [ 2 ] , 0 , 0 , $ _ [ 2 ] - > Size ) ;
$ _ [ 0 ] { val } = $ o ;
}
sub VREPLIC {
my $ o = Bit::Vector - > new ( $ _ [ 1 ] - > Word_Read ( 0 ) * $ _ [ 2 ] - > Size ) ;
my $ pos = 0 ;
for ( my $ time = 0 ; $ time <($_[1]-> Word_Read ( 0 ) ) ; $ time + + ) {
2019-05-08 02:34:09 +00:00
$ o - > Interval_Copy ( $ _ [ 2 ] , $ pos , 0 , $ _ [ 2 ] - > Size ) ;
$ pos += $ _ [ 2 ] - > Size ;
2008-10-06 13:59:22 +00:00
}
$ _ [ 0 ] { val } = $ o ;
}
2006-08-26 11:35:28 +00:00
#######################################################################
#######################################################################
#######################################################################
package Vg::Base ;
use Data::Dumper ;
use strict ;
#------------------------------------------------------------
# CREATORS
sub new {
my $ class = shift ;
my $ self = {
2019-05-08 02:34:09 +00:00
width = > 0 , # Width of expression, 0=Pick a width
#signed=>0/1, # Undef = pick a sign
@ _ } ;
2006-08-26 11:35:28 +00:00
bless $ self , $ class ;
return $ self ;
}
# ACCESSORS
#------------------------------------------------------------
# OUTPUTTING
sub val_to_text {
my $ treeref = shift ;
my $ val = lc $ treeref - > { val } - > to_Hex ( ) ;
$ val = "0" if $ treeref - > { val } - > is_empty ;
2017-09-08 01:08:49 +00:00
return ( $ treeref - > { width }
2019-05-08 02:34:09 +00:00
. ( $ treeref - > { signed } ? "'sh" : "'h" )
. $ val ) ;
2006-08-26 11:35:28 +00:00
}
sub tree_dump {
my $ treeref = shift ;
print Dumper ( $ treeref ) ;
}
2008-06-10 01:25:10 +00:00
2006-08-26 11:35:28 +00:00
#######################################################################
__END__
= pod
= head1 NAME
vgen . pl - Generate random verilog code
= head1 SYNOPSIS
2017-09-23 14:49:29 +00:00
vgen . pl - o vgen . v
2006-08-26 11:35:28 +00:00
= head1 DESCRIPTION
vgen . pl generates automatic random verilog programs .
= head1 ARGUMENTS
= over 4
= item - - help
Displays this message and program version and exits .
= item - - blockstmts
Number of statements per block . Defaults to 2 .
= item - - depth
Maximum depth of generated expressions .
= item - - initial
Put all statements into an initial block . This will probably be optimized
down to a NOP .
= item - - numops
2008-06-10 01:25:10 +00:00
Number of operations to create .
2006-08-26 11:35:28 +00:00
2017-09-23 14:49:29 +00:00
= item - o I <filename>
Specify output filename .
2006-08-26 11:35:28 +00:00
= item - - raise
Pick the specified number of random opcodes , and raise their frequency .
= item - - seed
Seed for the random number generator . Defaults to 5 , 0 = randomize .
= item - - signed
Include some signed arithmetic in the generated code . Experimental .
= back
2009-05-04 21:07:57 +00:00
= head1 DISTRIBUTION
2020-01-06 23:05:53 +00:00
Copyright 2001 - 2020 by Wilson Snyder . Verilator is free software ; you can
2009-05-04 21:07:57 +00:00
redistribute it and / or modify it under the terms of either the GNU Lesser
General Public License Version 3 or the Perl Artistic License Version 2.0 .
This program is distributed in the hope that it will be useful , but WITHOUT
ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
more details .
2006-08-26 11:35:28 +00:00
= head1 AUTHORS
Wilson Snyder <wsnyder@wsnyder.org>
2009-05-04 21:07:57 +00:00
= head1 SEE ALSO
2006-08-26 11:35:28 +00:00
= cut
######################################################################
### Local Variables:
2017-09-23 14:49:29 +00:00
### compile-command: "./vgen.pl --depth=10 --blockstmts=10 -o obj_dir/vgen.v"
### compile-command: "v4make test_regress/t/t_vgen.pl "
2006-08-26 11:35:28 +00:00
### End: