DesignWare
Practically speaking, a user may want to import any hardmarco or
preexisting module into BSV, but a DesignWare by Synopsys is a good
example... Fundumentally, it is not much different than any other
import bvi example: You define some methods in an interface, and then
specify how those method arguments connect to each pin of the verilog
file. At the lowest level, the file imported is verilog, so you can add
the necessary DesignWare instantiation or comment directives as needed.
In this case, the main interesting feature is that there are no registers.. This particular divider:
http://www.synopsys.com/products/designware/docs/doc/dwf/datasheets/dw_div.pdf
has no registers, so it has combinational paths from input to
outputs.. The compiler wants to know this as well as knowing how to
schedule the methods so that it may generate proper logic around it..
Additionally, I have added a basic bluespec compatible
"ready/enable" signal pair so that the outputs are not ready to be read
if the inputs have not been driving (for all the reasons we use
implicit conditions in bluespec :)
We don't have a DesignWare license in house, but using the
actual low level component call is a simple exercise, left to the
reader (it's just a simple verilog file at that point).. Set it up once
and add it to your library!
Here is the verilog file I used as the base component:
// wrap a designware divider module div( CLK, CLK_GATE, a, b, quotient, remainder, divide_by_zero, en, rdy ); parameter WIDTH = 1;
// we don't use the clock, many blocks do.. input CLK, CLK_GATE;
// these are the signals needed by the block itself input [WIDTH-1:0] a,b;
output [WIDTH-1:0] quotient, remainder; reg [WIDTH-1:0] quotient, remainder; output divide_by_zero; reg divide_by_zero;
// add ready enable to make this a true bsv block input en; output rdy; reg rdy;
always @(a or b) begin if (en) begin // place your designware comments here, etc divide_by_zero <= (b == 0); quotient <= a / b; remainder <= a % b;
// might as well add bluespec rdy, enable // after all, it's what we do, and it will // save us bugs later rdy <= 1; end else begin rdy <= 0; end end endmodule
Now the actual import bvi code. Essentially, we create an interface
to be used by callers (as with any other bluespec module's interface),
but the module definition is detailed to match the verilog block (as
defined further in the reference manual)..
interface DwDiv#(type tp); // drive inputs via action method // both a/b need to be driven at the same time method Action start( tp a, tp b );
// might be useful to be able to read each output individually method tp quot(); method tp rem(); method Bool zero(); endinterface
import "BVI" div = module mkDwDiv( DwDiv#(UInt#(n)) ); // use this just for UInt#(sizeN) for now // no_clock no_reset;
// allow the width to be parameterized on with width of the BSV input parameter WIDTH = valueof(n);
// make signals in verilog to method arguments method start( a, b ) enable(en); method quotient quot() ready(rdy); method remainder rem() ready(rdy); method divide_by_zero zero() ready(rdy); // tell the compiler all the combinational paths from input to output path (a,quotient); path (a,remainder); path (b,quotient); path (b,remainder); path (b,divide_by_zero); path (en,rdy);
// these are the defaults, but might as well get rid of the warnings schedule (start) SB (quot,rem,zero); schedule (start) C (start); schedule (quot,rem,zero) CF (quot,rem,zero); endmodule
And now the energetic person could create a very small testbench (as
I generally do just to make sure connections are okay, etc)..
import StmtFSM::*;
import DwDiv::*; typedef UInt#(16) TD;
(* synthesize *) module mkTB(); // here is the divider DwDiv#(TD) div <- mkDwDiv;
// just step through a few divides Stmt test = seq div.start( 10, 2 ); div.start( 10, 3 ); div.start( 12, 6 ); div.start( 10, 0 ); div.start( 50, 3 ); noAction; noAction; endseq;
mkAutoFSM( test );
// just display data when it is available rule showResults; $display("q=%x r=%x z=%x", div.quot, div.rem, div.zero); endrule
endmodule
Finally, you can build and run with most verilog simulators with
this make file (a simple one I often use for test cases like this)
all: # compile it bsc -u -verilog \ -vdir obj -bdir obj -simdir obj -p .:obj:+ \ -unspecified-to x TB.bsv
make run
run: # run it bsc -vsim iverilog -e mkTB -o obj/mkTB.exe div.v obj/*.v obj/mkTB.exe
clean: rm -fR obj
And running this with iverilog (can be run with vcs, modelsim,
ncverilog, iverilog, cver, or feel free to use your own command line...
it's just verilog)... The simulation output shows basic functionality:
q=0003 r=0001 z=0 q=0002 r=0000 z=0 q=xxxx r=xxxx z=1 q=0010 r=0002 z=0 q=xxxx r=xxxx z=x q=xxxx r=xxxx z=x
|