Computer Laboratory

Bluepsec Examples

Server Farm

Introduction

This is generic package replicates any Server as many times as you like. For example, we could take the FibServer example (or a DividerServer, left as an exercise to the reader) and replicate it twice as illustrated below. This will route the requests to in an alternating (round-robin) manner the two internal FibServer. If the FibServer is iterative, it will take several cycles, so the ServerFarm version with two FibServers will have twice the bandwidth.

ServerFarm Illustration

Example of ServerFarm instantiating two FibServers

So if the original FibServer was instantiated vis:

FibServerT#(`width) divServ <- mkFibServer;

then the new version with two FibServers is simply:

FibServerT#(`width) fasterDivServ <- mkServerFarm(2,mkFibServer);

This, for me, is an excellent example of how Bluespec allows you to do rapid design exploration.

Notes

  • The Server to be replicated is passed in as a higher-order type called mkServer. A vector of mkServers is created using replicateM (monadic replicate).
  • The incoming request is enqueued into a BypassFIFO. Exactly one of put_requests rules (generated using a for-loop) will be enabled and can forward the request to corresponding server.

The code

/*****************************************************************************
 ServerFarm
 ==========
 Simon Moore, Oct 2009
 
 Substantial improvements by Matthew Naylor in 2013

 Generic module which multiplexes N servers to one server interface.
 Useful if the base server is quite slow and you want several copies of it.

 *****************************************************************************/

package ServerFarm;

import FIFO::*;
import FIFOF::*;
import SpecialFIFOs::*;
import GetPut::*;
import ClientServer::*;
import Connectable::*;
import List::*;
import Assert::*;


module mkServerFarm#(Integer numServers, module#(Server#(requestT,responseT)) mkServer)
     (Server#(requestT,responseT))
      provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
 
  staticAssert(numServers > 1, "ServerFarm: number of servers must be > 1.");  
  staticAssert(numServers < 65, "ServerFarm: number of servers must be < 65.");  
 
  List#(Server#(requestT,responseT)) servers <- replicateM(numServers, mkServer);
 
  Reg#(UInt#(6)) write_server <- mkReg(0);
  Reg#(UInt#(6)) read_server  <- mkReg(0);

  FIFOF#(requestT)  request_fifo  <- mkBypassFIFOF;
  FIFOF#(responseT) response_fifo <- mkBypassFIFOF;

  function Integer nextServer(Integer n);
    let next = n+1;
    return (next>=numServers) ? 0 : next;
  endfunction
  
  for(Integer j=0; j<numServers; j=j+1)
    begin                        
      rule put_requests (write_server == fromInteger(j));
        let r = request_fifo.first;
        request_fifo.deq;
        servers[j].request.put(r);
        write_server <= fromInteger(nextServer(j));
      endrule
      rule gather_results (read_server == fromInteger(j));
        let result <- servers[j].response.get;
        response_fifo.enq(result);
        read_server <= fromInteger(nextServer(j));
      endrule
    end               

  interface Put request = toPut(request_fifo);
  interface Get response = toGet(response_fifo);
   
endmodule

endpackage

Link to the ServerFarm.bsv source