diff --git a/libs/BlueStuff b/libs/BlueStuff index df2529d..a6e2273 160000 --- a/libs/BlueStuff +++ b/libs/BlueStuff @@ -1 +1 @@ -Subproject commit df2529dd4298fe77cfba638001f4a960f82fbe02 +Subproject commit a6e2273920cadf21c54c16865d00dbd345b59b13 diff --git a/src_Core/CPU/Core.bsv b/src_Core/CPU/Core.bsv index fdd760f..6992529 100644 --- a/src_Core/CPU/Core.bsv +++ b/src_Core/CPU/Core.bsv @@ -224,6 +224,7 @@ interface CoreFixPoint; interface MemExePipeline memExeIfc; method Action killAll; // kill everything: used by commit stage interface Reg#(Bool) doStatsIfc; + method Bool pendingIncorrectSpec; endinterface `ifdef CONTRACTS_VERIFY @@ -430,8 +431,9 @@ module mkCore#(CoreId coreId)(Core); , inst_tag.dii_next_pid `endif ); - globalSpecUpdate.incorrectSpec(False, spec_tag, inst_tag); + globalSpecUpdate.incorrectSpec(False, spec_tag, inst_tag, spec_bits); endmethod + method Bool pauseExecute = globalSpecUpdate.pendingIncorrectSpec; method correctSpec = globalSpecUpdate.correctSpec[finishAluCorrectSpecPort(i)].put; method doStats = doStatsReg._read; `ifdef PERFORMANCE_MONITORING @@ -522,9 +524,10 @@ module mkCore#(CoreId coreId)(Core); interface fpuMulDivExeIfc = fpuMulDivExe; interface memExeIfc = memExe; method Action killAll; - globalSpecUpdate.incorrectSpec(True, ?, ?); + globalSpecUpdate.incorrectSpec(True, ?, ?, 0); endmethod interface doStatsIfc = doStatsReg; + method pendingIncorrectSpec = globalSpecUpdate.pendingIncorrectSpec; endmodule CoreFixPoint coreFix <- moduleFix(mkCoreFixPoint); @@ -659,6 +662,8 @@ module mkCore#(CoreId coreId)(Core); method stbEmpty = stb.isEmpty; method stqEmpty = lsq.stqEmpty; method lsqSetAtCommit = lsq.setAtCommit; + method lookupPAddr = lsq.lookupPAddr; + method pauseCommit = coreFix.pendingIncorrectSpec; method tlbNoPendingReq = iTlb.noPendingReq && dTlb.noPendingReq; method setFlushTlbs; diff --git a/src_Core/Core/CoreW.bsv b/src_Core/Core/CoreW.bsv index ba38045..9d058d6 100644 --- a/src_Core/Core/CoreW.bsv +++ b/src_Core/Core/CoreW.bsv @@ -59,6 +59,7 @@ import Cur_Cycle :: *; import GetPut_Aux :: *; import Routable :: *; import AXI4 :: *; +import AXI4_Utils :: *; import TagControllerAXI :: *; import CacheCore :: *; @@ -171,7 +172,7 @@ module mkCoreW #(Reset dm_power_on_reset) Proc_IFC proc <- mkProc (reset_by all_harts_reset); // handle uncached interface - let proc_uncached = extendIDFields (zeroMasterUserFields (proc.master1), 0); + let proc_uncached = prepend_AXI4_Master_id (0, zero_AXI4_Master_user (proc.master1)); // Bridge for uncached expernal bus transactions. let uncached_mem_shim <- mkAXI4ShimFF(reset_by all_harts_reset); @@ -388,7 +389,7 @@ module mkCoreW #(Reset dm_power_on_reset) //let slave_vector = newVector; slave_vector[default_slave_num] = uncached_mem_shim.slave; slave_vector[llc_slave_num] = proc.debug_module_mem_server; - slave_vector[plic_slave_num] = zeroSlaveUserFields (plic.axi4_slave); + slave_vector[plic_slave_num] = zero_AXI4_Slave_user (plic.axi4_slave); function Vector#(Num_Slaves_2x3, Bool) route_2x3 (Bit#(Wd_Addr) addr); Vector#(Num_Slaves_2x3, Bool) res = replicate(False); @@ -459,7 +460,7 @@ module mkCoreW #(Reset dm_power_on_reset) interface cpu_imem_master = tagController.master; // Uncached master to Fabric master interface - interface cpu_dmem_master = extendIDFields(zeroMasterUserFields(uncached_mem_shim.master), 0); + interface cpu_dmem_master = prepend_AXI4_Master_id(0, zero_AXI4_Master_user(uncached_mem_shim.master)); // ---------------------------------------------------------------- // External interrupt sources diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/AluExePipeline.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/AluExePipeline.bsv index b108761..177cc42 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/AluExePipeline.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/AluExePipeline.bsv @@ -195,6 +195,8 @@ interface AluExeInput; method Action writeRegFile(PhyRIndx dst, CapPipe data); // redirect method Action redirect(CapMem new_pc, SpecTag spec_tag, InstTag inst_tag, SpecBits spec_bits); + // pending invalidation could pause execute/redirections. + method Bool pauseExecute; // spec update method Action correctSpec(SpecTag t); @@ -354,7 +356,7 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline); }); endrule - rule doExeAlu; + rule doExeAlu(!inIfc.pauseExecute); regToExeQ.deq; let regToExe = regToExeQ.first; let x = regToExe.data; @@ -432,7 +434,7 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline); }); endrule - rule doFinishAlu; + rule doFinishAlu(!inIfc.pauseExecute); exeToFinQ.deq; let exeToFin = exeToFinQ.first; let x = exeToFin.data; @@ -498,6 +500,8 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline); isCompressed: x.isCompressed}, spec_bits: exeToFin.spec_bits }); + $display("alu mispredict pc¤: %x, nextPc: %x, %d", + x.controlFlow.pc, x.controlFlow.nextPc, cur_cycle); `ifdef PERF_COUNT // performance counter if(inIfc.doStats) begin diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv index 8d5d19a..bf17561 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/CommitStage.bsv @@ -60,6 +60,7 @@ import RenameDebugIF::*; import CHERICap::*; import CHERICC_Fat::*; import ISA_Decls_CHERI::*; +import RegFile::*; // Just for the interface `ifdef PERFORMANCE_MONITORING import StatCounters::*; `endif @@ -106,8 +107,12 @@ interface CommitInput; method Bool stqEmpty; // notify LSQ that inst has reached commit interface Vector#(SupSize, Put#(LdStQTag)) lsqSetAtCommit; + // method for getting translated addresses for tracing. + interface Vector#(SupSize, RegFile#(LdStQTag, Addr)) lookupPAddr; // TLB has stopped processing now method Bool tlbNoPendingReq; + // Pause committing, probably for buffered wrongSpec + method Bool pauseCommit; // set flags method Action setFlushTlbs; method Action setUpdateVMInfo; @@ -212,7 +217,7 @@ typedef struct { Data mtvec; } TraceStateBundle deriving(Bits, FShow); -function Maybe#(RVFI_DII_Execution#(DataSz,DataSz)) genRVFI(ToReorderBuffer rot, Dii_Id traceCnt, TraceStateBundle tsb, Data next_pc); +function Maybe#(RVFI_DII_Execution#(DataSz,DataSz)) genRVFI(ToReorderBuffer rot, Dii_Id traceCnt, TraceStateBundle tsb, Data next_pc, Addr paddr); Addr addr = 0; Data data = 0; Data wdata = 0; @@ -229,6 +234,9 @@ function Maybe#(RVFI_DII_Execution#(DataSz,DataSz)) genRVFI(ToReorderBuffer rot, case (rot.ppc_vaddr_csrData) matches tagged VAddr .vaddr: begin addr = vaddr; +`ifdef PADDR_RVFI + addr = paddr; +`endif case (rot.lsqTag) matches tagged Ld .l: rmask = rot.traceBundle.memByteEn; tagged St .s: begin @@ -527,6 +535,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); // we commit trap in two cycles: first cycle deq ROB and flush; second // cycle handles trap, redirect and handles system consistency Reg#(Maybe#(CommitTrap)) commitTrap <- mkReg(Invalid); // saves new pc here + Bool pauseCommit = isValid(commitTrap) || inIfc.pauseCommit; FIFO#(RedirectInfo) redirectQ <- mkFIFO; @@ -661,7 +670,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); `ifdef INCLUDE_GDB_CONTROL (rg_run_state == RUN_STATE_RUNNING) &&& `endif - !isValid(commitTrap) &&& + !pauseCommit &&& rob.deqPort[0].deq_data.trap matches tagged Valid .trap ); rob.deqPort[0].deq; @@ -798,7 +807,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); }); `ifdef RVFI Rvfi_Traces rvfis = replicate(tagged Invalid); - rvfis[0] = genRVFI(trap.x, traceCnt, getTSB(), getAddr(new_pc)); + rvfis[0] = genRVFI(trap.x, traceCnt, getTSB(), getAddr(new_pc), inIfc.lookupPAddr[0].sub(trap.x.lsqTag)); rvfiQ.enq(rvfis); traceCnt <= traceCnt + 1; `endif @@ -826,7 +835,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); `ifdef INCLUDE_GDB_CONTROL (rg_run_state == RUN_STATE_RUNNING) &&& `endif - !isValid(commitTrap) &&& + !pauseCommit &&& !isValid(rob.deqPort[0].deq_data.trap) &&& rob.deqPort[0].deq_data.ldKilled matches tagged Valid .killBy ); @@ -867,7 +876,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); `ifdef INCLUDE_GDB_CONTROL (rg_run_state == RUN_STATE_RUNNING) && `endif - !isValid(commitTrap) && + !pauseCommit && !isValid(rob.deqPort[0].deq_data.trap) && !isValid(rob.deqPort[0].deq_data.ldKilled) && rob.deqPort[0].deq_data.rob_inst_state == Executed && @@ -958,7 +967,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); end redirectQ.enq(RedirectInfo{trap_pc: next_pc `ifdef RVFI_DII - , x.dii_pid + (is_16b_inst(x.orig_inst) ? 1 : 2) + , dii_pid: x.dii_pid + (is_16b_inst(x.orig_inst) ? 1 : 2) `endif }); @@ -967,7 +976,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); Rvfi_Traces rvfis = replicate(tagged Invalid); x.ppc_vaddr_csrData = tagged PPC next_pc; CapPipe cp = cast(next_pc); - rvfis[0] = genRVFI(x, traceCnt, getTSB(), getOffset(cp)); + rvfis[0] = genRVFI(x, traceCnt, getTSB(), getOffset(cp), inIfc.lookupPAddr[0].sub(x.lsqTag)); rvfiQ.enq(rvfis); traceCnt <= traceCnt + 1; `endif @@ -1043,7 +1052,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); // Lr/Sc/Amo/MMIO cannot proceed to executed until we notify LSQ that it // has reached the commit stage rule notifyLSQCommit( - !isValid(commitTrap) && + !pauseCommit && !isValid(rob.deqPort[0].deq_data.trap) && !isValid(rob.deqPort[0].deq_data.ldKilled) && rob.deqPort[0].deq_data.rob_inst_state != Executed && @@ -1064,7 +1073,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); `ifdef INCLUDE_GDB_CONTROL (rg_run_state == RUN_STATE_RUNNING) && `endif - !isValid(commitTrap) && + !pauseCommit && !isValid(rob.deqPort[0].deq_data.trap) && !isValid(rob.deqPort[0].deq_data.ldKilled) && rob.deqPort[0].deq_data.rob_inst_state == Executed && @@ -1145,7 +1154,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); if (verbose) $display("%t : [doCommitNormalInst - %d] ", $time(), i, fshow(inst_tag), " ; ", fshow(x)); `ifdef RVFI CapPipe pipePc = cast(x.pc); - rvfis[i] = genRVFI(x, traceCnt + zeroExtend(whichTrace), getTSB(), getOffset(pipePc) + (is_16b_inst(x.orig_inst) ? 2:4)); + rvfis[i] = genRVFI(x, traceCnt + zeroExtend(whichTrace), getTSB(), getOffset(pipePc) + (is_16b_inst(x.orig_inst) ? 2:4), inIfc.lookupPAddr[i].sub(x.lsqTag)); whichTrace = whichTrace + 1; `endif @@ -1359,7 +1368,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage); RedirectInfo ri <- toGet(redirectQ).get; inIfc.redirectPc(ri.trap_pc, 0 `ifdef RVFI_DII - , ri.rii_pid + , ri.dii_pid `endif ); endrule diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv index a78dbe4..4ca1d16 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv @@ -363,6 +363,10 @@ module mkFetchStage(FetchStage); Integer pc_fetch3_port = 2; Integer pc_redirect_port = 3; Integer pc_final_port = 4; + // To track the next expected PC in Decode for early lookups for prediction. + Ehr#(TAdd#(SupSize, 2), Addr) decode_pc_reg <- mkEhr(?); + Integer decode_pc_redirect_port = valueOf(SupSize); + Integer decode_pc_final_port = valueOf(SupSize) + 1; // PC compression structure holding an indexed set of PC blocks so that only indexes need be tracked. IndexedMultiset#(PcIdx, PcMSB, SupSizeX2) pcBlocks <- mkIndexedMultisetQueue; @@ -677,12 +681,23 @@ module mkFetchStage(FetchStage); // Note that only 1 redirection may happen in a cycle Maybe#(IType) redirectInst = Invalid; `endif - + Bool likely_epoch_change = False; 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 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 + pred_res <- dirPred.pred[i].pred; + trainInfo.dir = pred_res.train; + likely_epoch_change = (pred_res.taken != validValue(decodeIn[i]).pred_jump); + end + Maybe#(CapMem) dir_ppc = decodeBrPred(pc, decode_result.dInst, pred_res.taken, (validValue(decodeIn[i]).inst_kind == Inst_32b)); if (decodeIn[i] matches tagged Valid .in) begin let cause = in.cause; - CapMem pc = decompressPc(in.pc); - CapMem ppc = decompressPc(in.ppc); pcBlocks.rPort[i].remove(in.pc.idx); if (verbose) $display("Decode: %0d in = ", i, fshow (in)); @@ -703,28 +718,15 @@ module mkFetchStage(FetchStage); end else if (in.decode_epoch == decode_epoch_local) begin doAssert(in.main_epoch == f_main_epoch, "main epoch must match"); - let decode_result = decode(in.inst, getFlags(pc)==1); // Decode 32b inst, or 32b expansion of 16b inst - // update cause if decode exception and no earlier (TLB) exception if (!isValid(cause)) begin cause = decode_result.illegalInst ? tagged Valid excIllegalInst : tagged Invalid; end - let dInst = decode_result.dInst; - let regs = decode_result.regs; - PredTrainInfo trainInfo = ?; // dir pred training bookkeeping - // update predicted next pc if (!isValid(cause)) begin // direction predict - Bool pred_taken = False; - if(dInst.iType == Br) begin - let pred_res <- dirPred.pred[i].pred(getAddr(pc)); - pred_taken = pred_res.taken; - trainInfo.dir = pred_res.train; - end - Maybe#(CapMem) nextPc = decodeBrPred(pc, dInst, pred_taken, (in.inst_kind == Inst_32b)); - + Maybe#(CapMem) nextPc = dir_ppc; // return address stack link reg is x1 or x5 function Bool linkedR(Maybe#(ArchRIndx) register); Bool res = False; @@ -773,7 +775,7 @@ module mkFetchStage(FetchStage); trainInfo.ras <- ras.ras[i].popPush(pop, m_push_addr); if(verbose) begin $display("Branch prediction: ", fshow(dInst.iType), " ; ", fshow(pc), " ; ", - fshow(ppc), " ; ", fshow(pred_taken), " ; ", fshow(nextPc)); + fshow(ppc), " ; ", fshow(nextPc)); end // If we don't have a good guess about where we are going, don't proceed. @@ -800,6 +802,7 @@ module mkFetchStage(FetchStage); `endif end end // if (!isValid(cause)) + decode_pc_reg[i] <= getAddr(ppc); let out = FromFetchStage{pc: pc, `ifdef RVFI_DII dii_pid: in.dii_pid, @@ -831,8 +834,8 @@ module mkFetchStage(FetchStage); end // for (Integer i = 0; i < valueof(SupSize); i=i+1) // update PC and epoch - if(redirectPc matches tagged Valid .nextPc) begin - pc_reg[pc_decode_port] <= nextPc; + if(redirectPc matches tagged Valid .rp) begin + pc_reg[pc_decode_port] <= rp; end `ifdef RVFI_DII doAssert(isValid(redirectPc) == isValid(redirectDiiPid), "PC and DII redirections always happen together"); @@ -858,6 +861,10 @@ module mkFetchStage(FetchStage); `endif endrule + rule reportDecodePc; + dirPred.nextPc(decode_pc_reg[decode_pc_final_port]); + endrule + // train next addr pred: we use a wire to catch outputs of napTrainByDecQ. // This prevents napTrainByDecQ from clogging doDecode rule when // superscalar size is large @@ -928,6 +935,7 @@ module mkFetchStage(FetchStage); dii_pid_reg[pc_redirect_port] <= dii_pid; if (verbose) $display("%t Redirect: dii_pid_reg %d", $time(), dii_pid); `endif + decode_pc_reg[decode_pc_redirect_port] <= getAddr(new_pc); set_main_epoch((f_main_epoch == fromInteger(valueOf(NumEpochs)-1)) ? 0 : f_main_epoch + 1, specBits); // redirect comes, stop stalling for redirect waitForRedirect[1] <= False; @@ -969,7 +977,7 @@ module mkFetchStage(FetchStage); //end if (iType == Br) begin // Train the direction predictor for all branches - dirPred.update(getAddr(pc), taken, trainInfo.dir, mispred); + dirPred.update(taken, trainInfo.dir, mispred); $display("Branch train PC: %x, taken: %x, mispred: %x", getAddr(pc), taken, mispred); end // train next addr pred when mispred diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/ProcConfig.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/ProcConfig.bsv index 871a586..d84e1ae 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/ProcConfig.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/ProcConfig.bsv @@ -167,6 +167,30 @@ // ==== CORE SIZE ==== // +`ifdef CORE_MINI + + // superscalar + `define sizeSup 2 + + // ROB + `define ROB_SIZE 32 + + // speculation + `define NUM_EPOCHS 4 + `define NUM_SPEC_TAGS 4 + + // LSQ + `define LDQ_SIZE 8 + `define STQ_SIZE 4 + `define SB_SIZE 2 + + // reservation station sizes + `define RS_ALU_SIZE 8 + `define RS_MEM_SIZE 4 + `define RS_FPUMULDIV_SIZE 4 + +`endif + `ifdef CORE_TINY // superscalar diff --git a/src_Core/RISCY_OOO/procs/lib/Bht.bsv b/src_Core/RISCY_OOO/procs/lib/Bht.bsv index e87cb08..7560fb4 100644 --- a/src_Core/RISCY_OOO/procs/lib/Bht.bsv +++ b/src_Core/RISCY_OOO/procs/lib/Bht.bsv @@ -42,18 +42,21 @@ import BrPred::*; export BhtTrainInfo; export mkBht; - -typedef Bit#(0) BhtTrainInfo; // no training info needs to be remembered +export BhtEntries; +export BhtIndex; // Local BHT Typedefs typedef 128 BhtEntries; typedef Bit#(TLog#(BhtEntries)) BhtIndex; +typedef BhtIndex BhtTrainInfo; + (* synthesize *) module mkBht(DirPredictor#(BhtTrainInfo)); // Read and Write ordering doesn't matter since this is a predictor // mkRegFileWCF is the RegFile version of mkConfigReg RegFile#(BhtIndex, Bit#(2)) hist <- mkRegFileWCF(0,fromInteger(valueOf(BhtEntries)-1)); + Reg#(Addr) pc_reg <- mkRegU; function BhtIndex getIndex(Addr pc); return truncate(pc >> 2); @@ -62,22 +65,24 @@ module mkBht(DirPredictor#(BhtTrainInfo)); Vector#(SupSize, DirPred#(BhtTrainInfo)) predIfc; for(Integer i = 0; i < valueof(SupSize); i = i+1) begin predIfc[i] = (interface DirPred; - method ActionValue#(DirPredResult#(BhtTrainInfo)) pred(Addr pc); - let index = getIndex(pc); + method ActionValue#(DirPredResult#(BhtTrainInfo)) pred; + let index = getIndex(offsetPc(pc_reg, i)); Bit#(2) cnt = hist.sub(index); Bool taken = cnt[1] == 1; return DirPredResult { taken: taken, - train: 0 + train: index }; endmethod endinterface); end + method nextPc = pc_reg._write; + interface pred = predIfc; - method Action update(Addr pc, Bool taken, BhtTrainInfo train, Bool mispred); - let index = getIndex(pc); + method Action update(Bool taken, BhtTrainInfo train, Bool mispred); + let index = train; let current_hist = hist.sub(index); Bit#(2) next_hist; if(taken) begin diff --git a/src_Core/RISCY_OOO/procs/lib/BrPred.bsv b/src_Core/RISCY_OOO/procs/lib/BrPred.bsv index 8d074a4..76f1b8e 100644 --- a/src_Core/RISCY_OOO/procs/lib/BrPred.bsv +++ b/src_Core/RISCY_OOO/procs/lib/BrPred.bsv @@ -67,18 +67,22 @@ endfunction // general types for direction predictor +// Function to offset PC by the probable size of an instruction without a full add delay. +function Addr offsetPc(Addr pc, Integer i) = {truncateLSB(pc), pc[7:0] + (fromInteger(i)*4)}; + typedef struct { Bool taken; trainInfoT train; // info that a branch must keep for future training } DirPredResult#(type trainInfoT) deriving(Bits, Eq, FShow); interface DirPred#(type trainInfoT); - method ActionValue#(DirPredResult#(trainInfoT)) pred(Addr pc); + method ActionValue#(DirPredResult#(trainInfoT)) pred; endinterface interface DirPredictor#(type trainInfoT); + method Action nextPc(Addr nextPc); interface Vector#(SupSize, DirPred#(trainInfoT)) pred; - method Action update(Addr pc, Bool taken, trainInfoT train, Bool mispred); + method Action update(Bool taken, trainInfoT train, Bool mispred); method Action flush; method Bool flush_done; endinterface diff --git a/src_Core/RISCY_OOO/procs/lib/Btb.bsv b/src_Core/RISCY_OOO/procs/lib/Btb.bsv index 3c572d3..2b92d72 100644 --- a/src_Core/RISCY_OOO/procs/lib/Btb.bsv +++ b/src_Core/RISCY_OOO/procs/lib/Btb.bsv @@ -38,6 +38,7 @@ import Types::*; import ProcTypes::*; import ConfigReg::*; +import DReg::*; import Map::*; import Vector::*; import CHERICC_Fat::*; @@ -58,6 +59,7 @@ endinterface // Local BTB Typedefs typedef 1 PcLsbsIgnore; typedef 1024 BtbEntries; +typedef Bit#(16) CompressedTarget; typedef 2 BtbAssociativity; typedef Bit#(TLog#(SupSizeX2)) BtbBank; // Total entries/lanes of superscalar lookup/associativity @@ -94,10 +96,12 @@ module mkBtbCore(NextAddrPred#(hashSz)) Add#(1, a__, TDiv#(tagSz, hashSz)), Add#(b__, tagSz, TMul#(TDiv#(tagSz, hashSz), hashSz))); // Read and Write ordering doesn't matter since this is a predictor - Reg#(BtbBank) firstBank_reg <- mkRegU; - Vector#(SupSizeX2, MapSplit#(HashedTag#(hashSz), BtbIndex, VnD#(CapMem), BtbAssociativity)) - records <- replicateM(mkMapLossyBRAM); - RWire#(BtbUpdate) updateEn <- mkRWire; + Reg#(CapMem) addr_reg <- mkRegU; + Vector#(SupSizeX2, MapSplit#(HashedTag#(hashSz), BtbIndex, VnD#(CapMem), 1)) + fullRecords <- replicateM(mkMapLossyBRAM); + Vector#(SupSizeX2, MapSplit#(HashedTag#(hashSz), BtbIndex, VnD#(CompressedTarget), BtbAssociativity)) + compressedRecords <- replicateM(mkMapLossyBRAM); + Reg#(Maybe#(BtbUpdate)) updateEn <- mkDReg(Invalid); function BtbAddr getBtbAddr(CapMem pc) = unpack(truncateLSB(getAddr(pc))); function BtbBank getBank(CapMem pc) = getBtbAddr(pc).bank; @@ -108,44 +112,58 @@ module mkBtbCore(NextAddrPred#(hashSz)) // no flush, accept update (* fire_when_enabled, no_implicit_conditions *) - rule canonUpdate(updateEn.wget matches tagged Valid .upd); + rule canonUpdate(updateEn matches tagged Valid .upd); let pc = upd.pc; let nextPc = upd.nextPc; let taken = upd.taken; /*$display("MapUpdate in BTB - pc %x, bank: %x, taken: %x, next: %x, time: %t", pc, getBank(pc), taken, nextPc, $time);*/ - records[getBank(pc)].update(lookupKey(pc), VnD{v:taken, d:nextPc}); + CompressedTarget shortMask = -1; + CapMem mask = ~zeroExtend(shortMask); + if ((pc&mask) == (nextPc&mask)) + compressedRecords[getBank(pc)].update(lookupKey(pc), VnD{v:taken, d:truncate(nextPc)}); + else + fullRecords[getBank(pc)].update(lookupKey(pc), VnD{v:taken, d:nextPc}); endrule method Action put_pc(CapMem pc); - BtbAddr addr = getBtbAddr(pc); - firstBank_reg <= addr.bank; + addr_reg <= pc; // Start SupSizeX2 BTB lookups, but ensure to lookup in the appropriate // bank for the alignment of each potential branch. for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) begin - BtbAddr a = unpack(pack(addr) + fromInteger(i)); - records[a.bank].lookupStart(MapKeyIndex{key: hash(a.tag), index: a.index}); + // Only add lower bits for timing. + BtbAddr a = getBtbAddr(pc); + a = unpack({a.tag, {a.index,a.bank} + fromInteger(i)}); + //BtbAddr a = unpack(pack(getBtbAddr(pc)) + fromInteger(i)); + fullRecords[a.bank].lookupStart(MapKeyIndex{key: hash(a.tag), index: a.index}); + compressedRecords[a.bank].lookupStart(MapKeyIndex{key: hash(a.tag), index: a.index}); end endmethod method Vector#(SupSizeX2, Maybe#(CapMem)) pred; Vector#(SupSizeX2, Maybe#(CapMem)) ppcs = replicate(Invalid); - for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) - if (records[i].lookupRead matches tagged Valid .record) - ppcs[i] = record.v ? Valid(record.d):Invalid; - ppcs = rotateBy(ppcs,unpack(-firstBank_reg)); // Rotate firstBank down to zeroeth element. + for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) begin + if (fullRecords[i].lookupRead matches tagged Valid .r) + ppcs[i] = r.v ? Valid(r.d):Invalid; + if (compressedRecords[i].lookupRead matches tagged Valid .r) + ppcs[i] = r.v ? Valid({truncateLSB(addr_reg),r.d}):Invalid; + end + ppcs = rotateBy(ppcs,unpack(-getBtbAddr(addr_reg).bank)); // Rotate firstBank down to zeroeth element. return ppcs; endmethod method Action update(CapMem pc, CapMem nextPc, Bool taken); - updateEn.wset(BtbUpdate {pc: pc, nextPc: nextPc, taken: taken}); + updateEn <= Valid(BtbUpdate {pc: pc, nextPc: nextPc, taken: taken}); endmethod `ifdef SECURITY method Action flush method Action flush; - for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) records[i].clear; + for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) begin + fullRecords[i].clear; + compressedRecords[i].clear; + end endmethod - method flush_done = records[0].clearDone; + method flush_done = fullRecords[0].clearDone; `else method flush = noAction; method flush_done = True; diff --git a/src_Core/RISCY_OOO/procs/lib/Fpu.bsv b/src_Core/RISCY_OOO/procs/lib/Fpu.bsv index b3894c4..d7ff598 100644 --- a/src_Core/RISCY_OOO/procs/lib/Fpu.bsv +++ b/src_Core/RISCY_OOO/procs/lib/Fpu.bsv @@ -95,7 +95,7 @@ module mkDoubleDiv(Server#(Tuple3#(Double, Double, FpuRoundMode), Tuple2#(Double `ifdef USE_XILINX_FPU let fpu <- mkXilinxFpDiv; `else - let int_div <- mkDivider(1); // [sizhuo] size in RVFpu: 2 + let int_div <- mkNonPipelinedDivider(3); // [sizhuo] size in RVFpu: 2 let fpu <- mkFloatingPointDivider(int_div); `endif return fpu; diff --git a/src_Core/RISCY_OOO/procs/lib/GSelectPred.bsv b/src_Core/RISCY_OOO/procs/lib/GSelectPred.bsv index 41b9f12..adf70ca 100644 --- a/src_Core/RISCY_OOO/procs/lib/GSelectPred.bsv +++ b/src_Core/RISCY_OOO/procs/lib/GSelectPred.bsv @@ -46,6 +46,9 @@ export GSelectGHistSz; export GSelectGHist; export GSelectTrainInfo; export mkGSelectPred; +export PCIndexSz; +export BhtIndexSz; +export BhtIndex; // 1KB gselect predictor @@ -60,6 +63,7 @@ typedef Bit#(BhtIndexSz) BhtIndex; // bookkeeping info a branch should keep for future training typedef struct { GSelectGHist gHist; + BhtIndex index; } GSelectTrainInfo deriving(Bits, Eq, FShow); // global history @@ -83,6 +87,9 @@ module mkGSelectPred(DirPredictor#(GSelectTrainInfo)); Ehr#(TAdd#(1, SupSize), Bit#(TLog#(TAdd#(SupSize, 1)))) predCnt <- mkEhr(0); Ehr#(TAdd#(1, SupSize), Bit#(SupSize)) predRes <- mkEhr(0); + // Lookup PC + Reg#(Addr) pc_reg <- mkRegU; + function BhtIndex getIndex(Addr pc, GSelectGHist gHist); Bit#(PCIndexSz) pcIdx = truncate(pc >> 2); return {gHist, pcIdx}; @@ -106,13 +113,14 @@ module mkGSelectPred(DirPredictor#(GSelectTrainInfo)); Vector#(SupSize, DirPred#(GSelectTrainInfo)) predIfc; for(Integer i = 0; i < valueof(SupSize); i = i+1) begin predIfc[i] = (interface DirPred; - method ActionValue#(DirPredResult#(GSelectTrainInfo)) pred(Addr pc); + method ActionValue#(DirPredResult#(GSelectTrainInfo)) pred; // get the global history // all previous branch in this cycle must be not taken // otherwise this branch should be on wrong path // because all inst in same cycle are fetched consecutively GSelectGHist gHist = curGHist >> predCnt[i]; - Bool taken = isTaken(tab.sub(getIndex(pc, gHist))); + BhtIndex index = getIndex(offsetPc(pc_reg, i), gHist); + Bool taken = isTaken(tab.sub(index)); // record pred result predCnt[i] <= predCnt[i] + 1; @@ -124,7 +132,8 @@ module mkGSelectPred(DirPredictor#(GSelectTrainInfo)); return DirPredResult { taken: taken, train: GSelectTrainInfo { - gHist: gHist + gHist: gHist, + index: index } }; endmethod @@ -138,16 +147,18 @@ module mkGSelectPred(DirPredictor#(GSelectTrainInfo)); predCnt[valueof(SupSize)] <= 0; endrule + method nextPc = pc_reg._write; + interface pred = predIfc; - method Action update(Addr pc, Bool taken, GSelectTrainInfo train, Bool mispred); + method Action update(Bool taken, GSelectTrainInfo train, Bool mispred); // update history if mispred if(mispred) begin GSelectGHist newHist = truncate({pack(taken), train.gHist} >> 1); globalHist.redirect(newHist); end // update sat cnt - let index = getIndex(pc, train.gHist); + let index = train.index; Bit#(2) cnt = tab.sub(index); tab.upd(index, updateCnt(cnt, taken)); endmethod diff --git a/src_Core/RISCY_OOO/procs/lib/GSharePred.bsv b/src_Core/RISCY_OOO/procs/lib/GSharePred.bsv index 395ba46..b95541f 100644 --- a/src_Core/RISCY_OOO/procs/lib/GSharePred.bsv +++ b/src_Core/RISCY_OOO/procs/lib/GSharePred.bsv @@ -46,6 +46,8 @@ export GShareGHistSz; export GShareGHist; export GShareTrainInfo; export mkGSharePred; +export BhtIndexSz; +export BhtIndex; // 16KB gshare predictor (to match BOOM evaluation paper) @@ -60,6 +62,7 @@ typedef Bit#(BhtIndexSz) BhtIndex; // bookkeeping info a branch should keep for future training typedef struct { GShareGHist gHist; + BhtIndex index; } GShareTrainInfo deriving(Bits, Eq, FShow); // global history @@ -83,6 +86,9 @@ module mkGSharePred(DirPredictor#(GShareTrainInfo)); Ehr#(TAdd#(1, SupSize), Bit#(TLog#(TAdd#(SupSize, 1)))) predCnt <- mkEhr(0); Ehr#(TAdd#(1, SupSize), Bit#(SupSize)) predRes <- mkEhr(0); + // Lookup PC + Reg#(Addr) pc_reg <- mkRegU; + function BhtIndex getIndex(Addr pc, GShareGHist gHist); Bit#(PCIndexSz) pcIdx = truncate(pc >> 2); return gHist ^ pcIdx; @@ -106,13 +112,14 @@ module mkGSharePred(DirPredictor#(GShareTrainInfo)); Vector#(SupSize, DirPred#(GShareTrainInfo)) predIfc; for(Integer i = 0; i < valueof(SupSize); i = i+1) begin predIfc[i] = (interface DirPred; - method ActionValue#(DirPredResult#(GShareTrainInfo)) pred(Addr pc); + method ActionValue#(DirPredResult#(GShareTrainInfo)) pred; // get the global history // all previous branch in this cycle must be not taken // otherwise this branch should be on wrong path // because all inst in same cycle are fetched consecutively GShareGHist gHist = curGHist >> predCnt[i]; - Bool taken = isTaken(tab.sub(getIndex(pc, gHist))); + BhtIndex index = getIndex(offsetPc(pc_reg, i), gHist); + Bool taken = isTaken(tab.sub(index)); // record pred result predCnt[i] <= predCnt[i] + 1; @@ -124,7 +131,8 @@ module mkGSharePred(DirPredictor#(GShareTrainInfo)); return DirPredResult { taken: taken, train: GShareTrainInfo { - gHist: gHist + gHist: gHist, + index: index } }; endmethod @@ -138,18 +146,19 @@ module mkGSharePred(DirPredictor#(GShareTrainInfo)); predCnt[valueof(SupSize)] <= 0; endrule + method nextPc = pc_reg._write; + interface pred = predIfc; - method Action update(Addr pc, Bool taken, GShareTrainInfo train, Bool mispred); + method Action update(Bool taken, GShareTrainInfo train, Bool mispred); // update history if mispred if(mispred) begin GShareGHist newHist = truncate({pack(taken), train.gHist} >> 1); globalHist.redirect(newHist); end // update sat cnt - let index = getIndex(pc, train.gHist); - Bit#(2) cnt = tab.sub(index); - tab.upd(index, updateCnt(cnt, taken)); + Bit#(2) cnt = tab.sub(train.index); + tab.upd(train.index, updateCnt(cnt, taken)); endmethod method flush = noAction; diff --git a/src_Core/RISCY_OOO/procs/lib/GlobalSpecUpdate.bsv b/src_Core/RISCY_OOO/procs/lib/GlobalSpecUpdate.bsv index f17bb98..28ae322 100644 --- a/src_Core/RISCY_OOO/procs/lib/GlobalSpecUpdate.bsv +++ b/src_Core/RISCY_OOO/procs/lib/GlobalSpecUpdate.bsv @@ -1,6 +1,6 @@ // Copyright (c) 2017 Massachusetts Institute of Technology -// +// // 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 @@ -8,10 +8,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 @@ -26,16 +26,24 @@ import HasSpecBits::*; import GetPut::*; import Vector::*; import ReorderBuffer::*; +import SpecFifo::*; + +typedef struct { + Bool kill_all; + SpecTag spec_tag; + InstTag inst_tag; +} IncorrectSpec deriving(Bits, Eq, FShow); interface GlobalSpecUpdate#(numeric type correctSpecPortNum, numeric type conflictWrongSpecPortNum); interface Vector#(correctSpecPortNum, Put#(SpecTag)) correctSpec; - method Action incorrectSpec(Bool kill_all, SpecTag spec_tag, InstTag inst_tag); + method Action incorrectSpec(Bool kill_all, SpecTag spec_tag, InstTag inst_tag, SpecBits spec_bits); // Some rules (e.g. doFinishFpuMulDiv) in Core.bsv may not conflict with wrong spec // and is ordered before rules that calls incorrectSpec // this creates cycles in scheduling // To break the cycle, such rules can call the following interface // to manually create a conflict with rules that do incorrectSpec interface Vector#(conflictWrongSpecPortNum, Put#(void)) conflictWrongSpec; + method Bool pendingIncorrectSpec; endinterface module mkGlobalSpecUpdate#( @@ -46,10 +54,11 @@ module mkGlobalSpecUpdate#( ); // record correct spec tags Vector#(correctSpecPortNum, RWire#(SpecTag)) correctSpecTag <- replicateM(mkRWire); - // make wrong spec conflict with correct spec - Vector#(correctSpecPortNum, RWire#(void)) spec_conflict <- replicateM(mkRWire); - // let the caller of conflictWrongSpec to be conflict with wrong spec - Vector#(conflictWrongSpecPortNum, RWire#(void)) wrongSpec_conflict <- replicateM(mkRWire); + // make wrong spec conflict with correct spec and conflictWrongSpec + PulseWire spec_conflict <- mkPulseWire; + // must be a single-element fifo to ensure all pushing rules cannot fire while we are waiting + // to kill. + SpecFifo#(2,IncorrectSpec,1,1) incorrectSpec_ff <- mkSpecFifoCF(True); (* fire_when_enabled, no_implicit_conditions *) rule canon_correct_spec; @@ -59,17 +68,26 @@ module mkGlobalSpecUpdate#( mask[tag] = 0; end end + incorrectSpec_ff.specUpdate.correctSpeculation(mask); ifc.correctSpeculation(mask); rob.correctSpeculation(mask); endrule + rule do_incorrect_spec; + IncorrectSpec x = incorrectSpec_ff.first.data; + incorrectSpec_ff.deq; + incorrectSpec_ff.specUpdate.incorrectSpeculation(x.kill_all, x.spec_tag); + ifc.incorrectSpeculation(x.kill_all, x.spec_tag); + rob.incorrectSpeculation(x.kill_all, x.spec_tag, x.inst_tag); + // conflict with correct spec and conflictWrongSpec + spec_conflict.send; + endrule + Vector#(correctSpecPortNum, Put#(SpecTag)) correctVec = ?; for(Integer i = 0; i < valueof(correctSpecPortNum); i = i+1) begin correctVec[i] = (interface Put; - method Action put(SpecTag t); + method Action put(SpecTag t) if (!spec_conflict); correctSpecTag[i].wset(t); - // conflict with wrong spec - spec_conflict[i].wset(?); endmethod endinterface); end @@ -77,26 +95,21 @@ module mkGlobalSpecUpdate#( Vector#(conflictWrongSpecPortNum, Put#(void)) conflictWrongVec = ?; for(Integer i = 0; i < valueof(conflictWrongSpecPortNum); i = i+1) begin conflictWrongVec[i] = (interface Put; - method Action put(void x); - wrongSpec_conflict[i].wset(?); + method Action put(void x) if (!spec_conflict); + noAction; endmethod endinterface); end interface correctSpec = correctVec; - method Action incorrectSpec(Bool kill_all, SpecTag spec_tag, InstTag inst_tag); - ifc.incorrectSpeculation(kill_all, spec_tag); - rob.incorrectSpeculation(kill_all, spec_tag, inst_tag); - // conflict with correct spec - for(Integer i = 0; i < valueof(correctSpecPortNum); i = i+1) begin - spec_conflict[i].wset(?); - end - // conflict with the caller of conflictWrongSpec - for(Integer i = 0; i < valueof(conflictWrongSpecPortNum); i = i+1) begin - wrongSpec_conflict[i].wset(?); - end - endmethod + method Action incorrectSpec(Bool kill_all, SpecTag spec_tag, InstTag inst_tag, SpecBits spec_bits) + = incorrectSpec_ff.enq(ToSpecFifo{ + data: IncorrectSpec{kill_all: kill_all, spec_tag: spec_tag, inst_tag: inst_tag}, + spec_bits: spec_bits + }); interface conflictWrongSpec = conflictWrongVec; + + method Bool pendingIncorrectSpec = incorrectSpec_ff.notEmpty; endmodule diff --git a/src_Core/RISCY_OOO/procs/lib/LatencyTimer.bsv b/src_Core/RISCY_OOO/procs/lib/LatencyTimer.bsv index 56b3853..2cdfb04 100644 --- a/src_Core/RISCY_OOO/procs/lib/LatencyTimer.bsv +++ b/src_Core/RISCY_OOO/procs/lib/LatencyTimer.bsv @@ -23,6 +23,7 @@ import Vector::*; import Types::*; +import ConfigReg::*; // a timer to track latency of multiple misses @@ -39,8 +40,8 @@ module mkLatencyTimer(LatencyTimer#(num, timeWidth)) provisos( Alias#(idxT, Bit#(TLog#(num))), Alias#(timeT, Bit#(timeWidth)) ); - Reg#(Vector#(num, timeT)) timer <- mkReg(replicate(0)); - Reg#(Vector#(num, Bool)) started <- mkReg(replicate(False)); // for checking purposes + Reg#(Vector#(num, timeT)) timer <- mkConfigReg(replicate(0)); + Reg#(Vector#(num, Bool)) started <- mkConfigReg(replicate(False)); // for checking purposes RWire#(idxT) startEn <- mkRWire; RWire#(idxT) doneEn <- mkRWire; diff --git a/src_Core/RISCY_OOO/procs/lib/PhysRFile.bsv b/src_Core/RISCY_OOO/procs/lib/PhysRFile.bsv index 90c5d2d..d1e1f7a 100644 --- a/src_Core/RISCY_OOO/procs/lib/PhysRFile.bsv +++ b/src_Core/RISCY_OOO/procs/lib/PhysRFile.bsv @@ -47,6 +47,7 @@ import ProcTypes::*; import Vector::*; import Ehr::*; import ConfigReg::*; +import SpecialRegs::*; interface RFileWr#(type d); method Action wr( PhyRIndx rindx, d data ); @@ -73,7 +74,9 @@ module mkRFile#(d defaultRegisterValue, Bool lazy)( RFile#(wrNum, rdNum, d) ) pr // phy reg init val must be 0: because x0 is renamed to phy reg 0, // which must be 0 at all time - Vector#(NumPhyReg, Ehr#(ehrPortNum, d)) rfile <- replicateM(mkEhr(defaultRegisterValue)); + // Using a mkRegOR here assumes there will be a single write per register per cycle. + // As each register is allocated to a single instruction which will execute once, this should always be true. + Vector#(NumPhyReg, Vector#(ehrPortNum, Reg#(d))) rfile <- replicateM(mkRegOR(defaultRegisterValue)); Vector#(NumPhyReg, d) rdData = ?; if(lazy) begin diff --git a/src_Core/RISCY_OOO/procs/lib/ReorderBuffer.bsv b/src_Core/RISCY_OOO/procs/lib/ReorderBuffer.bsv index 1ca4aa7..0077457 100644 --- a/src_Core/RISCY_OOO/procs/lib/ReorderBuffer.bsv +++ b/src_Core/RISCY_OOO/procs/lib/ReorderBuffer.bsv @@ -756,6 +756,7 @@ module mkSupReorderBuffer#( // move deqP & reset valid deqP[i] <= getNextPtr(deqP[i]); valid[i][deqP[i]][valid_deq_port] <= False; + $display("deq[%d][%d]", i, deqP[i]); end end // update firstDeqWay: find the first deq port that is not enabled @@ -935,6 +936,9 @@ module mkSupReorderBuffer#( end endfunction for(Integer i = 0; i < valueof(SingleScalarSize); i = i+1) begin + if (in_kill_range(fromInteger(i)) != (row[w][i].dependsOn_wrongSpec(specTag) && valid[w][i][valid_wrongSpec_port])) + $display("enqP: %d, enqPNext: %d, w: %d, i: %d, wrongSpec: %d, valid: %d, cur_cycle: %d", + enqP[w], enqPNext[w], w, i, row[w][i].dependsOn_wrongSpec(specTag), valid[w][i][valid_wrongSpec_port], cur_cycle); doAssert( in_kill_range(fromInteger(i)) == (row[w][i].dependsOn_wrongSpec(specTag) && valid[w][i][valid_wrongSpec_port]), diff --git a/src_Core/RISCY_OOO/procs/lib/SpecFifo.bsv b/src_Core/RISCY_OOO/procs/lib/SpecFifo.bsv index 4e48188..bae699f 100644 --- a/src_Core/RISCY_OOO/procs/lib/SpecFifo.bsv +++ b/src_Core/RISCY_OOO/procs/lib/SpecFifo.bsv @@ -25,7 +25,7 @@ import ProcTypes::*; import HasSpecBits::*; import Vector::*; import Ehr::*; -import FIFOF::*; +import DReg::*; import Assert::*; import Types::*; import ConfigReg::*; @@ -168,7 +168,7 @@ module mkSpecFifo#( }; endmethod - method Bool notEmpty = (valid[deqP][sched.validDeqPort]); + method Bool notEmpty = valid[deqP][sched.validDeqPort]; interface SpeculationUpdate specUpdate; method Action correctSpeculation(SpecBits mask); @@ -224,8 +224,8 @@ module mkSpecFifoCF#( Vector#(size, Reg#(t)) row <- replicateM(mkConfigRegU); Ehr#(3, Vector#(size, SpecBits)) specBits <- mkEhr(?); - FIFOF#(SpecBits) correctSpecF <- mkUGFIFOF; - FIFOF#(IncorrectSpeculation) incorrectSpecF <- mkUGFIFOF; + Reg#(Maybe#(SpecBits)) correctSpec <- mkDReg(Invalid); + Reg#(Maybe#(IncorrectSpeculation)) incorrectSpec <- mkDReg(Invalid); Reg#(idxT) enqP <- mkConfigReg(0); Ehr#(2, idxT) deqP_ehr <- mkEhr(0); @@ -246,17 +246,13 @@ module mkSpecFifoCF#( Vector#(size, SpecBits) newSpecBits = specBits[0]; Vector#(size, Bool) newValid = valid[0]; // Fold in CorrectSpec update: - if (correctSpecF.notEmpty) begin - SpecBits mask = correctSpecF.first(); - correctSpecF.deq(); + if (correctSpec matches tagged Valid .mask) begin // clear spec bits for all entries for (Integer i=0; i> predCnt[i]; // get global prediction - Bool globalTaken = isTaken(globalBht.sub(globalHist)); + Bool globalTaken = globalTakenVec[predCnt[i]]; // make choice - Bool useLocal = isTaken(choiceBht.sub(globalHist)); + Bool useLocal = useLocalVec[predCnt[i]]; Bool taken = useLocal ? localTaken : globalTaken; // record prediction @@ -99,10 +107,11 @@ module mkTourPred(DirPredictor#(TourTrainInfo)); return DirPredResult { taken: taken, train: TourTrainInfo { - globalHist: globalHist, + globalHist: curGHist >> predCnt[i], localHist: localHist, globalTaken: globalTaken, - localTaken: localTaken + localTaken: localTaken, + pcIndex: pcIndex } }; endmethod @@ -112,20 +121,30 @@ module mkTourPred(DirPredictor#(TourTrainInfo)); (* fire_when_enabled, no_implicit_conditions *) rule canonGlobalHist; gHistReg.addHistory(predRes[valueof(SupSize)], predCnt[valueof(SupSize)]); + // Buffer useLocalVec + // Reproduce next history; this would ideally be done in GlobalBrHistReg to avoid duplicating logic. + TourGlobalHist nHist = truncate({predRes[valueof(SupSize)], curGHist} >> predCnt[valueof(SupSize)]); + function Bool globalTakenLookup (Integer i) = isTaken(globalBht.sub(nHist >> i)); + function Bool useLocalLookup (Integer i) = isTaken(choiceBht.sub(nHist >> i)); + globalTakenVec <= genWith(globalTakenLookup); + useLocalVec <= genWith(useLocalLookup); + // Reset counters and prediction. predRes[valueof(SupSize)] <= 0; predCnt[valueof(SupSize)] <= 0; endrule + method nextPc = pc_reg._write; + interface pred = predIfc; - method Action update(Addr pc, Bool taken, TourTrainInfo train, Bool mispred); + method Action update(Bool taken, TourTrainInfo train, Bool mispred); // update history if mispred if(mispred) begin TourGlobalHist newHist = truncateLSB({pack(taken), train.globalHist}); gHistReg.redirect(newHist); end // update local history (assume only 1 branch for an PC in flight) - localHistTab.upd(getPCIndex(pc), truncateLSB({pack(taken), train.localHist})); + localHistTab.upd(train.pcIndex, truncateLSB({pack(taken), train.localHist})); // update local sat cnt let localCnt = localBht.sub(train.localHist); localBht.upd(train.localHist, updateCnt(localCnt, taken)); diff --git a/src_Core/RISCY_OOO/procs/lib/TourPredSecure.bsv b/src_Core/RISCY_OOO/procs/lib/TourPredSecure.bsv index 9b472f3..d97b46f 100644 --- a/src_Core/RISCY_OOO/procs/lib/TourPredSecure.bsv +++ b/src_Core/RISCY_OOO/procs/lib/TourPredSecure.bsv @@ -33,3 +33,238 @@ // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. + +import Types::*; +import ProcTypes::*; +import RegFile::*; +import Ehr::*; +import Vector::*; +import GlobalBrHistReg::*; +import BrPred::*; +import TourPred::*; + +export mkTourPredSecure; + +// 4KB tournament predictor with flush methods for security +// XXX We DO NOT stall prediction or update methods when flushing to reduce +// logic. It is guaranteed outside that no prediction or update can happen when +// flushing. + +typedef 10 PCIndexSz; +typedef Bit#(PCIndexSz) PCIndex; + +// We group several sat counters/local hists together in order to flush faster +typedef 9 TabIndexSz; +typedef Bit#(TabIndexSz) TabIndex; + +// vector of local hists +typedef TSub#(PCIndexSz, TabIndexSz) LgLocalHistVecSz; +typedef TExp#(LgLocalHistVecSz) LocalHistVecSz; +typedef Bit#(LgLocalHistVecSz) LocalHistVecSelect; + +// vector of local bht sat counters +typedef TSub#(TourLocalHistSz, TabIndexSz) LgLocalBhtVecSz; +typedef TExp#(LgLocalBhtVecSz) LocalBhtVecSz; +typedef Bit#(LgLocalBhtVecSz) LocalBhtVecSelect; + +// vector of global bht sat counters and global choice sat counters +typedef TSub#(TourGlobalHistSz, TabIndexSz) LgGlobalVecSz; +typedef TExp#(LgGlobalVecSz) GlobalVecSz; +typedef Bit#(GlobalVecSz) GlobalVecSelect; + +typedef struct { + Bool taken; + TourTrainInfo train; + Bool mispred; +} TourUpdate deriving(Bits, Eq, FShow); + +(* synthesize *) +module mkTourPredSecure(DirPredictor#(TourTrainInfo)); + // FIXME: The regfile should be initialized (on FPGA, all 0 after programming) + // local history: MSB is the latest branch + RegFile#(TabIndex, Vector#(LocalHistVecSz, TourLocalHist)) localHistTab <- mkRegFileWCF(0, maxBound); + // local sat counters + RegFile#(TabIndex, Vector#(LocalBhtVecSz, Bit#(3))) localBht <- mkRegFileWCF(0, maxBound); + // global history reg + TourGHistReg gHistReg <- mkTourGHistReg; + // global sat counters + RegFile#(TabIndex, Vector#(GlobalVecSz, Bit#(2))) globalBht <- mkRegFileWCF(0, maxBound); + // choice sat counters: large (taken) -- use local, small (not taken) -- use global + RegFile#(TabIndex, Vector#(GlobalVecSz, Bit#(2))) choiceBht <- mkRegFileWCF(0, maxBound); + + // Lookup PC + Reg#(Addr) pc_reg <- mkRegU; + + // EHR to record predict results in this cycle + Ehr#(TAdd#(1, SupSize), SupCnt) predCnt <- mkEhr(0); + Ehr#(TAdd#(1, SupSize), Bit#(SupSize)) predRes <- mkEhr(0); + + RWire#(TourUpdate) updateEn <- mkRWire; + + // security flush + Reg#(Bool) flushDone <- mkReg(True); + Reg#(TabIndex) flushIndex <- mkReg(0); + + function PCIndex getPCIndex(Addr pc) = truncate(pc >> 2); + + function Tuple2#(TabIndex, LocalHistVecSelect) getPCIndices(PCIndex pcIdx); + TabIndex tabIdx = truncateLSB(pcIdx); + LocalHistVecSelect sel = truncate(pcIdx); + return tuple2(tabIdx, sel); + endfunction + + function Tuple2#(TabIndex, LocalBhtVecSelect) getLocalBhtIndex(TourLocalHist hist); + TabIndex idx = truncateLSB(hist); + LocalHistVecSelect sel = truncate(hist); + return tuple2(idx, sel); + endfunction + + function Tuple2#(TabIndex, GlobalVecSelect) getGlobalIndex(TourGlobalHist hist); + TabIndex idx = truncateLSB(hist); + GlobalVecSelect sel = truncate(hist); + return tuple2(idx, sel); + endfunction + + // common sat counter operations + function Bool isTaken(Bit#(n) cnt) provisos(Add#(1, a__, n)); + Bit#(1) msb = truncateLSB(cnt); + return msb == 1; + endfunction + + function Bit#(n) updateCnt(Bit#(n) cnt, Bool taken); + if(taken) begin + return cnt == maxBound ? maxBound : cnt + 1; + end + else begin + return cnt == 0 ? 0 : cnt - 1; + end + endfunction + + TourGlobalHist curGHist = gHistReg.history; // global history: MSB is the latest branch + + Vector#(SupSize, DirPred#(TourTrainInfo)) predIfc; + for(Integer i = 0; i < valueof(SupSize); i = i+1) begin + predIfc[i] = (interface DirPred; + method ActionValue#(DirPredResult#(TourTrainInfo)) pred; + // get local history + PCIndex pcIndex = getPCIndex(offsetPc(pc_reg, i)); + let {localHistTabIdx, localHistVecSel} = getPCIndices(pcIndex); + Vector#(LocalHistVecSz, TourLocalHist) localHistVec = localHistTab.sub(localHistTabIdx); + TourLocalHist localHist = localHistVec[localHistVecSel]; + // get local prediction + let {localBhtTabIdx, localBhtVecSel} = getLocalBhtIndex(localHist); + Vector#(LocalBhtVecSz, Bit#(3)) localBhtVec = localBht.sub(localBhtTabIdx); + Bool localTaken = isTaken(localBhtVec[localBhtVecSel]); + + // get the global history + // all previous branch in this cycle must be not taken + // otherwise this branch should be on wrong path + // because all inst in same cycle are fetched consecutively + TourGlobalHist globalHist = curGHist >> predCnt[i]; + // get global prediction + let {globalTabIdx, globalVecSel} = getGlobalIndex(globalHist); + Vector#(GlobalVecSz, Bit#(2)) globalBhtVec = globalBht.sub(globalTabIdx); + Bool globalTaken = isTaken(globalBhtVec[globalVecSel]); + + // make choice + Vector#(GlobalVecSz, Bit#(2)) choiceVec = choiceBht.sub(globalTabIdx); + Bool useLocal = isTaken(choiceVec[globalVecSel]); + Bool taken = useLocal ? localTaken : globalTaken; + + // record prediction + predCnt[i] <= predCnt[i] + 1; + Bit#(SupSize) res = predRes[i]; + res[predCnt[i]] = pack(taken); + predRes[i] <= res; + + // return + return DirPredResult { + taken: taken, + train: TourTrainInfo { + globalHist: globalHist, + localHist: localHist, + globalTaken: globalTaken, + localTaken: localTaken, + pcIndex: pcIndex + } + }; + endmethod + endinterface); + end + + (* fire_when_enabled, no_implicit_conditions *) + rule canonGlobalHist; + gHistReg.addHistory(predRes[valueof(SupSize)], predCnt[valueof(SupSize)]); + predRes[valueof(SupSize)] <= 0; + predCnt[valueof(SupSize)] <= 0; + endrule + + // no flush, accept update + (* fire_when_enabled, no_implicit_conditions *) + rule canonUpdate(flushDone &&& updateEn.wget matches tagged Valid .upd); + let taken = upd.taken; + let train = upd.train; + let mispred = upd.mispred; + + // update history if mispred + if(mispred) begin + TourGlobalHist newHist = truncateLSB({pack(taken), train.globalHist}); + gHistReg.redirect(newHist); + end + + // update local history (assume only 1 branch for an PC in flight) + let {localHistTabIdx, localHistVecSel} = getPCIndices(train.pcIndex); + Vector#(LocalHistVecSz, TourLocalHist) localHistVec = localHistTab.sub(localHistTabIdx); + localHistVec[localHistVecSel] = truncateLSB({pack(taken), train.localHist}); + localHistTab.upd(localHistTabIdx, localHistVec); + + // update local sat cnt + let {localBhtTabIdx, localBhtVecSel} = getLocalBhtIndex(train.localHist); + Vector#(LocalBhtVecSz, Bit#(3)) localBhtVec = localBht.sub(localBhtTabIdx); + Bit#(3) localCnt = localBhtVec[localBhtVecSel]; + localBhtVec[localBhtVecSel] = updateCnt(localCnt, taken); + localBht.upd(localBhtTabIdx, localBhtVec); + + // update global sat cnt + let {globalTabIdx, globalVecSel} = getGlobalIndex(train.globalHist); + Vector#(GlobalVecSz, Bit#(2)) globalBhtVec = globalBht.sub(globalTabIdx); + Bit#(2) globalCnt = globalBhtVec[globalVecSel]; + globalBhtVec[globalVecSel] = updateCnt(globalCnt, taken); + globalBht.upd(globalTabIdx, globalBhtVec); + + // update choice cnt + if(train.globalTaken != train.localTaken) begin + Vector#(GlobalVecSz, Bit#(2)) choiceVec = choiceBht.sub(globalTabIdx); + Bit#(2) choiceCnt = choiceVec[globalVecSel]; + Bool useLocal = train.localTaken == taken; + choiceVec[globalVecSel] = updateCnt(choiceCnt, useLocal); + choiceBht.upd(globalTabIdx, choiceVec); + end + endrule + + // flushing, drop update and flush table entries one by one + rule canonFlush(!flushDone); + localHistTab.upd(flushIndex, replicate(0)); + localBht.upd(flushIndex, replicate(0)); + globalBht.upd(flushIndex, replicate(0)); + choiceBht.upd(flushIndex, replicate(0)); + gHistReg.redirect(0); + flushIndex <= flushIndex + 1; + if (flushIndex == maxBound) begin + flushDone <= True; + end + endrule + + method nextPc = pc_reg._write; + + interface pred = predIfc; + + method Action update(Bool taken, TourTrainInfo train, Bool mispred); + updateEn.wset(TourUpdate {taken: taken, train: train, mispred: mispred}); + endmethod + + method Action flush if(flushDone); + flushDone <= False; + endmethod + method flush_done = flushDone._read; +endmodule diff --git a/src_Testbench/SoC/SoC_Top.bsv b/src_Testbench/SoC/SoC_Top.bsv index 3fbd43f..4bb7e24 100644 --- a/src_Testbench/SoC/SoC_Top.bsv +++ b/src_Testbench/SoC/SoC_Top.bsv @@ -204,7 +204,7 @@ module mkSoC_Top #(Reset dm_power_on_reset) route_vector[mem0_controller_slave_num] = soc_map.m_mem0_controller_addr_range; // Fabric to UART0 - slave_vector[uart0_slave_num] = zeroSlaveUserFields(uart0.slave); + slave_vector[uart0_slave_num] = zero_AXI4_Slave_user(uart0.slave); route_vector[uart0_slave_num] = soc_map.m_uart0_addr_range; `ifdef INCLUDE_ACCEL0