RRR Compilation

Michael Adler edited this page Mar 3, 2015 · 1 revision

RRR Compilation

In this tutorial, we will examine the operation of the RRR compiler using the STDIO service as an example. STDIO uses RRR to allow hardware to make use of the software-side STDIO library. The code samples shown below are actual examples used in LEAP source, or produced by the RRR compiler. To reduce the burden of understanding, some parts of the code have been removed. Excisions are denoted by ....

This tutorial covers only the compilation of RRR. Other tutorials cover:

RRR Programming
RRR Architecture

Host-side Software interface

RRR generates host-side interfaces in the form of C++ classes.

Generated Software Client
client_stub_STDIO.h

#ifndef STDIO_CLIENT_STUB
#define STDIO_CLIENT_STUB


#define STDIO_METHOD_ID_Sync 2

typedef UINT8 IN_TYPE_Sync;
typedef UINT8 OUT_TYPE_Sync;

typedef class STDIO_CLIENT_STUB_CLASS* STDIO_CLIENT_STUB;
class STDIO_CLIENT_STUB_CLASS: public PLATFORMS_MODULE_CLASS
{

private: public: STDIO_CLIENT_STUB_CLASS(PLATFORMS_MODULE p) : PLATFORMS_MODULE_CLASS(p) { } ~STDIO_CLIENT_STUB_CLASS() { }


OUT_TYPE_Sync Sync(UINT8 dummy)
{
UMF_MESSAGE msg = new UMF_MESSAGE_CLASS;
msg→SetLength(1);
msg→SetServiceID(STDIO_SERVICE_ID);
msg→SetMethodID(STDIO_METHOD_ID_Sync);
msg→AppendUINT8(dummy);

UMF_MESSAGE resp = RRRClient→MakeRequest(msg); // Blocking call OUT_TYPE_Sync retval; retval = resp→ExtractUINT8(); delete resp; return retval; }


}
#endif

The RRR compiler generates the above code. The Sync method accepts a single argument which is marshalled into a unified RRR packet format.

Generated Software Server

server_stub_STDIO.h

#ifndef __STDIO_SERVER_STUB__
#define __STDIO_SERVER_STUB__

typedef struct
{
    UINT64 data;
    UINT8 eom;
}
IN_TYPE_Req;

...
typedef class STDIO_SERVER_STUB_CLASS* STDIO_SERVER_STUB;
class STDIO_SERVER_STUB_CLASS: public RRR_SERVER_STUB_CLASS,
    public PLATFORMS_MODULE_CLASS
{

  private:

    STDIO_SERVER server;
 
  public:

...
    UMF_MESSAGE Request(UMF_MESSAGE req)
    {
#ifdef BYPASS_SERVER_STUB

        return server->Request(req);

#else

        UMF_MESSAGE resp = NULL;

        UINT32 methodID = req->GetMethodID();

        switch(methodID)
        {
            case STDIO_METHOD_ID_Req:
            {
                UINT8 eom = req->ExtractUINT8();
                UINT64 data = req->ExtractUINT64();
                server->Req(data, eom);
                delete req;
                break;
            }
...
        }
    }
}
#endif

The above code is synthesized by the RRR compiler. For compound arguments and return types RRR will generate a C structure. When the software server receives a request from the FPGA it will decode the message header and invoke the appropriate user-defined handler.

FPGA-side interface

RRR produces hardware-side interfaces in the form of Bluespec System Verilog modules, which make use of SoftConnections. As a result, hardware clients and servers may be instantiated anywhere in a user design, without affecting the user interfaces. Client and server interfaces may be instantiated inside the same code. Methods on hardware clients and servers are split-phase, reflecting the non-atomicity of transporting data to and from the host.

Each RRR server links to the root RRR service by way of soft connections.

Generated Hardware server
server_stub_STDIO.bsh

typedef UINT8 IN_TYPE_Sync;
typedef UINT8 OUT_TYPE_Sync;


// Complete hardware server interface.
interface ServerStub_STDIO;
method ActionValue#(IN_TYPE_Rsp) acceptRequest_Rsp();
method IN_TYPE_Rsp peekRequest_Rsp();
method ActionValue#(IN_TYPE_Rsp64) acceptRequest_Rsp64();
method IN_TYPE_Rsp64 peekRequest_Rsp64();
method ActionValue#(IN_TYPE_Sync) acceptRequest_Sync();
method IN_TYPE_Sync peekRequest_Sync();
method Action sendResponse_Sync(UINT8 ack);
method ActionValue#(IN_TYPE_SetCondMask) acceptRequest_SetCondMask();
method IN_TYPE_SetCondMask peekRequest_SetCondMask();
endinterface

module [CONNECTED_MODULE] mkServerStub_STDIO (ServerStub_STDIO);
// Soft connection to root RRR handling
Connection_Receive#(UMF_PACKET) link_req <- mkConnection_Receive(“rrr_serv\
er_STDIO_req”);
Connection_Send#(UMF_PACKET) link_resp <- mkConnection_Send(“rrr_server_\
STDIO_resp”);
// Link management logic
Reg#(UMF_METHOD_ID) mid <- mkReg(0);
Integer mid_Rsp = 0;
Integer mid_Rsp64 = 1;
Integer mid_Sync = 2;
Integer numChunks_Sync = (8 % valueOf(UMF_CHUNK_BITS)) == 0 ?
(8 / valueOf(UMF_CHUNK_BITS)) :
(8 / valueOf(UMF_CHUNK_BITS)) + 1;
Integer mid_SetCondMask = 3;

