#!/usr/bin/perl # # Jeff Mock # 2030 Gough # San Francisco, CA 94109 # jeff@mock.com # (c) 2004 # # # $Id: mkdlpf_mult 262 2004-10-13 06:24:55Z jeff $ # # use Getopt::Long; use Math::Trig; use Math::BigInt; $opt_width = 8; # input width $opt_cwidth = 8; # coefficient (b) width $opt_xwidth = 12; # output width $opt_n = 32; $opt_dir = "."; $opt_odir = "."; $opt_prefix = "jfft"; $opt_norun = 0; $opt_imp = "virtex2"; $opt_xname = ""; $opt_ds = 0; $opt_ro = 0; $0 =~ /(.*)\/.*/; $opt_dir = $1 eq "" ? "." : $1; %opts = ( 'width=o' => \$opt_width, 'cwidth=o' => \$opt_cwidth, 'xwidth=o' => \$opt_xwidth, 'n=o' => \$opt_n, 'dir=s' => \$opt_dir, 'odir=s' => \$opt_odir, 'prefix=s' => \$opt_prefix, 'norun' => \$opt_norun, 'imp=s' => \$opt_imp, 'xname=s' => \$opt_xname, 'ds' => \$opt_ds, 'ro' => \$opt_ro, ); if (!GetOptions(%opts)) { print STDERR " Generate pieces of verilog for a decimating LPF mkdlpf_mult [options] [--n=n] Size of LPF [--width=n] Datapath width of LPF ($opt_width) [--cwidth=n] Datapath width of coefficient (B) ($opt_cwidth) [--xwidth=n] Datapath width of output ($opt_xwidth) [--dir=s] Directory with other mkdlpf programs ($opt_dir) [--odir=s] Output directory for verilog ($opt_odir) [--prefix=s] Prefix module name with string ($opt_prefix) [--norun] Do not recurse and build sub-modules [--imp=s] Set target implementation ($opt_imp) [--xname=s] Extra suffix for name (and filename) [--ds] Downscale result by 0.5 (keeps all of the bits) [--ro] Round output \n"; exit 1; } $opt_xname = "_${opt_xname}" if $opt_xname; sub pcode { my $fd = shift; my $sp = shift; my $code = shift; $code =~ s/^.*?\n//m; $code =~ s/^ {$sp}//mg; $code =~ s/ *$//; print $fd $code; } sub dlpf_mult_module { my $x = $opt_x ? "x" : ""; my $fn = "${opt_odir}/${opt_prefix}${opt_xname}_mult${x}.v"; my $pwid = $opt_width + $opt_cwidth; my $pwidm1 = $pwid - 1; my $xwid = $opt_xwidth; my $xwidm1 = $opt_xwidth - 1; my $xwidp1 = $opt_xwidth + 1; my $awidm1 = $opt_width - 1; my $cwidm1 = $opt_cwidth - 1; if (-s $fn) { print " $fn exists, mkdlpf_mult not creating\n"; return 0; } print " Creating $fn\n"; open $fd, "> $fn" or die "mkdlpf_mult cannot create file $fn.\n $!"; pcode($fd, 8, " // Multiplier // // Generated by mkdlpf_mult "); pcode($fd, 8, " // 2 pipeline delays, no rounding ") if !$opt_ro; pcode($fd, 8, " // 3 pipeline delays, with rounding ") if $opt_ro; pcode($fd, 8, " // module ${opt_prefix}${opt_xname}_mult${x} ( ck, a, b, y ); input ck; input [${awidm1}:0] a; input [${cwidm1}:0] b; output [${xwidm1}:0] y; "); if ($opt_imp eq "virtex2") { my $bitmax = 34; $bitmax = 35 if $opt_ds; my $bitmin = $bitmax - $opt_xwidth + 1; my $bitminr = $bitmin - 1; die "Botch: bitmin is $bitmin" if $bitmin < 0; die "Botch: bitminr is $bitminr" if $bitminr < 0 && $opt_ro; die "Do not know how to make virtex2 multiplers for widths>18" if $opt_cwidth > 18; die "Do not know how to make virtex2 multipliers for outputs>35" if $opt_xwidth > 35; $aop = "a"; $aop = sprintf("{ a, %d\'h0 }", 18-$opt_width) if $opt_width < 18; $aop = sprintf("a[%d:%d]", $opt_width-1, $opt_width-18) if $opt_width > 18; $bop = "b"; $bop = sprintf("{ b, %d\'h0 }", 18-$opt_cwidth) if $opt_cwidth < 18; pcode($fd, 12, " wire [35:0] prod; MULT18X18S m ( .P ( prod ), .A ( ${aop} ), .B ( ${bop} ), .C ( ck ), .CE ( 1'b1 ), .R ( 1'b0 ) ); "); if ($opt_ro) { pcode($fd, 12, " reg [${xwid}:0] yp; reg [${xwid}:0] yp2; wire [${xwidm1}:0] y; always @(posedge ck) begin yp <= prod[${bitmax}:${bitminr}]; yp2 <= yp + ${xwidp1}'d1; end assign y = yp2[${xwid}:1]; "); } else { pcode($fd, 12, " reg [${xwidm1}:0] y; always @(posedge ck) y <= prod[${bitmax}:${bitmin}]; "); } pcode($fd, 12, " endmodule "); } else { if ($opt_ro) { my $bitmax = $pwid - 2; $bitmax = $pwid-1 if $opt_ds; my $bitmin = $bitmax - $opt_xwidth; my $zfill = 0; if ($bitmin < 0) { $zfill = -$bitmin; $bitmin = 0; } pcode($fd, 16, " wire [${pwidm1}:0] prod; wire [${pwidm1}:0] a1; wire [${pwidm1}:0] b1; reg [${xwid}:0] yreg; reg [${xwid}:0] yp; reg [${xwidm1}:0] y; assign a1 = { ${opt_cwidth}{a[${awidm1}]}, a}; assign b1 = { ${opt_width}{b[${cwidm1}]}, b}; assign prod = a1 * b1; always @(posedge ck) begin "); if ($zfill) { pcode($fd, 16, " // With zero fill no actual rounding yreg <= {prod[${bitmax}:${bitmin}], ${zfill}'b0}; yp <= yreg; y <= yp[${xwid}:1]; "); } else { pcode($fd, 16, " yreg <= prod[${bitmax}:${bitmin}]; yp <= yreg + ${xwidp1}'d1; y <= yp[${xwid}:1]; "); } pcode($fd, 16, " end endmodule "); } else { my $bitmax = $pwid - 2; $bitmax = $pwid-1 if $opt_ds; my $bitmin = $bitmax - $opt_xwidth + 1; my $zfill = 0; if ($bitmin < 0) { $zfill = -$bitmin; $bitmin = 0; } pcode($fd, 16, " wire [${pwidm1}:0] prod; wire [${pwidm1}:0] a1; wire [${pwidm1}:0] b1; reg [${xwidm1}:0] yreg; reg [${xwidm1}:0] y; assign a1 = { ${opt_cwidth}{a[${awidm1}]}, a}; assign b1 = { ${opt_width}{b[${cwidm1}]}, b}; assign prod = a1 * b1; always @(posedge ck) begin "); pcode($fd, 16, " yreg <= prod[${bitmax}:${bitmin}]; ") if $zfill==0; pcode($fd, 16, " yreg <= {prod[${bitmax}:${bitmin}], ${zfill}'b0}; ") if $zfill>0; pcode($fd, 16, " y <= yreg; end endmodule "); } } close $fd; } dlpf_mult_module();