Bluepsec Examples
Server Farm
Introduction
This is generic package replicates any Server as many times as you like. For example, we could take the DividerServer example and replicate it twice as illustrated below. This will route the requests to in an alternating (round-robin) manner the two internal DividerServer. Since the DividerServer is iterative and takes several cycles, the ServerFarm version with two DividerServers will have twice the bandwidth.

Example of ServerFarm instantiating two DividerServers
So if the original DividerServer was instantiated vis:
DividerServerT#(`width) divServ <- mkDividerServer;
then the new version with two DividerServers is simply:
DividerServerT#(`width) fasterDivServ <- mkServerFarm2(mkDividerServer);
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.
- There are some helper functions (e.g. mkServerFarm2) which preserve the Server interface type externally and internally invoke mkServerFarmFull with a ServerFarmFullIfc interface and provides 2 as a parameter of the number of replications required. There doesn't appear to be a mechanism to provide the number of replications without modifying the interface.
The code
/*****************************************************************************
ServerFarm
==========
Simon Moore, Oct 2009
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 Vector::*;
interface ServerFarmFullIfc#(numeric type num_servers, type requestT, type responseT);
interface Server#(requestT,responseT) server;
endinterface
typedef UInt#(TAdd#(TLog#(num_servers),1)) ServerNumT#(numeric type num_servers);
module mkServerFarmFull#(module#(Server#(requestT,responseT)) mkServer)
(ServerFarmFullIfc#(num_servers,requestT,responseT))
provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
let inum_servers = valueof(num_servers);
Vector#(num_servers, Server#(requestT,responseT)) servers <- replicateM(mkServer);
Reg#(ServerNumT#(num_servers)) write_server <- mkReg(0);
Reg#(ServerNumT#(num_servers)) read_server <- mkReg(0);
FIFOF#(requestT) request_fifo <- mkBypassFIFOF;
FIFOF#(responseT) response_fifo <- mkBypassFIFOF;
function ServerNumT#(num_servers) next_server(ServerNumT#(num_servers) n, ServerNumT#(num_servers) max);
let next = n+1;
return (next>=max) ? 0 : next;
endfunction
for(Integer j=0; j<inum_servers; j=j+1)
begin
rule put_requests (write_server==fromInteger(j)); // && request_fifo.notEmpty);
let r = request_fifo.first;
request_fifo.deq;
servers[j].request.put(r);
write_server <= next_server(fromInteger(j),fromInteger(inum_servers));
endrule
rule gather_results (read_server==fromInteger(j)); // && response_fifo.notFull);
let result <- servers[j].response.get;
response_fifo.enq(result);
read_server <= next_server(fromInteger(j),fromInteger(inum_servers));
endrule
end
interface Server server;
interface Put request = toPut(request_fifo);
interface Get response = toGet(response_fifo);
endinterface
endmodule
module mkServerFarm2#(module#(Server#(requestT,responseT)) mkServer)
(Server#(requestT,responseT))
provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
ServerFarmFullIfc#(2,requestT,responseT) sf <- mkServerFarmFull(mkServer);
interface Put request = sf.server.request;
interface Get response = sf.server.response;
endmodule
module mkServerFarm3#(module#(Server#(requestT,responseT)) mkServer)
(Server#(requestT,responseT))
provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
ServerFarmFullIfc#(2,requestT,responseT) sf <- mkServerFarmFull(mkServer);
interface Put request = sf.server.request;
interface Get response = sf.server.response;
endmodule
module mkServerFarm4#(module#(Server#(requestT,responseT)) mkServer)
(Server#(requestT,responseT))
provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
ServerFarmFullIfc#(4,requestT,responseT) sf <- mkServerFarmFull(mkServer);
interface Put request = sf.server.request;
interface Get response = sf.server.response;
endmodule
module mkServerFarm5#(module#(Server#(requestT,responseT)) mkServer)
(Server#(requestT,responseT))
provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
ServerFarmFullIfc#(5,requestT,responseT) sf <- mkServerFarmFull(mkServer);
interface Put request = sf.server.request;
interface Get response = sf.server.response;
endmodule
module mkServerFarm6#(module#(Server#(requestT,responseT)) mkServer)
(Server#(requestT,responseT))
provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
ServerFarmFullIfc#(6,requestT,responseT) sf <- mkServerFarmFull(mkServer);
interface Put request = sf.server.request;
interface Get response = sf.server.response;
endmodule
module mkServerFarm7#(module#(Server#(requestT,responseT)) mkServer)
(Server#(requestT,responseT))
provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
ServerFarmFullIfc#(7,requestT,responseT) sf <- mkServerFarmFull(mkServer);
interface Put request = sf.server.request;
interface Get response = sf.server.response;
endmodule
module mkServerFarm8#(module#(Server#(requestT,responseT)) mkServer)
(Server#(requestT,responseT))
provisos(Bits#(requestT,requestTwidth), Bits#(responseT,responseTwidth));
ServerFarmFullIfc#(8,requestT,responseT) sf <- mkServerFarmFull(mkServer);
interface Put request = sf.server.request;
interface Get response = sf.server.response;
endmodule
endpackage
Link to the ServerFarm.bsv source
