lookupRsp.first
: need to review it to match the CheriTagResponse returned in MultiLevelTagLookup.bsvpeekMemResponse()
: mRsps.first
. See section helper functionConnect to l2 cache; and connect to memory to provide proxied memory interface.
The Connection:
L2Cache — tagController — main memory
in Memory.bsv: mkMIPSMemory(…):
mkConnection(l2CacheMemory, tagController.cache);
// tagController cache is connected with l2 cache’s memory interface. They share the same memory interface. SO there WILL be conflicts and thus performance overhead.memory = topMemIfc = tagControllerMemory;
// Master/client interface to main memory module (not included in .bsv)in MIPSTop.bsv
memory = theMem = mkMIPSMemory
, see MIPSTop.bsvMultiLevelTagLookup
, see MultiLevelTagLoopup, or TagLookupCheriMemRequest/Response
contains a masterID
, the value is used to distinguish which level of cache the request is issued and which level of cache the response is for. In addition, at tagController, it is used to distinguish a regular memory response or a tag response.
CheriMemRespone
is distinguished at Master response interface, and dispatched either back to L2Cache or back to tagLookup.
masterID
for tag request/response is first initialized when a tag cache miss happens and a new CheriMemRequest is crafted. see function CheriMemRquest craftTagReadReq/craftTagWriteReq
in cherilibs/trunk/MultiLevelTagLookup.bsv
;
Every CacheCore
derived module has the cacheID
as the masterID
.
tagController has the same masterID = 12
as its submodule tagLookup
; a request contains this masterID
means a tag request/response;
TagController provides a proxy for memory accesses which adds support for tagged memory.
Tag values are stored in memory (currently at the top of DRAM)
There is a cache of 32ki tags (representing 1MB memory) stored in BRAM (SRAM in FPGA?).
Read responses are amended with the correct tag value and write requests update the value in the tag cache (which is later written back to memory)
// cherilibs/trunk/TagController.bsv
/******************************************************************************
* mkTagController
*
* This module provides a proxy for memory accesses which adds support for
* tagged memory. It connects to memory on one side and the processor/L2 cache
* on the other. Tag values are stored in memory (currently at the top of DRAM
* and there is a cache of 32ki tags (representing 1MB memory) stored in BRAM.
* Read responses are amended with the correct tag value and write requests update
* the value in the tag cache (which is later written back to memory).
*
*****************************************************************************/
Two sub-interfaces:
The definition of CheriMemRequest/CheriMemResponse
is in MemTypes.bsv, which contains the data to be write/read with tags (Data#).
The connections:
mkConnection(l2CacheMemory, tagController.cache);
mkConnection(tagLookup.cache.response,toCheckedPut(ff2fifof(lookupRsp)));
...
-----------------------
| (slave/srv/cache) |
| L2Cache |
| (master/clt/memory) |
-----------------------
/\
|
\/
-------------------------------------------------------------------
| (slave/srv/cache) | |
| | |
| | |
| TagController | -> tag cache req: tagLookup..put(req) |
| | | <- tag cache hit: lookupRsp..first() |
| mem | tag <------------------> (slave/srv/cache) |
| | | | |
| | | tagLookup (~L3Cache) |
| | | | |
| | | |<--------------------> (master/clt/memory) |
| \/ | \/ <- tag cache miss (forwardLookupReqs) |
| (master/clt/memory) -> tag mem rsps () |
-------------------------------------------------------------------
/\
|
\/
| -----------------------------------------------------------------
| mReqs.enq(r) mRsps.first |
| memory |
-------------------------------------------------------------------
Overview: Get input request, hand it over to fifo mReqs
and tagLookup.cache.request
, and wait for the response
memory request CheriMemRequest req
: -> mReqs.enq(req)
memory.request.get()
which returns memReqs.first from L2Cache:cache.put()
which enqueue the request mReqs.enq(req), which willThe cache.put()
will also put the request in tagLookup module: tagLookup.cache.request.put(req)
, which will
// cherilibs/trunk/TagController.bsv
interface Slave cache;
// request side
///////////////////////////////////////////////////////
interface CheckedPut request;
method Bool canPut() = slvCanPut;
method Action put(CheriMemRequest req) if (slvCanPut);
debug2("tagcontroller", $display("<time %0t TagController> New request: ", $time, fshow(req)));
mReqs.enq(req);
`ifndef NOTAG
tagLookup.cache.request.put(req);
`endif
endmethod
endinterface
Output2: (Slave) memory response from here up to l2.
Call peekMemResponse() when slvCanGet
, means there is a response.
response will be returned as CheriMemResponse
to L2Cache
// cherilibs/trunk/TagController.bsv
interface Slave cache;
// response side
///////////////////////////////////////////////////////
interface CheckedGet response;
method Bool canGet() = slvCanGet;
method CheriMemResponse peek() = peekMemResponse();
method ActionValue#(CheriMemResponse) get() if (slvCanGet);
// prepare memory response
CheriMemResponse resp = peekMemResponse();
// dequeue memory response fifo
mRsps.deq();
`ifndef NOTAG
// in case of read response ...
if (resp.operation matches tagged Read .rop) begin
// on the last flit,
if (rop.last) begin
lookupRsp.deq(); // dequeue the tag lookup response fifo
frame <= 0; // reset the current frame
end else frame <= frame + 1; // for non last flits, increment frame
end
`endif
debug2("tagcontroller", $display("<time %0t TagController> Returning response: ", $time, fshow(resp)));
return resp;
endmethod
endinterface
endinterface
(Master/Client) memory requests CheriMemRequest req
from tagController down to mem;
If got a response from memory, the request will be distinguished according to its reqType:
tagLookup.memory.response
otherwise, will send response to data response fifo mRsps
which will be forwarded to l2Cache, as in above section.
// cherilibs/trunk/TagController.bsv
interface Master memory;
// an interface of type CheckedGet#(CheriMemRequest mReqs, see [cherilibs/trunk/MasterSlave.bsv](../master-slave)
// used to send request to memory
interface request = toCheckedGet(ff2fifof(mReqs));
// an interface of type CheckedPut
// used to get response from memory
interface CheckedPut response;
method Bool canPut();
return (mRsps.notFull() && tagLookup.memory.response.canPut());
endmethod
method Action put(CheriMemResponse r) if (mRsps.notFull() && tagLookup.memory.response.canPut());
`ifdef NOTAG
mRsps.enq(r);
`else
MemReqType reqType = (r.masterID == mID) ? TagLookupReq : StdReq;
debug2("tagcontroller", $display("<time %0t TagController> response from memory: source=%x ", $time, reqType, fshow(r)));
if (reqType == TagLookupReq) begin
if (r.operation matches tagged Read.rop) tagLookup.memory.response.put(r);
debug2("tagcontroller", $display("<time %0t TagController> tag response", $time));
end else begin
mRsps.enq(r);
debug2("tagcontroller", $display("<time %0t TagController> memory response", $time));
end
`endif
endmethod
endinterface
endinterface
TagLookupIfc tagLookup <-mkMultiLevelTagLookup(…);
TagTableStructure; // declares and initialize the tableStructure Vector of interger
FF#(CheriTagResponse,4) lookupRsp; // lookup responses fifo
Reg#(Bit#(2)) frame; // lookup response frame to access (for multi-flit transaction)
FF#(CheriMemRequest, 2) mReqs <- mkFF(); // memory request fifo
FF#(CheriMemResponse, 32) mRsps <- mkUGFF(); // memory response fifo
tagLookup module is the core module that handles tag search and tag cache miss, where a cache miss will be forwarded as a normal memory request via mReqs
in this module.
A memory request is sent to tagLookup via connections on Slave request interface
A memory response can be get from tagLookup via this connection: Connetion between tagLookup.cache.response(A Slave#/Server# CheckedGet#) – lookupRsp (toCheckedPut#):
mkConnection(tagLookup.cache.response,toCheckedPut(ff2fifof(lookupRsp)));
A tag lookup miss will be forward as a regular memory request in rule forwardLookupReqs
rule forwardLookupReqs(tagLookup.memory.request.canGet() && mReqs.notFull()); // forwards the tag lookup requests to the memory interface
rule debug; // print debug2 information every cycle?
Forwards tag lookup requests (tagLookup.memory.request
) to the memory interface (via fifo mReqs.enq(r)
).
Note: if tagLookup module got a tag cache miss, then this rule will be triggered and new tag-related memory request will be put in the queue mReqs
.
// forwards tag lookup requests to the memory interface
rule forwardLookupReqs(tagLookup.memory.request.canGet() && mReqs.notFull());
debug2("tagcontroller",
$display(
"<time %0t TagController> Injecting request from tag lookup engine: ",
$time, fshow(tagLookup.memory.request.peek())
));
CheriMemRequest r <- tagLookup.memory.request.get();
mReqs.enq(r);
endrule
peekMemResponse(): grab a response from fifo mRsps, parse the tag if read and return the response struct.
function CheriMemResponse peekMemResponse(); // look at the next memory response
Vector#(TDiv#(CheriDataWidth,CapWidth),Bool) tags = replicate(True);
??? Now it seems (CheriDataWidth == CapWidth), and tags is 1-bit long?lookupRsp.first()
: // check this place if we will expand tag bits.Covered .ts: tags = unpack(ts[frame])
;if matches Unconvered : tags = unpack(0)
;
// cherilibs/trunk/TagController.bsv
// look at the next memory response
function CheriMemResponse peekMemResponse();
// look at the next response from the memory master interface
CheriMemResponse resp = mRsps.first;
// initialise new response to response coming from memory
CheriMemResponse newResp = resp;
// in case of read, need to construct the tags
if (resp.operation matches tagged Read .rop) begin
Vector#(TDiv#(CheriDataWidth,CapWidth),Bool) tags = replicate(True);
`ifndef NOTAG
// look at the tag lookup response
case (lookupRsp.first()) matches
tagged Covered .ts : tags = unpack(ts[frame]); // check this place if we will expand tag bits.
tagged Uncovered : tags = unpack(0);
endcase
`endif
// update the new response with appropriate tags
newResp.data.cap = tags;
end
return newResp;
endfunction
mReqs
, another at tagLookup.cache.request
mReqs
;mRsps
) and tag cache (lookupRsp
)mkConnection(l2CacheMemory, tagController.cache);
two sub-interfaces that are connected with the L2CacheMemory
:
defined in
// cherilibs/trunk/MasterSlave.bsv
interface Slave#(type req_t, type rsp_t);
interface CheckedPut#(req_t) request;
interface CheckedGet#(rsp_t) response;
endinterface
The interface declaration of CheckedPut/Get, similar to Get/Put in Bluespec, where Get is for others to get sth out, and Put for others to put sth in; CheckedPut/Get are defined in cherilibs/trunk/MasterSlave.bsv
Type of CheckedPut
: is for L2Cache to send in new request.
methods:
mReqs.enq(req);
tagLookup.cache.request.put(req);
Type of CheckedGet
: is for L2Cache to
methods:
resp
: CheriMemResponse resp = peekMemResponse();
mRsps.deq()
Connected to main memory interface:
MIPSTop.bsv (mkMIPSMemory theMem: interface memory = theMem.memory) ==>
Memory.bsv: (MIPSMemory Ifc: Master# memory = topMemIfc = tagControllerMemory) ==> this master interface
The memory interface transfers bit-convertable data type of CheriMemRequest
and CheriMemResponse
.
No distinguish to the request sent to the memory, but distinguish the response being send back from the memory. The bus will contain these bits being transferred to and from the memory.
Two sub-interfaces
declared in:
// cherilibs/trunk/MasterSlave.v
interface Master#(type req_t, type rsp_t);
interface CheckedGet#(req_t) request;
interface CheckedPut#(rsp_t) response;
endinterface
request
is an interface of CheckedGet#(
interface request = toCheckedGet(ff2fifof(mReqs));
Definition of toCheckedGet(fifo)
(also see MemTypes)
// cherilibs/trunk/MasterSlave.bsv
instance ToCheckedGet#(FIFOF#(data_t), data_t);
function CheckedGet#(data_t) toCheckedGet (FIFOF#(data_t) f) =
interface CheckedGet#(data_t);
method canGet = f.notEmpty;
method data_t peek if (f.notEmpty);
return f.first;
endmethod
method ActionValue#(data_t) get if (f.notEmpty);
f.deq;
return f.first;
endmethod
endinterface;
endinstance
Used to grab response from main memory. Responses of main memory will be found at fifo mRsps
.
// cherilibs/trunk/TagController.bsv
interface CheckedPut response;
method Bool canPut();
return (mRsps.notFull() && tagLookup.memory.response.canPut());
endmethod
method Action put(CheriMemResponse r) if (mRsps.notFull() && tagLookup.memory.response.canPut());
`ifdef NOTAG
mRsps.enq(r);
`else
MemReqType reqType = (r.masterID == mID) ? TagLookupReq : StdReq;
debug2("tagcontroller", $display("<time %0t TagController> response from memory: source=%x ", $time, reqType, fshow(r)));
if (reqType == TagLookupReq) begin
if (r.operation matches tagged Read.rop) tagLookup.memory.response.put(r);
debug2("tagcontroller", $display("<time %0t TagController> tag response", $time));
end else begin
mRsps.enq(r);
debug2("tagcontroller", $display("<time %0t TagController> memory response", $time));
end
`endif
endmethod
endinterface
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?