Computer Laboratory

Bluepsec Examples

Fib. Servers

Overview

The following code presents a collection of implementations of modules which compute Fibonacci numbers. The first version is iterative (i.e. it takes multiple cycles). Then there are two versions which create ROMs at compile time using Bluespec's powerful static elaboration system. The ROM versions produce a result in a single cycle but the ROM size obviously grows with the bit-width of the input variable. The ROM versions produce particularly nice Verilog, particularly when one considers that so much static elaboration was done to produce it. Some simple test cases are also provided.


The code

/*****************************************************************************
 Examples of Fibonnaci Servers
 =============================
 Simon Moore, January 2010
 *****************************************************************************/

import FIFO::*;
import GetPut::*;
import ClientServer::*;
import Vector::*;

/*****************************************************************************
 Iterative Fib Server
 *****************************************************************************/

// specialisation of Server interface for Fib
typedef Server#(UInt#(width), UInt#(TMul#(width,4)))
   FibServerT#(numeric type width);

module mkFibServer(FibServerT#(width))
  provisos (Add#(a__, width, TMul#(width, 4)));

  Reg#(UInt#(TMul#(width,4)))            a <- mkRegU;
  Reg#(UInt#(TMul#(width,4)))            b <- mkRegU;
  Reg#(UInt#(TMul#(width,4)))            j <- mkRegU;
  Reg#(Bool)                        active <- mkReg(False);
  FIFO#(UInt#(TMul#(width,4))) result_fifo <- mkLFIFO;
   
  rule loop (active && (j>1));
    a <= a+b;
    b <= a;
    j <= j-1;
  endrule
   
  rule the_end (active && (j==1));
    result_fifo.enq(a);
    active <= False;
  endrule
   
  rule n_is_zero (active && (j==0));
    result_fifo.enq(0);
    active <= False;
  endrule
   
  interface Put request;
    method Action put(n) if (!active);
      j      <= extend(n);
      a      <= 1;
      b      <= 0;
      active <= True;
    endmethod
  endinterface
   
  interface response = toGet(result_fifo);

endmodule


// simple test code for the above  
module mkTestFibServer(Empty);
   
  FibServerT#(8)  fib    <- mkFibServer;
  Reg#(UInt#(8))  n      <- mkReg(0);
  FIFO#(UInt#(8)) inputs <- mkSizedFIFO(4);
   
  rule loop (n <= 20);
    n <= n+1;
    fib.request.put(n);
    inputs.enq(n);
  endrule
   
  rule display_results;
    let r <- fib.response.get();
    inputs.deq;
    $display("%05t: result of fib(%2d)=%d",
       $time, inputs.first, r);
  endrule
   
endmodule


/*****************************************************************************
 Recursive and iterative functions for Fib used in static elaboration
 *****************************************************************************/

function Integer fib_func(Integer n);
  if(n<2) return n;
     else return fib_func(n-1)+fib_func(n-2);
endfunction

function Integer fib_func_iterative(Integer n);
  if(n<2) return n;
  else 
    begin
      Integer a=1;
      Integer b=1;
      for(Integer j=2; j<n; j=j+1)
        begin
	  a=a+b;
	  b=a-b;
        end
      return a;
    end
endfunction

module mkTestFibFunc(Empty);
   
  rule do_fib;
    $display("Output fib results on one cycle");
    for(Integer n=0; n<10; n=n+1)
      begin
        Integer f = fib_func(n);
        $display("%05t: result of fib(%1d)=%d",
		 $time, n, fromInteger(f));
	 end
      $finish();
  endrule

endmodule


/*****************************************************************************
 Fib in ROM
 ==========
 
 Fib. numbers stored in ROMs generated during static elaboration
 (i.e. at compile time).  Arrays and vectors are demonstrated.
 *****************************************************************************/

module mkFibServerROM(FibServerT#(width))
  provisos (Add#(width,TMul#(width,3),TMul#(width,4)));
  
  FIFO#(UInt#(TMul#(width,4))) result_fifo <- mkLFIFO;
  
  UInt#(width) index=0;
  UInt#(TMul#(width,4)) rom[valueOf(TExp#(width))];
  for(Integer n=0; inLiteralRange(index,n); n=n+1)
    rom[fromInteger(n)] = fromInteger(fib_func(n));
   
  interface Put request;
    method Action put(n);
      result_fifo.enq(rom[n]);
    endmethod
  endinterface
   
  interface response = toGet(result_fifo);
   
endmodule


module mkFibServerROMvectors(FibServerT#(width))
  provisos (Add#(width,TMul#(width,3),TMul#(width,4)));
   
  Vector#(TExp#(width), Wire#(UInt#(TMul#(width,4)))) rom <- replicateM(mkBypassWire);
  FIFO#(UInt#(TMul#(width,4))) result_fifo <- mkLFIFO;
  UInt#(width) index=0;

  rule init_rom;
    for(Integer n=0; inLiteralRange(index,n); n=n+1)
      rom[fromInteger(n)] <= fromInteger(fib_func_iterative(n));
  endrule
   
  interface Put request;
    method Action put(n);
      result_fifo.enq(rom[n]);
    endmethod
  endinterface
   
  interface response = toGet(result_fifo);
   
endmodule



// make a test ROM
`define romwidth 4

module mkTestFibServerROM(Empty);
   
  FibServerT#(`romwidth)  fib    <- mkFibServerROM;
  Reg#(UInt#(`romwidth))  n      <- mkReg(1);
  FIFO#(UInt#(`romwidth)) inputs <- mkSizedFIFO(`romwidth);
   
  rule loop (n!=0);
    n <= n+1;
    fib.request.put(n);
    inputs.enq(n);
  endrule
   
  rule display_results;
    let r <- fib.response.get();
    inputs.deq;
    $display("%05t: result of fib(%2d)=%d",
       $time, inputs.first, r);
  endrule
   
endmodule


// make a synthesized version
(* synthesize *)
module mkFibServerROM4(FibServerT#(4));
  FibServerT#(4) fibserver <- mkFibServerROM;
  interface request = fibserver.request;
  interface response = fibserver.response;
endmodule

Link to the FibServer.bsv source