From 1f968b0c0765bf03086a71043a7fa57d89305cc3 Mon Sep 17 00:00:00 2001 From: jon Date: Fri, 24 Jul 2020 12:38:37 +0100 Subject: [PATCH] 2-byte aligned instruction memory to simplify compressed instruction fetch. --- src_Core/CPU/MMIOPlatform.bsv | 48 +++++--- src_Core/RISCY_OOO/coherence/src/CCTypes.bsv | 4 +- src_Core/RISCY_OOO/coherence/src/IBank.bsv | 44 +++---- .../RISCY_OOO/coherence/src/SelfInvIBank.bsv | 28 ++--- .../RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv | 110 ++++-------------- src_Core/RISCY_OOO/procs/lib/L1CoCache.bsv | 12 +- src_Core/RISCY_OOO/procs/lib/MMIOInst.bsv | 22 ++-- src_Core/RISCY_OOO/procs/lib/ProcTypes.bsv | 6 +- src_Core/RISCY_OOO/procs/lib/Types.bsv | 4 +- 9 files changed, 113 insertions(+), 165 deletions(-) diff --git a/src_Core/CPU/MMIOPlatform.bsv b/src_Core/CPU/MMIOPlatform.bsv index 278a3b1..97588d7 100644 --- a/src_Core/CPU/MMIOPlatform.bsv +++ b/src_Core/CPU/MMIOPlatform.bsv @@ -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 diff --git a/src_Core/RISCY_OOO/coherence/src/CCTypes.bsv b/src_Core/RISCY_OOO/coherence/src/CCTypes.bsv index 586d232..b583769 100644 --- a/src_Core/RISCY_OOO/coherence/src/CCTypes.bsv +++ b/src_Core/RISCY_OOO/coherence/src/CCTypes.bsv @@ -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 diff --git a/src_Core/RISCY_OOO/coherence/src/IBank.bsv b/src_Core/RISCY_OOO/coherence/src/IBank.bsv index eea023e..1fcf4fb 100644 --- a/src_Core/RISCY_OOO/coherence/src/IBank.bsv +++ b/src_Core/RISCY_OOO/coherence/src/IBank.bsv @@ -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 - diff --git a/src_Core/RISCY_OOO/coherence/src/SelfInvIBank.bsv b/src_Core/RISCY_OOO/coherence/src/SelfInvIBank.bsv index 8587d60..785cdca 100644 --- a/src_Core/RISCY_OOO/coherence/src/SelfInvIBank.bsv +++ b/src_Core/RISCY_OOO/coherence/src/SelfInvIBank.bsv @@ -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 - diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv index 3eae334..e593c6f 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv @@ -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