ECAD and Architecture Practical Classes
Bluespec SystemVerilog
I have mentioned Bluespec SystemVerilog a couple of times during ECAD lectures. For those feeling adventurous (!), 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 achieved by sourcing a bash script:
source $CLTEACH/swm11/bluespec/setup.bash
Open Source Bluespec
The Bluespec SystemVerilog compiler was made open source in 2020 and can be built from source: https://github.com/B-Lang-org/bsc
Examples and Tutorials
We have an online Bluespec tutor, based on the SystemVerilog web tutor.
A tutorial available from one of the creaters of Bluespec is available on GitHub: https://github.com/rsnikhil/Bluespec_BSV_Tutorial
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 Computer.
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