From 064cd22114bb74acd7ab6489e9c12aa96665ed62 Mon Sep 17 00:00:00 2001 From: Jonathan Woodruff Date: Mon, 7 Mar 2022 17:52:11 +0000 Subject: [PATCH] Inteligently delay Decode (for up to 8 cycles) if we encounter a pop while waiting for a push. --- .../RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv | 133 ++++++++++++------ src_Core/RISCY_OOO/procs/lib/Ras.bsv | 20 ++- src_SSITH_P3/Makefile | 2 +- 3 files changed, 107 insertions(+), 48 deletions(-) diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv index 3be89fa..b419b35 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv @@ -240,6 +240,31 @@ typedef struct { Bool mispred_first_half; } InstrFromFetch3 deriving(Bits, Eq, FShow); +function Bool popInst(DecodeResult dr); + let dInst = dr.dInst; + Bool doPop = False; + Bool dst_link = linkedR(dr.regs.dst); + Bool src1_link = linkedR(dr.regs.src1); + if (dr.dInst.iType == Jr || dr.dInst.iType == CJALR) begin // jalr TODO CCALL could be push + // pop or nop (if to trampoline) + // Add hint to architecture? + if (!dst_link && src1_link) begin + // rd is link while rs1 is not: pop + doPop = True; + end + else if (!src1_link && dst_link) begin + doPop = doPop; // Nothing + end + else if (dst_link && src1_link) begin + // both rd and rs1 are links + if (dr.regs.src1 != dr.regs.dst) begin + doPop = True; + end + end + end + return doPop; +endfunction + function InstrFromFetch3 fetch3_2_instC(Fetch3ToDecode in, Instruction inst, Bit#(32) orig_inst) = InstrFromFetch3 { pc: in.pc, @@ -610,12 +635,6 @@ module mkFetchStage(FetchStage); end endrule: doFetch3 - Bool delay_epoch = False; -`ifdef NO_SPEC_REDIRECT - // Delay decode if the head of this buffer matches the current epoch; - // this means the source of this epoch is still speculative. - delay_epoch = (main_epoch_spec.first.spec_bits != 0); -`endif function Bool isCurrent(Fetch3ToDecode in) = (main_epoch_spec.notEmpty && in.main_epoch == f_main_epoch && in.decode_epoch == decode_epoch[0]); @@ -633,44 +652,63 @@ module mkFetchStage(FetchStage); main_epoch_spec.first.spec_bits, main_epoch_spec.notEmpty, isCurrent(f32d.deqS[0].first), f_main_epoch, f32d.deqS[0].first.main_epoch); endrule - rule doDecode(f32d.deqS[0].canDeq && isCurrent(f32d.deqS[0].first) && !delay_epoch); - Vector#(SupSize, Maybe#(InstrFromFetch3)) decodeIn = replicate(Invalid); - // Express the incoming fragments as a vector of maybes. - Vector#(SupSizeX2, Maybe#(Fetch3ToDecode)) frags; - for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) - frags[i] = (f32d.deqS[i].canDeq) ? Valid (f32d.deqS[i].first) : Invalid; - // Pick as up to SupSize instructions from the f32d SupFifo. - // Stop picking when we have SupSize instructions or when we have exhausted the ports on the instruction fragment FIFO. - Maybe#(Bit#(TLog#(SupSizeX2))) m_used_frag_count = Invalid; - Bit#(TLog#(SupSize)) pick_count = 0; - Bool prev_frag_available = False; - for (Integer i = 0; i < valueOf(SupSizeX2) && !isValid(decodeIn[valueOf(SupSize) - 1]); i = i + 1) begin - Maybe#(InstrFromFetch3) new_pick = Invalid; - if (frags[i] matches tagged Valid .frag) begin - Fetch3ToDecode prev_frag = (i != 0) ? validValue(frags[i-1]) : ?; - if (prev_frag_available &&& !is_16b_inst(prev_frag.inst_frag)) begin // 2nd half of 32-bit instruction - new_pick = tagged Valid fetch3s_2_inst(frag, prev_frag); - if (!validValue(new_pick).mispred_first_half) begin - doAssert(getAddr(decompressPc(prev_frag.pc))+2 == getAddr(decompressPc(frag.pc)), "Attached fragments with non-contigious PCs"); -`ifdef RVFI_DII - doAssert(prev_frag.dii_pid+1 == frag.dii_pid, "Attached fragments with non-contigious DII IDs"); -`endif - end - end else if (is_16b_inst(frag.inst_frag) || isValid(frag.cause)) begin // 16-bit instruction - new_pick = tagged Valid fetch3_2_instC(frag, - fv_decode_C (misa, misa_mxl_64, getFlags(decompressPc(frag.pc))==1, frag.inst_frag), - zeroExtend(frag.inst_frag)); - end + Vector#(SupSize, Maybe#(InstrFromFetch3)) decodeIn = replicate(Invalid); + // Express the incoming fragments as a vector of maybes. + Vector#(SupSizeX2, Maybe#(Fetch3ToDecode)) frags; + for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) + frags[i] = (f32d.deqS[i].canDeq) ? Valid (f32d.deqS[i].first) : Invalid; + // Pick as up to SupSize instructions from the f32d SupFifo. + // Stop picking when we have SupSize instructions or when we have exhausted the ports on the instruction fragment FIFO. + Maybe#(Bit#(TLog#(SupSizeX2))) m_used_frag_count = Invalid; + Bit#(TLog#(SupSize)) pick_count = 0; + Bool prev_frag_available = False; + for (Integer i = 0; i < valueOf(SupSizeX2) && !isValid(decodeIn[valueOf(SupSize) - 1]); i = i + 1) begin + Maybe#(InstrFromFetch3) new_pick = Invalid; + if (frags[i] matches tagged Valid .frag) begin + Fetch3ToDecode prev_frag = (i != 0) ? validValue(frags[i-1]) : ?; + if (prev_frag_available &&& !is_16b_inst(prev_frag.inst_frag)) begin // 2nd half of 32-bit instruction + new_pick = tagged Valid fetch3s_2_inst(frag, prev_frag); + /*if (!validValue(new_pick).mispred_first_half) begin + doAssert(getAddr(decompressPc(prev_frag.pc))+2 == getAddr(decompressPc(frag.pc)), "Attached fragments with non-contigious PCs"); + `ifdef RVFI_DII + doAssert(prev_frag.dii_pid+1 == frag.dii_pid, "Attached fragments with non-contigious DII IDs"); + `endif + end*/ + end else if (is_16b_inst(frag.inst_frag) || isValid(frag.cause)) begin // 16-bit instruction + new_pick = tagged Valid fetch3_2_instC(frag, + fv_decode_C (misa, misa_mxl_64, getFlags(decompressPc(frag.pc))==1, frag.inst_frag), + zeroExtend(frag.inst_frag)); end - decodeIn[pick_count] = new_pick; - if (isValid(new_pick)) begin - if (verbose) - $display("Decode: picked instruction %d, next frag %d :", pick_count, i, fshow(decodeIn[pick_count])); - pick_count = pick_count + truncate(8'b1); - m_used_frag_count = tagged Valid fromInteger(i); - prev_frag_available = False; - end else prev_frag_available = isValid(frags[i]); end + decodeIn[pick_count] = new_pick; + if (isValid(new_pick)) begin + //if (verbose) + // $display("Decode: picked instruction %d, next frag %d :", pick_count, i, fshow(decodeIn[pick_count])); + pick_count = pick_count + truncate(8'b1); + m_used_frag_count = tagged Valid fromInteger(i); + prev_frag_available = False; + end else prev_frag_available = isValid(frags[i]); + end + Bool anyReturns = False; + Vector#(SupSize, DecodeResult) decodeResults = ?; + for (Integer i = 0; i < valueOf(SupSize); i = i + 1) begin + CapMem pc = decompressPc(validValue(decodeIn[i]).pc); + decodeResults[i] = decode(validValue(decodeIn[i]).inst, getFlags(pc)==1); // Decode 32b inst, or 32b expansion of 16b inst + if (popInst(decodeResults[i])) anyReturns = True; + end + + Bool delay_epoch = False; +`ifdef NO_SPEC_REDIRECT + // Delay decode if the head of this buffer matches the current epoch; + // this means the source of this epoch is still speculative. + delay_epoch = (main_epoch_spec.first.spec_bits != 0); +`endif +`ifdef NO_SPEC_RSB_PUSH + Bool delayForPop = ras.pendingPush && anyReturns; + delay_epoch = delay_epoch || delayForPop; +`endif + + rule doDecode(f32d.deqS[0].canDeq && isCurrent(f32d.deqS[0].first) && !delay_epoch); if (m_used_frag_count matches tagged Valid .used_frag_count) begin for (Integer i = 0; i < valueOf(SupSizeX2) && fromInteger(i) <= used_frag_count; i = i + 1) f32d.deqS[i].deq; if (verbose) @@ -693,12 +731,12 @@ module mkFetchStage(FetchStage); for (Integer i = 0; i < valueof(SupSize); i=i+1) begin CapMem pc = decompressPc(validValue(decodeIn[i]).pc); CapMem ppc = decompressPc(validValue(decodeIn[i]).ppc); - let decode_result = decode(validValue(decodeIn[i]).inst, getFlags(pc)==1); // Decode 32b inst, or 32b expansion of 16b inst + let decode_result = decodeResults[i]; // Decode 32b inst, or 32b expansion of 16b inst let dInst = decode_result.dInst; let regs = decode_result.regs; PredTrainInfo trainInfo = ?; // dir pred training bookkeeping DirPredResult#(DirPredTrainInfo) pred_res = DirPredResult{taken: False, train: ?}; - if(decode_result.dInst.iType == Br && !likely_epoch_change) begin + if(dInst.iType == Br && !likely_epoch_change) begin pred_res <- dirPred.pred[i].pred; trainInfo.dir = pred_res.train; likely_epoch_change = (pred_res.taken != validValue(decodeIn[i]).pred_jump); @@ -836,8 +874,11 @@ module mkFetchStage(FetchStage); end // if (decodeIn[i] matches tagged Valid .in) end // for (Integer i = 0; i < valueof(SupSize); i=i+1) -`ifndef NO_SPEC_RSB_PUSH - if (m_push_addr matches tagged Valid .pc) ras.push(pc); + if (m_push_addr matches tagged Valid .pc) +`ifdef NO_SPEC_RSB_PUSH + ras.willPush; +`else + ras.push(pc); `endif // update PC and epoch diff --git a/src_Core/RISCY_OOO/procs/lib/Ras.bsv b/src_Core/RISCY_OOO/procs/lib/Ras.bsv index 8d07a92..5ec7735 100644 --- a/src_Core/RISCY_OOO/procs/lib/Ras.bsv +++ b/src_Core/RISCY_OOO/procs/lib/Ras.bsv @@ -55,6 +55,8 @@ typedef RasIndex RasPredTrainInfo; interface ReturnAddrStack; interface Vector#(SupSize, RAS) ras; + method Action willPush; + method Bool pendingPush; method Action push(CapMem pushAddr); method Action setHead(RasIndex h); method Action flush; @@ -67,6 +69,15 @@ module mkRas(ReturnAddrStack) provisos(NumAlias#(TExp#(TLog#(RasEntries)), RasEn // head points past valid data // to gracefully overflow, head is allowed to overflow to 0 and overwrite the oldest data Ehr#(TAdd#(SupSize, 3), RasIndex) head <- mkEhr(0); + Ehr#(3, RasIndex) pendingPushReg <- mkEhr(0); + + Reg#(Bit#(6)) pendingPushDelay <- mkReg(0); + rule updatePendingPushDelay(pendingPushReg[2] != 0); + if (pendingPushDelay > 8) begin + pendingPushReg[2] <= 0; + pendingPushDelay <= 0; + end else pendingPushDelay <= pendingPushDelay + 1; + endrule `ifdef SECURITY Reg#(Bool) flushDone <- mkReg(True); @@ -95,11 +106,18 @@ module mkRas(ReturnAddrStack) provisos(NumAlias#(TExp#(TLog#(RasEntries)), RasEn endinterface); end + method Action willPush; + pendingPushReg[0]._write(pendingPushReg[0] + 1); + $display("RAS willPushReg<-%d", pendingPushReg[0] + 1); + endmethod + method Bool pendingPush = (pendingPushReg[0] != 0); + method Action push(CapMem pushAddr); Reg#(RasIndex) h = head[valueof(SupSize) + 2]; stack[h+1][1] <= pushAddr; - $display("RAS push head<-%d, val:%x", h+1, pushAddr); + $display("RAS push head<-%d, val:%x, willPushReg<-%d", h+1, pushAddr, pendingPushReg[1] - 1); h <= h+1; + if (pendingPushReg[1] != 0) pendingPushReg[1] <= pendingPushReg[1] - 1; endmethod method Action setHead(RasIndex h); diff --git a/src_SSITH_P3/Makefile b/src_SSITH_P3/Makefile index 129853a..f3777ca 100644 --- a/src_SSITH_P3/Makefile +++ b/src_SSITH_P3/Makefile @@ -39,7 +39,7 @@ BSC_COMPILATION_FLAGS += \ -D MEM64 \ -D RISCV \ -D TSO_MM \ - -D NO_SPEC_TRAINING -D NO_SPEC_REDIRECT -D NO_SPEC_STRAIGHT_PATH -D SPEC_RSB_FIXUP \ + -D NO_SPEC_TRAINING -D NO_SPEC_REDIRECT -D NO_SPEC_STRAIGHT_PATH -D SPEC_RSB_FIXUP -D NO_SPEC_RSB_PUSH \ -D INCLUDE_GDB_CONTROL \ -D BRVF_TRACE \ -D XILINX_BSCAN -D JTAG_TAP