2-byte aligned instruction memory to simplify compressed instruction

fetch.
This commit is contained in:
jon
2020-07-24 12:38:37 +01:00
parent ecce475b97
commit 1f968b0c07
9 changed files with 113 additions and 165 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;