rules/functions processing different states:
- Init:
- doLookup condition !Init
- Idle:
- Slave cache.request.canPut(), put(),
- doLookup condition !Idle
- ReadTag, SetTag, ClearTag:
- used in doLookup
- set in Slave cache.request.put(req)
- FoldZeroes:
- used in doLookup
- set in doLookup,
rules triggered by getReq.send():
-> rule drainMemRsp: // done
rule doLookup:
-> ClearTags:
-> getOldTagsEntry() // done // do nothing if flat table.
-> getReq.send() // done
-> doTransition() // done
Slave:
-> request.put():
-> craftTagReadReq() // done
-> getTableAddr() // done
-> read -> nextState = ReadTag -> rule doLookup // done
-> write:
-> nextState = Idle -> rule doLookup // done
-> nextState = ClearTag -> rule doLookup // done
-> nextState = SetTag -> rule doLookup // done
-> set globals
- pendingCapNumber, used in rule doLookup, send this to functions getTableEntry(,,), getTableAddr(,), craftTagReadReq(,),craftTagWriteReq(,,,,), getNewTagsEntry(,),getOldTagsEntry(,,) // todo
- pendingTags, used in rule doLookup, send this to functions craftTagWriteReq(,,,,),getNewTagsEntry(,) // todo
- pendingCapEnable, used in rule doLookup, send this to functions craftTagWriteReq(,,,,),getNewTagsEntry(,,,,) // todo
-> doTransition()
-> tagCacheReq.enq(mr) // rule feedTagCache: forward from tagCacheReq to tagCache module // done
-> useNextRsp.enq(useRsp) // used in rule drainMemRsp: drain unused response; used in rule doLookup condition: only if not full, doLookup will be triggered.
-> state <= newState; // new state in effect.
-> response.get(): return lookupRsp.first // done.
Reference 1
Parameters:
ways = 4, keyBits is Indices - 1
, inFlight = 1
cacheID = 12,
writeMissBehavior = WriteAllocate,
responseBehavior = ResponseAll,
orderBehavior = InOrder,
whichCache = TCache,
memReqFifoSpace = zeroExtend(mReqs.remaining()),
memReqs = ff2fifof(mReqs),
memRsps = ff2fifof(mRsps)
// cherilibs/trunk/MultiLevelTagLookup.bsv
// interface types
///////////////////////////////////////////////////////////////////////////////
typedef Vector#(4,Bit#(CapsPerFlit)) LineTags;
typedef union tagged {
void Uncovered;
LineTags Covered;
} CheriTagResponse deriving (Bits,FShow);
// cherilibs/trunk/MultiLevelTagLookup.bsv
interface TagLookupIfc;
interface Slave#(CheriMemRequest, CheriTagResponse) cache;
interface Master#(CheriMemRequest, CheriMemResponse) memory;
`ifdef STATCOUNTERS
interface Get#(ModuleEvents) cacheEvents;
`endif
endinterface
same as in TagLookup.bsv
Node:
Leaf: the tags for every address is stored and can be accessed directly. Usually it will contain non-zero tags.
TableEntry deriving(Bits)
Tablelvl deriving(FShow)
TDepth: maximum table depth of 8;
Parameters/Instantiate
Interface TagLookupIfc
arguments:
ways = 4, keyBits is Indices - 1
, inFlight = 1
cacheID = 12,
writeMissBehavior = WriteAllocate,
responseBehavior = ResponseAll,
orderBehavior = InOrder,
whichCache = TCache,
memReqFifoSpace = zeroExtend(mReqs.remaining()),
memReqs = ff2fifof(mReqs),
memRsps = ff2fifof(mRsps)
State Registers:
Vectors:
lvlDesc
from 0 to tdepth - 1;FIFOs:
Submodules:
// cherilibs/trunk/MultiLevelTagLookup.bsv:
// tag cache CacheCore module
CacheCore#(4, TSub#(Indices, 1), 1) tagCache <- mkCacheCore(
12, WriteAllocate, RespondAll, InOrder, TCache,
zeroExtend(mReqs.remaining()), ff2fifof(mReqs), ff2fifof(mRsps));
// cherilibs/trunk/CacheCore.bsv:
module mkCacheCore#(Bit#(16) cacheId,
WriteMissBehaviour writeBehaviour,
ResponseBehaviour responseBehaviour,
OrderBehaviour orderBehaviour,
WhichCache whichCache,
// Must be > 5 or we can't issue reads with evictions!
// This means that a write-allocate cache must have >=5 capacity in the output fifo.
Bit#(10) memReqFifoSpace,
FIFOF#(CheriMemRequest) memReqs,
FIFOF#(CheriMemResponse) memRsps)
(CacheCore#(ways, keyBits, inFlight))
Overview: when table only have one level, it does no transformation to tags, and will return the input as output
Overview: put memory request in the fifo so it will be fed to tagCache, at the same time, put a bool switch useRsp
to flag whether the response will be ignored or not in rule doLookup
;
// file: cherilibs/trunk/MultiLevelTagLookup.bsv
function Action doTransition (
Maybe#(CheriMemRequest) mmr, // Contains one valid bit, and then request.
TDepth newDepth,
State newState,
Bool useRsp
) = action
debug2("taglookup",
$display("<time %0t TagLookup> table structure -", $time, fshow(tableDesc)
));
case (mmr) matches
tagged Valid .mr: begin
// send the tag cache request and increment the transaction number
debug2("taglookup",
$display("<time %0t TagLookup> sending lookup: ",
$time, fshow(mr)
));
tagCacheReq.enq(mr);
useNextRsp.enq(useRsp);
transNum <= transNum + 1;
end
endcase
// update lookup depth
currentDepth <= newDepth;
// do state transistion
state <= newState;
debug2("taglookup",
$display("<time %0t TagLookup> pendingCapNumber %x, currentDepth %d -> %d, state ",
$time, pendingCapNumber, currentDepth, newDepth, fshow(state), " -> ", fshow(newState)
));
endaction;
If a valid memory request, send the cache request and increment the transaction number
tagCacheReq.enq(mr);
// request will then be fed to tagCache.put(tagCacheReq.first())
useNextRsp.enq(useRsp);
// whether this request will have a response being parsed in rule doLookup. ???transNum <= transNum + 1;
Overview: lookup the multi level table
By default only one-level table is used. That is all nodes are leaf nodes.
TODO: where does the read response generated?
Check the current state
state
if ReadTag: check the table entry’s union type
Node
type entry: check Node
value for short cut (all 0 tags), or go to next level table entry by calling craftTagReadReq
//Leaf
type entry: enqueue lookupRsp
the leaf LineTags, where the first bit is the start of the requested capNumber’s flit’s tags.getReq.send()
// drain unused memory response (for unused write responses)doATransition = True
// will call doTransition() to put request to tagCache, the request can be invalid.if SetTag:
memRspReady
meaning the memory content to be written has been loaded from memory into the tagCache.getReq.send()
// drain unused memory response (for unused write responses)doATransition = True
// will call doTransition() to put request to tagCacheif ClearTag:
memRspReady
, meaning the memory is loaded into the cache already;getOldTagsEntry(dpth,capNumber,rspData)
// todogetReq.send()
// drain unused memory response (for unused write responses)doATransition = True
// will call doTransition() to put request to tagCacheif FoldZeroes …
doTransition(): put mem request to tagCache
interface Slave cache; two subinterfaces
Bool canPut() = (state == Idle); // only can receive request when Idle
Action put(CheriMemRequest req) if (state == Idle); // only when Idle
The put
method, in steps:
doTagLookup
= isCovered(req.addr);newPendingTags
: temporal store number of tags in a flit;newPendingCapEnable
: temporal store enable bits for each cap in a flit;rule doLookup
capEnable
to mask the cap bits to be written in a flit;capTags
from the request;andTags
= capEnable & newPendingTags
;capEnable
: set to IDLE
if all disabled, i.e. no write ops;andTags
: if all 0, mean all tag to write is 0, then set to ClearTag
state. // Lele: we might use similar solution to initialize color tags in scale.SetTag
pendingCapNumber <= capAddr.capNumber
; // the cap aligned addresspendingTags <= newPendingTags
; // tags to be written, 0 if read;pendingCapEnable <= newPendingCapEnable
; // enabled cap bits to be written, 0 if read.doTransition(tagged Valid mReq, rootLvl, nextState, True)
tagCacheReq.enq(mr);
useNextRsp.enq(useRsp);
state
to newState
The get
method, for tagController to get response from here. Returned struct is CheriTagResponse
, a tagged union, contain LineTags
tagged as Covered
as valid type; LineTags
is a vector of tags in 4*flits width (every bit is a tag)
The get()
steps:
!readReqs.first() || lookupRsp.notEmpty()
CheriTagResponse tr = tagged Covered lookupRsp.first();
interface Master memory; two subinterfaces
// Constant physical memory region
// file: cherilibs/trunk/MultiLevelTagLoopup.bsv
// static parameters
/////////////////////////////////////////////////////////////////////////////
// covered region include DRAM and BROM
// starting address of the covered region
CheriPhyAddr coveredStrtAddr = unpack(40'h00000000);
// ending address of the covered region
CheriPhyAddr coveredEndAddr = unpack(40'h40010000); // Lele: 1GB + 64KB. Why 64KB here?
// tagd table is at top of DRAM
// starting address of the tags table
CheriPhyAddr tagTabStrtAddr = unpack(40'h3F000000);
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?