Learning BSV‎ > ‎Advanced Bluespec‎ > ‎Import BVI‎ > ‎

DesignWare Divider

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
Comments