A Btb with 1/4 the storage that will (hopefully) infer as BRAM.

This commit is contained in:
jon
2021-03-05 12:14:26 +00:00
parent 7aea0325fc
commit 4b411bf752
2 changed files with 66 additions and 45 deletions

View File

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

View File

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