A Btb with 1/4 the storage that will (hopefully) infer as BRAM.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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});
|
||||
|
||||
Reference in New Issue
Block a user