rule startRequest (True); UMF_PACKET packet = link_req.receive(); link_req.deq(); mid <= packet.UMF_PACKET_header.methodID; dem.start(packet.UMF_PACKET_header.numChunks); endrule rule continueRequest (True); UMF_PACKET packet = link_req.receive(); link_req.deq(); dem.insert(packet.UMF_PACKET_dataChunk); endrule rule continueResponse (True); UMF_CHUNK chunk = mar.first(); mar.deq(); link_resp.send(tagged UMF_PACKET_dataChunk chunk); endrule


// handler for specific RRR method
method ActionValue#(IN_TYPE_Sync) acceptRequest_Sync() if (mid == fromInteg\
er(mid_Sync));
let a <- dem.readAndDelete();
IN_TYPE_Sync retval = unpack(truncate(a));
return retval;
endmethod

method IN_TYPE_Sync peekRequest_Sync() if (mid == fromInteger(mid_Sync)); let a = dem.peek(); IN_TYPE_Sync retval = unpack(truncate(a)); return retval; endmethod method Action sendResponse_Sync(UINT8 ack) if (! mar.notEmpty); let resp = ack; UMF_PACKET header = tagged UMF_PACKET_header UMF_PACKET_HEADER { filler: ?, phyChannelPvt: ?, channelID: ?, serviceID: `SERVICE_ID, methodID : fromInteger(mid_Sync), numChunks: fromInteger(numChunks_Sync) }; link_resp.send(header); mar.enq(zeroExtend(pack(resp)), fromInteger(numChunks_Sync)); endmethod

endmodule

The generated code for the RRR server stub consists of three methods in Bluespec for each hardware method. peekRequest allows the user code to observe the first request available in the server. The acceptRequest pops the latest request from the server stub. sendResponse returns a response to the host. Those methods without a response value do not have a sendResponse method.

RRR uses a shared marshaller and a shared demarshaller per stub. Thus, only one Request and one Response method can potentially be invoked in a cycle. The rules startRequest, continueRequest, and continueResponse in the example above deal with formatting data packets.

Generated Hardware client
client_stub_STDIO.bsh

`ifndef _STDIO_CLIENT_STUB_
`define _STDIO_CLIENT_STUB_

...

typedef struct
{
    UINT64 data;
    UINT8 eom;
}
IN_TYPE_Req
    deriving (Bits, Eq);

interface ClientStub_STDIO;
    method Action makeRequest_Req(UINT64 data, UINT8 eom);
endinterface

module [CONNECTED_MODULE] mkClientStub_STDIO (ClientStub_STDIO);

    Connection_Send#(UMF_PACKET)    link_req  <- mkConnection_Send("rrr_client_\
STDIO_req");
    Connection_Receive#(UMF_PACKET) link_resp <- mkConnection_Receive("rrr_clie\
nt_STDIO_resp");

    // No return value means that no Demarshaller is required. 
    MARSHALLER_N#(UMF_CHUNK, Bit#(72)) mar <- mkSimpleMarshallerN(True);

...

    rule continueRequest (True);
        UMF_CHUNK chunk = mar.first();
        mar.deq();
        link_req.send(tagged UMF_PACKET_dataChunk chunk);
    endrule

    method Action makeRequest_Req(UINT64 data, UINT8 eom) if (! mar.notEmpty);
        let req = IN_TYPE_Req { data:data, eom:eom };
        UMF_PACKET header = tagged UMF_PACKET_header UMF_PACKET_HEADER
                            {
                                filler: ?,
                                phyChannelPvt: ?,
                                channelID: ?,
                                serviceID: `SERVICE_ID,
                                methodID : fromInteger(mid_Req),
                                numChunks: fromInteger(numChunks_Req)
                            };
        link_req.send(header);
        mar.enq(zeroExtend(pack(req)), fromInteger(numChunks_Req));
    endmethod
endmodule

`endif

Each client method may have up to three synthesized Bluespec methods. makeRequest sends a request to software. peekResponse allows user code to examine the next response from the host. acceptResponse pops the response from the host. Because the Req method of STDIO has no response from host, the Response methods and their corresponding support hardware are not included in the client stub.

As with the RRR server, the RRR client also uses a shared marshalling architecture, and is subject to the same parallelism restrictions.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.