From 4b411bf752d0c6d78e33c2743bf5933f6b797a5b Mon Sep 17 00:00:00 2001 From: jon <> Date: Fri, 5 Mar 2021 12:14:26 +0000 Subject: [PATCH] A Btb with 1/4 the storage that will (hopefully) infer as BRAM. --- .../RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv | 22 ++--- src_Core/RISCY_OOO/procs/lib/Btb.bsv | 89 ++++++++++++------- 2 files changed, 66 insertions(+), 45 deletions(-) diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv index f576bfd..423e84d 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv @@ -343,7 +343,7 @@ module mkFetchStage(FetchStage); // We stall until the flush is done Ehr#(3, Bool) waitForFlush <- mkEhr(False); - Ehr#(4, CapMem) pc_reg <- mkEhr(nullCap); + Ehr#(5, CapMem) pc_reg <- mkEhr(nullCap); `ifdef RVFI_DII Ehr#(4, Dii_Parcel_Id) dii_pid_reg <- mkEhr(0); `endif @@ -351,6 +351,7 @@ module mkFetchStage(FetchStage); Integer pc_decode_port = 1; Integer pc_fetch3_port = 2; Integer pc_redirect_port = 3; + Integer pc_final_port = 4; // PC compression structure holding an indexed set of PC blocks so that only indexes need be tracked. IndexedMultiset#(PcIdx, PcMSB, SupSizeX2) pcBlocks <- mkIndexedMultisetQueue; @@ -414,6 +415,10 @@ module mkFetchStage(FetchStage); endrule `endif + rule updatePcInBtb; + nextAddrPred.put_pc(pc_reg[pc_final_port]); + endrule + // 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 @@ -421,14 +426,9 @@ module mkFetchStage(FetchStage); rule doFetch1(started && !(waitForRedirect[0]) && !(waitForFlush[0])); let pc = pc_reg[pc_fetch1_port]; - // 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#(SupSizeX2, Maybe#(CapMem)) pred_future_pc; - for(Integer i = 0; i < valueof(SupSizeX2); i = i+1) begin - pred_future_pc[i] = nextAddrPred.pred[i].predPc(addPc(pc, fromInteger(2 * i))); - end + // Grab a chain of predictions from the BTB, which predicts targets for the next + // set of addresses based on the current PC. + Vector#(SupSizeX2, Maybe#(CapMem)) pred_future_pc = nextAddrPred.pred; // Next pc is the first nextPc that breaks the chain of pc+4 or // that is at the end of a cacheline. @@ -467,7 +467,7 @@ module mkFetchStage(FetchStage); main_epoch: f_main_epoch}; f12f2.enq(out); - if (verbose) $display("Fetch1: ", fshow(out), " posLastSupX2: %d", posLastSupX2); + if (verbose) $display("%d Fetch1: ", cur_cycle, fshow(out), " posLastSupX2: %d", posLastSupX2); endrule rule doFetch2; @@ -749,7 +749,7 @@ module mkFetchStage(FetchStage); // check previous mispred if (nextPc matches tagged Valid .decode_pred_next_pc &&& (decode_pred_next_pc != ppc)) begin - if (verbose) $display("ppc and decodeppc : %h %h", ppc, decode_pred_next_pc); + if (verbose) $display("%x: ppc and decodeppc : %h %h", pc, ppc, decode_pred_next_pc); decode_epoch_local = !decode_epoch_local; redirectPc = Valid (decode_pred_next_pc); // record redirect next pc `ifdef RVFI_DII diff --git a/src_Core/RISCY_OOO/procs/lib/Btb.bsv b/src_Core/RISCY_OOO/procs/lib/Btb.bsv index 4711e68..1694826 100644 --- a/src_Core/RISCY_OOO/procs/lib/Btb.bsv +++ b/src_Core/RISCY_OOO/procs/lib/Btb.bsv @@ -43,16 +43,12 @@ import Vector::*; import CHERICC_Fat::*; import CHERICap::*; -export PredPcIfc(..); export NextAddrPred(..); export mkBtb; -interface PredPcIfc; - method Maybe#(CapMem) predPc(CapMem pc); -endinterface - interface NextAddrPred; - interface Vector#(SupSizeX2, PredPcIfc) pred; + method Action put_pc(CapMem pc); + interface Vector#(SupSizeX2, Maybe#(CapMem)) pred; method Action update(CapMem pc, CapMem brTarget, Bool taken); // security method Action flush; @@ -62,8 +58,15 @@ endinterface // Local BTB Typedefs typedef 1 PcLsbsIgnore; typedef 256 BtbEntries; // 4KB BTB -typedef Bit#(TLog#(BtbEntries)) BtbIndex; +typedef Bit#(TLog#(SupSizeX2)) BtbBank; +typedef TDiv#(BtbEntries,SupSizeX2) BtbIndices; +typedef Bit#(TLog#(BtbIndices)) BtbIndex; typedef Bit#(TSub#(TSub#(AddrSz, TLog#(BtbEntries)), PcLsbsIgnore)) BtbTag; +typedef struct { + BtbTag tag; + BtbIndex index; + BtbBank bank; +} BtbAddr deriving(Bits, Eq, FShow); typedef struct { CapMem pc; @@ -71,13 +74,20 @@ typedef struct { Bool taken; } BtbUpdate deriving(Bits, Eq, FShow); +typedef struct { + BtbTag tag; + CapMem nextPc; +} BtbRecord deriving(Bits, Eq, FShow); + (* synthesize *) module mkBtb(NextAddrPred); // Read and Write ordering doesn't matter since this is a predictor // mkRegFileWCF is the RegFile version of mkConfigReg - Vector#(SupSizeX2, RegFile#(BtbIndex, CapMem)) next_addrs <- replicateM(mkRegFileWCF(0,fromInteger(valueOf(BtbEntries)-1))); - Vector#(SupSizeX2, RegFile#(BtbIndex, BtbTag)) tags <- replicateM(mkRegFileWCF(0,fromInteger(valueOf(BtbEntries)-1))); - Vector#(BtbEntries, Reg#(Bool)) valid <- replicateM(mkConfigReg(False)); + Reg#(BtbTag) tag_reg <- mkRegU; + Reg#(BtbBank) firstBank_reg <- mkRegU; + Vector#(SupSizeX2, Reg#(BtbIndex)) idxs_reg <- replicateM(mkRegU); + Vector#(SupSizeX2, RegFile#(BtbIndex, BtbRecord)) records <- replicateM(mkRegFileWCF(0,~0)); + Vector#(SupSizeX2, Vector#(BtbIndices, Reg#(Bool))) valid <- replicateM(replicateM(mkConfigReg(False))); RWire#(BtbUpdate) updateEn <- mkRWire; @@ -87,8 +97,10 @@ module mkBtb(NextAddrPred); Bool flushDone = True; `endif - function BtbIndex getIndex(CapMem pc) = truncate(getAddr(pc) >> valueof(PcLsbsIgnore)); - function BtbTag getTag(CapMem pc) = truncateLSB(getAddr(pc)); + function BtbAddr getBtbAddr(CapMem pc) = unpack(truncateLSB(getAddr(pc))); + function BtbBank getBank(CapMem pc) = getBtbAddr(pc).bank; + function BtbIndex getIndex(CapMem pc) = getBtbAddr(pc).index; + function BtbTag getTag(CapMem pc) = getBtbAddr(pc).tag; // no flush, accept update (* fire_when_enabled, no_implicit_conditions *) @@ -99,41 +111,50 @@ module mkBtb(NextAddrPred); let index = getIndex(pc); let tag = getTag(pc); + let bank = getBank(pc); + $display("cap: %x, btbaddr: ", pc, fshow(getBtbAddr(pc)), " nextPc:%x", nextPc); if(taken) begin - valid[index] <= True; - for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) begin - tags[i].upd(index, tag); - next_addrs[i].upd(index, nextPc); - end - end else if( tags[0].sub(index) == tag ) begin + valid[bank][index] <= True; + records[bank].upd(index, BtbRecord{tag: tag, nextPc: nextPc}); + end else if(records[bank].sub(index).tag == tag ) begin // current instruction has target in btb, so clear it - valid[index] <= False; + valid[bank][index] <= False; + records[bank].upd(index, BtbRecord{tag: {4'ha,0}, nextPc: nextPc}); // An invalid virtual address. end endrule `ifdef SECURITY // flush, clear everything (and drop update) rule doFlush(!flushDone); - writeVReg(valid, replicate(False)); + for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) writeVReg(valid[i], replicate(False)); flushDone <= True; endrule `endif - Vector#(SupSizeX2, PredPcIfc) predPcs; - for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) begin - predPcs[i] = interface PredPcIfc; - method Maybe#(CapMem) predPc(CapMem pc); - BtbIndex index = getIndex(pc); - BtbTag tag = getTag(pc); - if(valid[index] && tag == tags[i].sub(index)) - return tagged Valid next_addrs[i].sub(index); - else - return tagged Invalid; - endmethod - endinterface; - end + method Action put_pc(CapMem pc); + BtbAddr addr = getBtbAddr(pc); + tag_reg <= addr.tag; + firstBank_reg <= addr.bank; + for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) begin + BtbAddr a = unpack(pack(addr) + fromInteger(i)); + $display("put pc[%d]: ", i, fshow(a)); + idxs_reg[a.bank] <= a.index; + end + endmethod - method pred = predPcs; + method Vector#(SupSizeX2, Maybe#(CapMem)) pred; + Vector#(SupSizeX2, Maybe#(BtbRecord)) recs = ?; + for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1) + recs[i] = (valid[i][idxs_reg[i]]) ? Valid(records[i].sub(idxs_reg[i])):Invalid; + function Maybe#(CapMem) tagHit(Maybe#(BtbRecord) br) = + case (br) matches + tagged Valid .b &&& (tag_reg == b.tag): return Valid(b.nextPc); + tagged Invalid: return Invalid; + endcase; + Vector#(SupSizeX2, Maybe#(CapMem)) ppcs = map(tagHit,recs); + ppcs = rotateBy(ppcs,unpack(-firstBank_reg)); // 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});