2-byte aligned instruction memory to simplify compressed instruction
fetch.
This commit is contained in:
@@ -163,7 +163,7 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
|
||||
provisos (Bits #(Data, 64)); // this module assumes Data is 64-bit wide
|
||||
|
||||
Integer verbosity = 1;
|
||||
Integer verbosity = 2;
|
||||
|
||||
// mtimecmp
|
||||
Vector#(CoreNum, Reg#(Data)) mtimecmp <- replicateM(mkReg(0));
|
||||
@@ -191,10 +191,10 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
// offset of the requested inst within a Data
|
||||
Reg#(MemDataInstOffset) instSel <- mkRegU;
|
||||
// the current superscaler way being fetched
|
||||
Reg#(SupWaySel) fetchingWay <- mkRegU;
|
||||
Reg#(SupWayX2Sel) fetchingWay <- mkRegU;
|
||||
// the already fetched insts
|
||||
Vector#(TSub#(SupSize, 1),
|
||||
Reg#(Instruction)) fetchedInsts <- replicateM(mkRegU);
|
||||
Vector#(TSub#(SupSizeX2, 1),
|
||||
Reg#(Instruction16)) fetchedInsts <- replicateM(mkRegU);
|
||||
|
||||
// we need to wait for resp from cores when we need to change MTIP
|
||||
Reg#(Vector#(CoreNum, Bool)) waitMTIPCRs <- mkRegU;
|
||||
@@ -937,21 +937,33 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
$display (" ", fshow (req));
|
||||
end
|
||||
endrule
|
||||
|
||||
/*
|
||||
function Vector #(SupSizeX2, Maybe #(Instruction16)) prepareFinalInstResp(Vector #(SupSize, Maybe #(Instruction)) respBigInsts, Bit#(1) addr_bit_1);
|
||||
Vector #(SupSizeX2, Maybe #(Instruction16)) respSmallInsts = replicate (Invalid);
|
||||
for (Integer i = 0; i < valueOf (SupSize); i = i+1) begin
|
||||
if (respBigInsts[i] matches tagged Valid .inst) begin
|
||||
respSmallInsts[i*2] = tagged Valid (truncate(inst));
|
||||
respSmallInsts[(i*2) + 1] = tagged Valid (truncateLSB(inst));
|
||||
end
|
||||
end
|
||||
// This unconventional zero-extension of addr_bit_1 works around a type error in shiftOutFrom0.
|
||||
return shiftOutFrom0(Invalid, respSmallInsts, {4'b0, addr_bit_1});
|
||||
endfunction
|
||||
*/
|
||||
rule rl_mmio_from_fabric_ifetch_rsp (curReq matches tagged MMIO_Fabric_Adapter .addr
|
||||
&&& (state == WaitResp)
|
||||
&&& isInstFetch);
|
||||
MMIODataPRs dprs <- mmio_fabric_adapter_core_side.response.get;
|
||||
if (! dprs.valid) begin
|
||||
// Access fault
|
||||
Vector #(SupSize, Maybe #(Instruction)) resp = replicate (Invalid);
|
||||
for(Integer i = 0; i < valueof (SupSize); i = i+1) begin
|
||||
Vector #(SupSizeX2, Maybe #(Instruction16)) resp = replicate (Invalid);
|
||||
for(Integer i = 0; i < valueof (SupSizeX2); i = i+1) begin
|
||||
if (fromInteger (i) < fetchingWay)
|
||||
resp [i] = Valid (fetchedInsts [i]);
|
||||
else if (fromInteger (i) == fetchingWay)
|
||||
resp [i] = tagged Invalid;
|
||||
end
|
||||
cores[reqCore].pRs.enq (tagged InstFetch (resp));
|
||||
cores[reqCore].pRs.enq (tagged InstFetch resp);
|
||||
state <= SelectReq;
|
||||
|
||||
if (verbosity > 0) begin
|
||||
@@ -963,28 +975,26 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
else begin
|
||||
// No access fault
|
||||
|
||||
SupWaySel maxWay = 0;
|
||||
SupWayX2Sel maxWay = 0;
|
||||
if(reqFunc matches tagged Inst .w) begin
|
||||
maxWay = w;
|
||||
end
|
||||
|
||||
// View Data as a vector of instructions
|
||||
Vector#(MemDataSzInst, Instruction) instVec = unpack(pack(dprs.data.data));
|
||||
Vector#(MemDataSzInst, Instruction16) instVec = unpack(pack(dprs.data.data));
|
||||
// extract inst from resp data
|
||||
Instruction inst = instVec[instSel];
|
||||
Instruction16 inst = instVec[instSel];
|
||||
// check whether we are done or not
|
||||
if (fetchingWay >= maxWay) begin
|
||||
// all 0..maxWay insts are fetched; we can resp now
|
||||
Vector#(SupSize, Maybe#(Instruction)) resp = replicate(Invalid);
|
||||
for(Integer i = 0; i < valueof(SupSize); i = i+1) begin
|
||||
if(fromInteger(i) < fetchingWay) begin
|
||||
Vector#(SupSizeX2, Maybe#(Instruction16)) resp = replicate(Invalid);
|
||||
for(Integer i = 0; i < valueof(SupSizeX2); i = i+1) begin
|
||||
if(fromInteger(i) < fetchingWay)
|
||||
resp[i] = Valid (fetchedInsts[i]);
|
||||
end
|
||||
else if(fromInteger(i) == fetchingWay) begin
|
||||
else if(fromInteger(i) == fetchingWay)
|
||||
resp[i] = Valid (inst);
|
||||
end
|
||||
end
|
||||
cores[reqCore].pRs.enq (tagged InstFetch (resp));
|
||||
end
|
||||
cores[reqCore].pRs.enq (tagged InstFetch resp);
|
||||
state <= SelectReq;
|
||||
|
||||
if (verbosity > 0) begin
|
||||
|
||||
@@ -97,7 +97,7 @@ typedef TDiv#(MemDataSz, 8) MemDataSzBytes;
|
||||
typedef TLog#(MemDataSzBytes) LgMemDataSzBytes;
|
||||
typedef Bit#(LgMemDataSzBytes) MemDataBytesOffset;
|
||||
|
||||
typedef TDiv#(InstSz, 8) InstSzBytes;
|
||||
typedef TDiv#(Inst16_Sz, 8) InstSzBytes;
|
||||
typedef TLog#(InstSzBytes) LgInstSzBytes;
|
||||
|
||||
// 64B cache line -- XXX same with parameters in CacheUtils.bsv
|
||||
@@ -230,7 +230,7 @@ typedef struct {
|
||||
// I$ req/resp
|
||||
interface InstServer#(numeric type supSz);
|
||||
interface Put#(Addr) req;
|
||||
interface Get#(Vector#(supSz, Maybe#(Instruction))) resp;
|
||||
interface Get#(Vector#(TMul#(supSz,2), Maybe#(Instruction16))) resp;
|
||||
`ifdef DEBUG_ICACHE
|
||||
interface Get#(DebugICacheResp) done; // the id and cache line of the I$ req that truly performs
|
||||
`endif
|
||||
|
||||
@@ -124,7 +124,8 @@ module mkIBank#(
|
||||
Alias#(cRqSlotT, ICRqSlot#(wayT, tagT)), // cRq MSHR slot
|
||||
Alias#(l1CmdT, L1Cmd#(indexT, cRqIdxT, pRqIdxT)),
|
||||
Alias#(pipeOutT, PipeOut#(wayT, tagT, Msi, void, cacheOwnerT, void, RandRepInfo, Line, l1CmdT)),
|
||||
Alias#(resultT, Vector#(supSz, Maybe#(Instruction))),
|
||||
Mul#(2, supSz, supSzX2),
|
||||
Alias#(resultT, Vector#(supSzX2, Maybe#(Instruction16))),
|
||||
// requirements
|
||||
FShow#(pipeOutT),
|
||||
Add#(tagSz, a__, AddrSz),
|
||||
@@ -156,13 +157,13 @@ module mkIBank#(
|
||||
|
||||
// index Q to order all in flight cRq for in-order resp
|
||||
FIFO#(cRqIdxT) cRqIndexQ <- mkSizedFIFO(valueof(cRqNum));
|
||||
|
||||
|
||||
`ifdef DEBUG_ICACHE
|
||||
// id for each cRq, incremented when each new req comes
|
||||
Reg#(Bit#(64)) cRqId <- mkReg(0);
|
||||
// FIFO to signal the id of cRq that is performed
|
||||
// FIFO has 0 cycle latency to match L1 D$ resp latency
|
||||
Fifo#(1, DebugICacheResp) cRqDoneQ <- mkBypassFifo;
|
||||
Fifo#(1, DebugICacheResp) cRqDoneQ <- mkBypassFifo;
|
||||
`endif
|
||||
|
||||
// security flush
|
||||
@@ -248,8 +249,8 @@ module mkIBank#(
|
||||
mshrIdx: n
|
||||
}));
|
||||
if (verbose)
|
||||
$display("%t I %m pRqTransfer: ", $time,
|
||||
fshow(n), " ; ",
|
||||
$display("%t I %m pRqTransfer: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(req)
|
||||
);
|
||||
endrule
|
||||
@@ -268,7 +269,7 @@ module mkIBank#(
|
||||
$display("%t I %m pRsTransfer: ", $time, fshow(resp));
|
||||
doAssert(resp.toState == S && isValid(resp.data), "I$ must upgrade to S with data");
|
||||
endrule
|
||||
|
||||
|
||||
`ifdef SECURITY
|
||||
// start flush when cRq MSHR is empty
|
||||
rule startFlushReq(!flushDone && !flushReqStart && cRqMshr.emptyForFlush);
|
||||
@@ -326,8 +327,8 @@ module mkIBank#(
|
||||
// (prevent parent resp from coming to release MSHR entry before replace resp is sent)
|
||||
rqToPIndexQ_sendRsToP.enq(n);
|
||||
if (verbose)
|
||||
$display("%t I %m sendRsToP: ", $time,
|
||||
fshow(rsToPIndexQ.first)," ; ",
|
||||
$display("%t I %m sendRsToP: ", $time,
|
||||
fshow(rsToPIndexQ.first)," ; ",
|
||||
fshow(req), " ; ",
|
||||
fshow(slot), " ; ",
|
||||
fshow(resp)
|
||||
@@ -347,9 +348,9 @@ module mkIBank#(
|
||||
rsToPQ.enq(resp);
|
||||
pRqMshr.sendRsToP_pRq.releaseEntry(n); // mshr entry released
|
||||
if (verbose)
|
||||
$display("%t I %m sendRsToP: ", $time,
|
||||
fshow(rsToPIndexQ.first), " ; ",
|
||||
fshow(req), " ; ",
|
||||
$display("%t I %m sendRsToP: ", $time,
|
||||
fshow(rsToPIndexQ.first), " ; ",
|
||||
fshow(req), " ; ",
|
||||
fshow(resp)
|
||||
);
|
||||
doAssert(req.toState == I, "I$ only has downgrade req to I");
|
||||
@@ -370,10 +371,10 @@ module mkIBank#(
|
||||
};
|
||||
rqToPQ.enq(cRqToP);
|
||||
if (verbose)
|
||||
$display("%t I %m sendRqToP: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(req), " ; ",
|
||||
fshow(slot), " ; ",
|
||||
$display("%t I %m sendRqToP: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(req), " ; ",
|
||||
fshow(slot), " ; ",
|
||||
fshow(cRqToP)
|
||||
);
|
||||
`ifdef PERF_COUNT
|
||||
@@ -404,14 +405,14 @@ module mkIBank#(
|
||||
|
||||
// function to get superscaler inst read result
|
||||
function resultT readInst(Line line, Addr addr);
|
||||
Vector#(LineSzInst, Instruction) instVec = unpack(pack(line.data));
|
||||
Vector#(LineSzInst, Instruction16) instVec = unpack(pack(line.data));
|
||||
// the start offset for reading inst
|
||||
LineInstOffset startSel = getLineInstOffset(addr);
|
||||
// calculate the maximum inst count that could be read from line
|
||||
LineInstOffset maxCntMinusOne = maxBound - startSel;
|
||||
// read inst superscalaer
|
||||
resultT val = ?;
|
||||
for(Integer i = 0; i < valueof(supSz); i = i+1) begin
|
||||
for(Integer i = 0; i < valueof(supSzX2); i = i+1) begin
|
||||
if(fromInteger(i) <= maxCntMinusOne) begin
|
||||
LineInstOffset sel = startSel + fromInteger(i);
|
||||
val[i] = Valid (instVec[sel]);
|
||||
@@ -474,7 +475,7 @@ module mkIBank#(
|
||||
procRqT procRq = pipeOutCRq;
|
||||
if (verbose)
|
||||
$display("%t I %m pipelineResp: cRq: ", $time, fshow(n), " ; ", fshow(procRq));
|
||||
|
||||
|
||||
// find end of dependency chain
|
||||
Maybe#(cRqIdxT) cRqEOC = cRqMshr.pipelineResp.searchEndOfChain(procRq.addr);
|
||||
|
||||
@@ -487,7 +488,7 @@ module mkIBank#(
|
||||
// and this func is only called when cs < S (otherwise will hit)
|
||||
// because L1 has no children to wait for
|
||||
doAssert(!cSlot.waitP && ram.info.cs == I, "waitP must be false and cs must be I");
|
||||
// Thus we must send req to parent
|
||||
// Thus we must send req to parent
|
||||
// XXX first send to a temp indexQ to avoid conflict, then merge to rqToPIndexQ later
|
||||
rqToPIndexQ_pipelineResp.enq(n);
|
||||
// update mshr
|
||||
@@ -537,7 +538,7 @@ module mkIBank#(
|
||||
rsToPIndexQ.enq(CRq (n));
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
|
||||
// function to set cRq to Depend, and make no further change to cache
|
||||
function Action cRqSetDepNoCacheChange;
|
||||
action
|
||||
@@ -786,7 +787,7 @@ module mkIBank#(
|
||||
};
|
||||
endmethod
|
||||
endinterface
|
||||
|
||||
|
||||
interface pRqStuck = pRqMshr.stuck;
|
||||
|
||||
`ifdef SECURITY
|
||||
@@ -886,4 +887,3 @@ endmodule
|
||||
// unsafe version: all reads read the original reg value, except sendRsToC, which should bypass from pipelineResp
|
||||
// all writes are cononicalized. NOTE: writes of sendRsToC should be after pipelineResp
|
||||
// we maintain the logical ordering in safe version
|
||||
|
||||
|
||||
@@ -122,7 +122,8 @@ module mkSelfInvIBank#(
|
||||
Alias#(cRqSlotT, ICRqSlot#(wayT, tagT)), // cRq MSHR slot
|
||||
Alias#(iCmdT, SelfInvICmd#(cRqIdxT)),
|
||||
Alias#(pipeOutT, PipeOut#(wayT, tagT, Msi, void, cacheOwnerT, otherT, RandRepInfo, Line, iCmdT)),
|
||||
Alias#(resultT, Vector#(supSz, Maybe#(Instruction))),
|
||||
Mul#(2, supSz, supSzX2),
|
||||
Alias#(resultT, Vector#(supSzX2, Maybe#(Instruction16))),
|
||||
// requirements
|
||||
FShow#(pipeOutT),
|
||||
Add#(tagSz, a__, AddrSz),
|
||||
@@ -146,7 +147,7 @@ module mkSelfInvIBank#(
|
||||
|
||||
// index Q to order all in flight cRq for in-order resp
|
||||
FIFO#(cRqIdxT) cRqIndexQ <- mkSizedFIFO(valueof(cRqNum));
|
||||
|
||||
|
||||
// Reconcile states
|
||||
Reg#(Bool) needReconcile <- mkReg(False);
|
||||
Reg#(Bool) waitReconcileDone <- mkReg(False);
|
||||
@@ -156,7 +157,7 @@ module mkSelfInvIBank#(
|
||||
Reg#(Bit#(64)) cRqId <- mkReg(0);
|
||||
// FIFO to signal the id of cRq that is performed
|
||||
// FIFO has 0 cycle latency to match L1 D$ resp latency
|
||||
Fifo#(1, DebugICacheResp) cRqDoneQ <- mkBypassFifo;
|
||||
Fifo#(1, DebugICacheResp) cRqDoneQ <- mkBypassFifo;
|
||||
`endif
|
||||
|
||||
`ifdef PERF_COUNT
|
||||
@@ -244,7 +245,7 @@ module mkSelfInvIBank#(
|
||||
$display("%t I %m pRsTransfer: ", $time, fshow(resp));
|
||||
doAssert(resp.toState == S && isValid(resp.data), "I$ must upgrade to S with data");
|
||||
endrule
|
||||
|
||||
|
||||
rule sendRqToP;
|
||||
rqToPIndexQ.deq;
|
||||
cRqIdxT n = rqToPIndexQ.first;
|
||||
@@ -260,10 +261,10 @@ module mkSelfInvIBank#(
|
||||
};
|
||||
rqToPQ.enq(cRqToP);
|
||||
if (verbose)
|
||||
$display("%t I %m sendRqToP: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(req), " ; ",
|
||||
fshow(slot), " ; ",
|
||||
$display("%t I %m sendRqToP: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(req), " ; ",
|
||||
fshow(slot), " ; ",
|
||||
fshow(cRqToP)
|
||||
);
|
||||
`ifdef PERF_COUNT
|
||||
@@ -294,14 +295,14 @@ module mkSelfInvIBank#(
|
||||
|
||||
// function to get superscaler inst read result
|
||||
function resultT readInst(Line line, Addr addr);
|
||||
Vector#(LineSzInst, Instruction) instVec = unpack(pack(line.data));
|
||||
Vector#(LineSzInst, Instruction16) instVec = unpack(pack(line.data));
|
||||
// the start offset for reading inst
|
||||
LineInstOffset startSel = getLineInstOffset(addr);
|
||||
// calculate the maximum inst count that could be read from line
|
||||
LineInstOffset maxCntMinusOne = maxBound - startSel;
|
||||
// read inst superscalaer
|
||||
resultT val = ?;
|
||||
for(Integer i = 0; i < valueof(supSz); i = i+1) begin
|
||||
for(Integer i = 0; i < valueof(supSzX2); i = i+1) begin
|
||||
if(fromInteger(i) <= maxCntMinusOne) begin
|
||||
LineInstOffset sel = startSel + fromInteger(i);
|
||||
val[i] = Valid (instVec[sel]);
|
||||
@@ -364,7 +365,7 @@ module mkSelfInvIBank#(
|
||||
procRqT procRq = pipeOutCRq;
|
||||
if (verbose)
|
||||
$display("%t I %m pipelineResp: cRq: ", $time, fshow(n), " ; ", fshow(procRq));
|
||||
|
||||
|
||||
// find end of dependency chain
|
||||
Maybe#(cRqIdxT) cRqEOC = cRqMshr.pipelineResp.searchEndOfChain(procRq.addr);
|
||||
|
||||
@@ -380,7 +381,7 @@ module mkSelfInvIBank#(
|
||||
doAssert(ram.info.cs <= S, "no exclusive in I$");
|
||||
// This cannot be a hit
|
||||
doAssert(ram.info.cs == I || ram.info.tag != getTag(procRq.addr), "cannot hit");
|
||||
// Thus we must send req to parent
|
||||
// Thus we must send req to parent
|
||||
rqToPIndexQ.enq(n);
|
||||
// update mshr
|
||||
cRqMshr.pipelineResp.setStateSlot(n, WaitSt, ICRqSlot {
|
||||
@@ -551,7 +552,7 @@ module mkSelfInvIBank#(
|
||||
};
|
||||
endmethod
|
||||
endinterface
|
||||
|
||||
|
||||
interface pRqStuck = nullGet;
|
||||
|
||||
`ifdef SECURITY
|
||||
@@ -659,4 +660,3 @@ endmodule
|
||||
// unsafe version: all reads read the original reg value, except sendRsToC, which should bypass from pipelineResp
|
||||
// all writes are cononicalized. NOTE: writes of sendRsToC should be after pipelineResp
|
||||
// we maintain the logical ordering in safe version
|
||||
|
||||
|
||||
@@ -262,7 +262,6 @@ endfunction
|
||||
|
||||
// Fetching instructions from mem returns up to superscalar-size 32b parcels, = twice that many 16b parcels
|
||||
|
||||
typedef TMul #(SupSize, 2) SupSizeX2;
|
||||
typedef Bit #(TLog #(TAdd #(SupSizeX2, 1))) SupCntX2;
|
||||
|
||||
// Merging up to SupSize-1 pending instructions with up to SupSizeX2 decoded
|
||||
@@ -311,27 +310,6 @@ instance DefaultValue #(Inst_Item);
|
||||
};
|
||||
endinstance
|
||||
|
||||
// Input 'inst_d' was fetched from memory: up to superscalar-size sequence of 32b parcels.
|
||||
// Convert this into 16b parcels, prior to re-parsing for possible mix of 32b and 16b instructions.
|
||||
// This is a pure function; ActionValue is used only to allow $displays for debugging.
|
||||
|
||||
function ActionValue #(Tuple2 #(SupCntX2,
|
||||
Vector #(SupSizeX2, Bit #(16))))
|
||||
fav_inst_d_to_x16s (Vector #(SupSize, Maybe #(Instruction)) inst_d);
|
||||
actionvalue
|
||||
// Convert inst_d into 16-bit parcels (v_x16)
|
||||
function Bit #(32) fv_x32 (Integer i) = fromMaybe (0, inst_d [i]);
|
||||
Vector #(SupSize, Bit #(32)) v_x32 = genWith (fv_x32);
|
||||
Vector #(SupSizeX2, Bit #(16)) v_x16 = unpack (pack (v_x32));
|
||||
|
||||
// Count the number of 16b parcels (n_x16s)
|
||||
function Bit #(1) fv_valid (Maybe #(Instruction) inst) = (isValid (inst) ? 1 : 0);
|
||||
SupCntX2 n_x16s = 2 * extend (pack (countOnes (pack (map (fv_valid, inst_d)))));
|
||||
|
||||
return tuple2 (n_x16s, v_x16);
|
||||
endactionvalue
|
||||
endfunction
|
||||
|
||||
`ifdef RVFI_DII
|
||||
typedef Tuple4 #(CapMem, Dii_Parcel_Id, Bit #(16), Bool) Straddle;
|
||||
function Straddle fv_straddle (CapMem pc, Dii_Parcel_Id dii_pid, Bit #(16) lsbs, Bool mispred);
|
||||
@@ -370,8 +348,7 @@ function ActionValue #(Tuple4 #(SupCntX2,
|
||||
orig_inst: 0,
|
||||
inst: 0});
|
||||
MStraddle next_straddle = tagged Invalid;
|
||||
// Start parse at parcel 0/1 depending on pc lsbs.
|
||||
SupCntX2 j = (getAddr(pc_start) [1:0] == 2'b00 ? 0 : 1);
|
||||
SupCntX2 j = 0;
|
||||
Addr pc = getAddr(pc_start);
|
||||
`ifdef RVFI_DII
|
||||
Dii_Parcel_Id dii_pid = dii_pid_start;
|
||||
@@ -557,7 +534,7 @@ module mkFetchStage(FetchStage);
|
||||
RvfiDiiServer dii <- mkRvfiDiiServer;
|
||||
`endif
|
||||
Server#(Addr, TlbResp) tlb_server = iTlb.to_proc;
|
||||
Server#(Addr, Vector#(SupSize, Maybe#(Instruction))) mem_server = iMem.to_proc;
|
||||
Server#(Addr, Vector#(SupSizeX2, Maybe#(Instruction16))) mem_server = iMem.to_proc;
|
||||
|
||||
// performance counters
|
||||
Fifo#(1, DecStagePerfType) perfReqQ <- mkCFFifo; // perf req FIFO
|
||||
@@ -592,32 +569,6 @@ module mkFetchStage(FetchStage);
|
||||
Reg#(Addr) lastImemReq <- mkConfigReg(0);
|
||||
`endif
|
||||
|
||||
// Predict the next fetch-PC based only on current PC (without
|
||||
// knowing the instructions).
|
||||
|
||||
function ActionValue #(Tuple2 #(Integer, Maybe #(CapMem))) fav_pred_next_pc (CapMem pc);
|
||||
actionvalue
|
||||
CapMem prev_PC = pc;
|
||||
Maybe #(CapMem) pred_next_pc = nextAddrPred.predPc (prev_PC);
|
||||
Integer posLastSupX2 = 0;
|
||||
Bool done = False;
|
||||
for (Integer i = 0; i < valueOf (SupSizeX2); i = i + 1) begin
|
||||
if (! done) begin
|
||||
Bool isLastX2 = (i == (valueOf (SupSizeX2) - 1)) || ((getAddr(pc)[1:0] != 2'b00) && (i == (valueOf (SupSizeX2) - 2)));
|
||||
Bool lastInstInCacheLine = (getLineInstOffset (getAddr(prev_PC)) == maxBound) && (getAddr(prev_PC)[1:0] != 2'b00);
|
||||
Bool isJump = isValid(pred_next_pc);
|
||||
done = isLastX2 || lastInstInCacheLine || isJump;
|
||||
posLastSupX2 = i;
|
||||
if (! done) begin
|
||||
prev_PC = addPc(prev_PC, 2);
|
||||
pred_next_pc = nextAddrPred.predPc (prev_PC);
|
||||
end
|
||||
end
|
||||
end
|
||||
return tuple2 (posLastSupX2, pred_next_pc);
|
||||
endactionvalue
|
||||
endfunction
|
||||
|
||||
// We don't send req to TLB when waiting for redirect or TLB flush. Since
|
||||
// there is no FIFO between doFetch1 and TLB, when OOO commit stage wait
|
||||
// TLB idle to change VM CSR / signal flush TLB, there is no wrong path
|
||||
@@ -625,32 +576,27 @@ module mkFetchStage(FetchStage);
|
||||
rule doFetch1(started && !waitForRedirect && !waitForFlush);
|
||||
let pc = pc_reg[pc_fetch1_port];
|
||||
|
||||
/* ORIGINAL CODE
|
||||
// Chain of prediction for the next instructions
|
||||
// We need a BTB with a register file with enough ports!
|
||||
// Instead of cascading predictions, we can always feed pc+4*i into
|
||||
// predictor, because we will break superscaler fetch if nextpc != pc+4
|
||||
Vector#(SupSize, Addr) pred_future_pc;
|
||||
for(Integer i = 0; i < valueof(SupSize); i = i+1) begin
|
||||
pred_future_pc[i] = nextAddrPred.predPc(pc + fromInteger(4 * i));
|
||||
Vector#(SupSizeX2, Maybe#(CapMem)) pred_future_pc;
|
||||
for(Integer i = 0; i < valueof(SupSizeX2); i = i+1) begin
|
||||
pred_future_pc[i] = nextAddrPred.predPc(addPc(pc, fromInteger(2 * i)));
|
||||
end
|
||||
|
||||
// Next pc is the first nextPc that breaks the chain of pc+4 or
|
||||
// that is at the end of a cacheline.
|
||||
Vector#(SupSize,Integer) indexes = genVector;
|
||||
function Bool findNextPc(Addr pc, Integer i);
|
||||
Bool notLastInst = getLineInstOffset(pc + fromInteger(4*i)) != maxBound;
|
||||
Bool noJump = pred_future_pc[i] == pc + fromInteger(4*(i+1));
|
||||
Vector#(SupSizeX2,Integer) indexes = genVector;
|
||||
function Bool findNextPc(CapMem pc, Integer i);
|
||||
Bool notLastInst = getLineInstOffset(getAddr(pc) + fromInteger(2*i)) != maxBound;
|
||||
Bool noJump = !isValid(pred_future_pc[i]);
|
||||
return (!(notLastInst && noJump));
|
||||
endfunction
|
||||
Integer posLastSup = fromMaybe(valueof(SupSize) - 1, find(findNextPc(pc), indexes));
|
||||
Addr pred_next_pc = pred_future_pc[posLastSup];
|
||||
pc_reg[pc_fetch1_port] <= pred_next_pc;
|
||||
*/
|
||||
Bit#(TLog#(SupSizeX2)) posLastSupX2 = fromInteger(fromMaybe(valueof(SupSizeX2) - 1, find(findNextPc(pc), indexes)));
|
||||
Maybe#(CapMem) pred_next_pc = pred_future_pc[posLastSupX2];
|
||||
|
||||
match { .posLastSupX2, .pred_next_pc } <- fav_pred_next_pc (pc);
|
||||
|
||||
let next_fetch_pc = fromMaybe(addPc(pc, 2 * (fromInteger(posLastSupX2) + 1)), pred_next_pc);
|
||||
let next_fetch_pc = fromMaybe(addPc(pc, 2 * (zeroExtend(posLastSupX2) + 1)), pred_next_pc);
|
||||
pc_reg[pc_fetch1_port] <= next_fetch_pc;
|
||||
|
||||
`ifdef RVFI_DII
|
||||
@@ -659,9 +605,7 @@ module mkFetchStage(FetchStage);
|
||||
`endif
|
||||
|
||||
// Send TLB request.
|
||||
// Mask to 32-bit alignment, even if 'C' is supported (where we may discard first 2 bytes)
|
||||
Addr align32b_mask = 'h3;
|
||||
tlb_server.request.put (getAddr(pc) & (~ align32b_mask));
|
||||
tlb_server.request.put (getAddr(pc));
|
||||
`ifdef DEBUG_WEDGE
|
||||
lastItlbReq <= getAddr(pc) & (~ align32b_mask);
|
||||
`endif
|
||||
@@ -675,10 +619,9 @@ module mkFetchStage(FetchStage);
|
||||
fetch3_epoch: fetch3_epoch,
|
||||
decode_epoch: decode_epoch[0],
|
||||
main_epoch: f_main_epoch};
|
||||
let nbSupX2 = fromInteger(posLastSupX2) + (getAddr(pc)[1:0] == 2'b00 ? 0 : 1);
|
||||
|
||||
f12f2.enq(tuple2(nbSupX2,out));
|
||||
if (verbose) $display("Fetch1: ", fshow(out), " posLastSupX2: %d", posLastSupX2, " nbSupX2: %d", nbSupX2);
|
||||
f12f2.enq(tuple2(posLastSupX2,out));
|
||||
if (verbose) $display("Fetch1: ", fshow(out), " posLastSupX2: %d", posLastSupX2);
|
||||
endrule
|
||||
|
||||
rule doFetch2;
|
||||
@@ -696,7 +639,7 @@ module mkFetchStage(FetchStage);
|
||||
// doFetch1 for the real MMIO and ICache require 32-bit, so make
|
||||
// DII look like that by decrementing pid if PC is "odd"; this
|
||||
// extra parcel on the front will be discarded by fav_parse_insts.
|
||||
dii.fromDii.request.put(in.dii_pid - (getAddr(in.pc)[1:0] == 2'b00 ? 0 : 1));
|
||||
dii.fromDii.request.put(in.dii_pid);
|
||||
end
|
||||
`else
|
||||
if (!isValid(cause)) begin
|
||||
@@ -713,8 +656,7 @@ module mkFetchStage(FetchStage);
|
||||
// cache line size, so all nbSup+1 insts can be fetched
|
||||
// from boot rom. It won't happen that insts fetched from
|
||||
// boot rom is less than requested.
|
||||
Bit #(TLog #(SupSize)) nbSup = truncate(nbSupX2 >> 1);
|
||||
mmio.bootRomReq(phys_pc, nbSup);
|
||||
mmio.bootRomReq(phys_pc, nbSupX2);
|
||||
access_mmio = True;
|
||||
`ifdef DEBUG_WEDGE
|
||||
lastImemReq <= phys_pc;
|
||||
@@ -821,7 +763,7 @@ module mkFetchStage(FetchStage);
|
||||
// In case of exception, we still need to process at least inst_data[0]
|
||||
// (it will be turned to an exception later), so inst_data[0] must be
|
||||
// valid.
|
||||
Vector#(SupSize,Maybe#(Instruction)) inst_d = replicate(tagged Valid (0));
|
||||
Vector#(SupSizeX2,Maybe#(Instruction16)) inst_d = replicate(tagged Valid (0));
|
||||
if (drop_f22f3 || parse_f22f3) begin
|
||||
f22f3.deq();
|
||||
if (!isValid(fetch3In.cause)) begin
|
||||
@@ -829,8 +771,8 @@ module mkFetchStage(FetchStage);
|
||||
inst_d <- dii.fromDii.response.get;
|
||||
`else
|
||||
if(fetch3In.access_mmio) begin
|
||||
if(verbose) $display("get answer from MMIO 0x%0x", getAddr(fetch3In.pc));
|
||||
inst_d <- mmio.bootRomResp;
|
||||
if(verbose) $display("get answer from MMIO 0x%0x", getAddr(fetch3In.pc), " ", fshow(inst_d));
|
||||
end
|
||||
else begin
|
||||
if(verbose) $display("get answer from memory 0x%0x", getAddr(fetch3In.pc));
|
||||
@@ -855,17 +797,9 @@ module mkFetchStage(FetchStage);
|
||||
end
|
||||
end
|
||||
else if (parse_f22f3) begin
|
||||
// Re-interpret fetched 32b parcels (inst_d) as 16b parcels
|
||||
let { n_x16s, v_x16 } <- fav_inst_d_to_x16s (inst_d);
|
||||
// Cap n_x16s, as otherwise we misattribute the bundle's PC
|
||||
// prediction to a later instruction and erroneously think we
|
||||
// took a branch miss. This condition is hit because the cache
|
||||
// interface uses aligned 32b parcels and thus we can end up with
|
||||
// an extra 16b parcel after the window we want. Note that
|
||||
// nbSupX2In will still include the first 16b parcel even if our PC
|
||||
// is misaligned, but this will be discarded by fav_parse_insts.
|
||||
if (n_x16s > extend(nbSupX2In) + 1)
|
||||
n_x16s = extend(nbSupX2In) + 1;
|
||||
Vector#(SupSizeX2,Instruction16) v_x16;
|
||||
for (Integer i=0; i<valueOf(SupSizeX2); i=i+1) v_x16[i] = fromMaybe(?,inst_d[i]);
|
||||
SupCntX2 n_x16s = min(zeroExtend(nbSupX2In)+1, pack(countIf(isValid,inst_d)));
|
||||
|
||||
// Parse v_x16 into 32-bit and 16-bit instructions
|
||||
CapMem pred_next_pc;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
//
|
||||
// This work was supported by NCSC programme grant 4212611/RFA 15971 ("SafeBet").
|
||||
//-
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
@@ -21,10 +21,10 @@
|
||||
// modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
@@ -72,6 +72,7 @@ export DCoCache(..);
|
||||
export mkDCoCache;
|
||||
|
||||
export ISupSz;
|
||||
export ISupSzX2;
|
||||
export L1ICRqStuck(..);
|
||||
export L1IPRqStuck(..);
|
||||
export ICoCache(..);
|
||||
@@ -293,10 +294,11 @@ typedef Bit#(TLog#(ICRqNum)) ICRqMshrIdx;
|
||||
typedef Bit#(TLog#(IPRqNum)) IPRqMshrIdx;
|
||||
|
||||
typedef SupSize ISupSz;
|
||||
typedef TMul#(SupSize, 2) ISupSzX2;
|
||||
|
||||
(* synthesize *)
|
||||
module mkICRqMshrWrapper(
|
||||
ICRqMshr#(ICRqNum, L1Way, ITag, ProcRqToI, Vector#(ISupSz, Maybe#(Instruction)))
|
||||
ICRqMshr#(ICRqNum, L1Way, ITag, ProcRqToI, Vector#(ISupSzX2, Maybe#(Instruction16)))
|
||||
);
|
||||
function Addr getAddrFromReq(ProcRqToI r);
|
||||
return r.addr;
|
||||
@@ -360,7 +362,7 @@ typedef IPRqStuck L1IPRqStuck;
|
||||
|
||||
|
||||
interface ICoCache;
|
||||
interface Server#(Addr, Vector#(ISupSz, Maybe#(Instruction))) to_proc;
|
||||
interface Server#(Addr, Vector#(ISupSzX2, Maybe#(Instruction16))) to_proc;
|
||||
method Action flush;
|
||||
method Bool flush_done;
|
||||
interface Perf#(L1IPerfType) perf;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//
|
||||
// This work was supported by NCSC programme grant 4212611/RFA 15971 ("SafeBet").
|
||||
//-
|
||||
//
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without
|
||||
@@ -22,10 +22,10 @@
|
||||
// modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
// of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
@@ -47,8 +47,8 @@ import MMIOAddrs::*;
|
||||
import SoC_Map :: *; // Bluespec setup
|
||||
|
||||
interface MMIOInstToCore;
|
||||
interface FifoDeq#(Tuple2#(Addr, SupWaySel)) instReq;
|
||||
interface FifoEnq#(Vector#(SupSize, Maybe#(Instruction))) instResp;
|
||||
interface FifoDeq#(Tuple2#(Addr, SupWayX2Sel)) instReq;
|
||||
interface FifoEnq#(Vector#(SupSizeX2, Maybe#(Instruction16))) instResp;
|
||||
method Action setHtifAddrs(Addr toHost, Addr fromHost);
|
||||
endinterface
|
||||
|
||||
@@ -63,10 +63,10 @@ interface MMIOInst;
|
||||
method InstFetchTarget getFetchTarget(Addr phyPc);
|
||||
// When req boot rom, need to specify the number of instructions to fetch,
|
||||
// i.e., maxWay + 1
|
||||
method Action bootRomReq(Addr phyPc, SupWaySel maxWay);
|
||||
method Action bootRomReq(Addr phyPc, SupWayX2Sel maxWay);
|
||||
// The return type is same as I$. An entry is Invalid if it is an access
|
||||
// fault or not requested before.
|
||||
method ActionValue#(Vector#(SupSize, Maybe#(Instruction))) bootRomResp;
|
||||
method ActionValue#(Vector#(SupSizeX2, Maybe#(Instruction16))) bootRomResp;
|
||||
interface MMIOInstToCore toCore;
|
||||
endinterface
|
||||
|
||||
@@ -80,8 +80,8 @@ module mkMMIOInst(MMIOInst);
|
||||
Reg#(DataAlignedAddr) fromHostAddr <- mkConfigReg(0);
|
||||
// MMIO requests are handled in a very slow manner at platform, so no need
|
||||
// to use large FIFO here
|
||||
Fifo#(1, Tuple2#(Addr, SupWaySel)) reqQ <- mkCFFifo;
|
||||
Fifo#(1, Vector#(SupSize, Maybe#(Instruction))) respQ <- mkCFFifo;
|
||||
Fifo#(1, Tuple2#(Addr, SupWayX2Sel)) reqQ <- mkCFFifo;
|
||||
Fifo#(1, Vector#(SupSizeX2, Maybe#(Instruction16))) respQ <- mkCFFifo;
|
||||
// To prevent inst fetch requests from clogging the network, we limit to at
|
||||
// most 1 pending req. The resp for the pending req will be buffered in
|
||||
// respQ, no affecting other MMIO accesses.
|
||||
@@ -103,12 +103,12 @@ module mkMMIOInst(MMIOInst);
|
||||
end
|
||||
endmethod
|
||||
|
||||
method Action bootRomReq(Addr phyPc, SupWaySel maxWay);
|
||||
method Action bootRomReq(Addr phyPc, SupWayX2Sel maxWay);
|
||||
reqQ.enq(tuple2(phyPc, maxWay));
|
||||
pendQ.enq(?);
|
||||
endmethod
|
||||
|
||||
method ActionValue#(Vector#(SupSize, Maybe#(Instruction))) bootRomResp;
|
||||
method ActionValue#(Vector#(SupSizeX2, Maybe#(Instruction16))) bootRomResp;
|
||||
pendQ.deq;
|
||||
respQ.deq;
|
||||
return respQ.first;
|
||||
|
||||
@@ -58,6 +58,8 @@ typedef Bit#(TLog#(CoreNum)) CoreId;
|
||||
typedef `sizeSup SupSize;
|
||||
typedef Bit#(TLog#(SupSize)) SupWaySel;
|
||||
typedef Bit#(TLog#(TAdd#(SupSize, 1))) SupCnt;
|
||||
typedef TMul#(SupSize, 2) SupSizeX2;
|
||||
typedef Bit#(TLog#(SupSizeX2)) SupWayX2Sel;
|
||||
|
||||
typedef `NUM_EPOCHS NumEpochs;
|
||||
typedef Bit#(TLog#(NumEpochs)) Epoch;
|
||||
@@ -674,7 +676,7 @@ typedef struct {
|
||||
// MMIO
|
||||
typedef union tagged {
|
||||
// inst fetch: contains the maximum superscaler way to fetch
|
||||
SupWaySel Inst;
|
||||
SupWayX2Sel Inst;
|
||||
// data access
|
||||
void Ld;
|
||||
void St;
|
||||
@@ -710,7 +712,7 @@ typedef struct {
|
||||
typedef union tagged {
|
||||
// Resp for INST fetch. A vector entry can be invalid for two reasons: 1)
|
||||
// that entry is not requested, 2) that entry is access fault.
|
||||
Vector#(SupSize, Maybe#(Instruction)) InstFetch;
|
||||
Vector#(SupSizeX2, Maybe#(Instruction16)) InstFetch;
|
||||
// Resp for DATA access, i.e. LOAD, STORE and AMO
|
||||
MMIODataPRs DataAccess;
|
||||
} MMIOPRs deriving(Bits, Eq, FShow);
|
||||
|
||||
@@ -145,10 +145,10 @@ typedef Bit#(AsidSz) Asid;
|
||||
typedef TLog#(MemDataBytes) IndxShamt;
|
||||
typedef Vector#(MemDataBytes, Bool) MemDataByteEn;
|
||||
|
||||
typedef TDiv#(DataSz, InstSz) DataSzInst;
|
||||
typedef TDiv#(DataSz, Inst16_Sz) DataSzInst;
|
||||
typedef TLog#(DataSzInst) LgDataSzInst;
|
||||
typedef Bit#(LgDataSzInst) DataInstOffset;
|
||||
typedef TDiv#(MemDataSz, InstSz) MemDataSzInst;
|
||||
typedef TDiv#(MemDataSz, Inst16_Sz) MemDataSzInst;
|
||||
typedef TLog#(MemDataSzInst) LgMemDataSzInst;
|
||||
typedef Bit#(LgMemDataSzInst) MemDataInstOffset;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user