Computer Laboratory

Course pages 2016–17 (still under preparation!)

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 in the VM or on MCS Linux here:

   /servers/ux/clteach/swm11/bluespec

Before using the tools a few environment variables need to be setup which is easily achived by sourcing a bash script:

   source $CLTEACH/swm11/bluespec/setup.bash

Examples and Tutorials

The MPhil Advanced Computer Design course uses Bluespec and you might find the notes and lab sessions to be of interest. Design examples can be found on the PWF Linux here:

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

Many are also 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):

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

Thacker's Tiny Computer in Bluespec

I've created a Bluespec version of Thacker's Tiny Comptuer.

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 $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