Computer Laboratory

ECAD and Architecture Practical Classes

Bluespec SystemVerilog

I have mentioned Bluespec SystemVerilog a couple of times during ECAD lectures. For those feeling adventerous (!), you might like to have a go with Bluespec that I've installed on the PWF Linux here:

   /ux/clteach/swm11/bluespec

Before using the tools a few environment variables need to be setup which is easily achived using the following script which needs to be sourced:

   source /ux/clteach/swm11/bluespec/setup.bash

Examples and Tutorial Material

I teaching an ACS Masters module on Advanced Computer Design - see the course wiki for some of the material. I've also placed design examples on the PWF here:

   /ux/clteach/swm11/bluespec/bluespec-examples

Many of these examples are available open source from: http://www.cl.cam.ac.uk/~swm11/examples/bluespec/

Finally, the official Bluespec SystemVerilog documentation is available here (please do not redistribute over the web):

   /ux/clteach/swm11/bluespec/current/doc/BSV

Quick start

Below is a copy of me running the tools in a shell. Note that there are a few comments (look for the # prefix).

soup:~$ source /ux/clteach/swm11/bluespec/setup.bash
soup:~$ mkdir MyFirstBluespec
soup:~$ cd MyFirstBluespec/
soup:MyFirstBluespec$ cp /ux/clteach/swm11/bluespec/DividerExample/Divider.bsv .
soup:MyFirstBluespec$ cat Divider.bsv 
import FIFO::*;

interface DividerIfc;
   method Action start(UInt#(16) a, UInt#(16) b);
   method ActionValue#(UInt#(16)) get_result;
endinterface


(* synthesize *)
module mkDivider(DividerIfc);
   
   Reg#(UInt#(16)) ra <- mkReg(0);
   Reg#(UInt#(16)) rb <- mkReg(0);
   Reg#(UInt#(16)) d  <- mkReg(0);
   Reg#(Bool) running <- mkReg(False);
   FIFO#(UInt#(16)) result_fifo <- mkLFIFO;

   // horibly inefficient divider implementation!   
   rule do_division (running && (ra>=rb));
      let new_ra = ra - rb;
      let new_d = d+1;
      ra <= new_ra;
      d <= new_d;
      $display("%05t: do_division... ra=%d rb=%d d=%d",$time,ra,rb,d);
      if(new_ra < rb)
         begin
            $display("%05t: do_division enq'd result early",$time);
            result_fifo.enq(new_d);
            running <= False;
         end
   endrule
   
   rule do_ending (running && (ra<rb));
      running <= False;
      result_fifo.enq(d);
      $display("%05t: do_division enq'd result",$time);
   endrule
   
   method Action start(UInt#(16) a, UInt#(16) b) if (!running);
      ra <= a;
      rb <= b;
      d <= 0;
      running <= True;
   endmethod
   
   method ActionValue#(UInt#(16)) get_result;
      result_fifo.deq;
      return result_fifo.first;
   endmethod
   
endmodule



module mkTestBench(Empty);
   Reg#(UInt#(16)) a <- mkReg(13);
   DividerIfc div <- mkDivider;
   
   rule do_init (a>=5);
      div.start(a,3);
      a <= a-5;
      $display("%05t: started division",$time);
   endrule
   
   rule read_result;
      let r <- div.get_result();
      $display("%05t: result = %d",$time,r);
   endrule
   
endmodule
soup:MyFirstBluespec$ # now create a makefile to do simulate the testbench
soup:MyFirstBluespec$ makemakefile Divider.bsv mkTestBench
Creating Makefile with top-level package "Divider.bsv" and top-level module "mkTestBench"
soup:MyFirstBluespec$ make run
bsc -keep-fires -cross-info -sim -g mkTestBench -u Divider.bsv
checking package dependencies
compiling Divider.bsv
code generation for mkDivider starts
Elaborated module file created: mkDivider.ba
code generation for mkTestBench starts
Elaborated module file created: mkTestBench.ba
All packages are up to date.
bsc -keep-fires -cross-info -sim -o mkTestBench  -e mkTestBench  mkTestBench.ba
Bluesim object created: mkTestBench.{h,o}
Bluesim object created: mkDivider.{h,o}
Bluesim object created: schedule.{h,o}
Simulation shared library created: mkTestBench.so
Simulation executable created: mkTestBench
./mkTestBench -m 1500
   10: started division
   20: do_division... ra=   13 rb=    3 d=    0
   30: do_division... ra=   10 rb=    3 d=    1
   40: do_division... ra=    7 rb=    3 d=    2
   50: do_division... ra=    4 rb=    3 d=    3
   50: do_division enq'd result early
   60: result =     4
   60: started division
   70: do_division... ra=    8 rb=    3 d=    0
   80: do_division... ra=    5 rb=    3 d=    1
   80: do_division enq'd result early
   90: result =     2
soup:MyFirstBluespec$ # note that the following C++ files were created and then compiled to form the executable cycle accurate simulation:
soup:MyFirstBluespec$ ls *.cxx
mkDivider.cxx  mkTestBench.cxx  schedule.cxx
soup:MyFirstBluespec$ make clean
rm -f  *.bi *.bo *.ba *.info *.sched *.c *.h *.o *.so  mk*.v  *~ mkTestBench v95/* >/dev/null
soup:MyFirstBluespec$ # now lets synthesis the Verilog by specifying ModelSim as the simulator (i.e. a Verilog simulator)
soup:MyFirstBluespec$ makemakefile Divider.bsv mkTestBench modelsim
Makefile exists, ok to overwrite? (y/N) y
Creating Makefile with top-level package "Divider.bsv" and top-level module "mkTestBench"
soup:MyFirstBluespec$ # the following verilog files were created:
soup:MyFirstBluespec$ ls -l *.v
-rw-r--r-- 1 swm11 swm11 6411 2010-11-08 11:36 mkDivider.v
-rw-r--r-- 1 swm11 swm11 2750 2010-11-08 11:36 mkTestBench.v