Merge branch 'CHERI' into jdw57_prediction

This commit is contained in:
Jonathan Woodruff
2022-02-16 10:10:00 +00:00
22 changed files with 535 additions and 205 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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]),

View File

@@ -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<valueOf(size); i=i+1)
newSpecBits[i] = newSpecBits[i] & mask;
end
// Fold in IncorrectSpec update:
if (incorrectSpecF.notEmpty) begin
IncorrectSpeculation incSpec = incorrectSpecF.first();
incorrectSpecF.deq();
if (incorrectSpec matches tagged Valid .incSpec) begin
// clear entries
for (Integer i=0; i<valueOf(size); i=i+1)
if(incSpec.kill_all || newSpecBits[i][incSpec.specTag] == 1'b1)
@@ -316,12 +312,12 @@ module mkSpecFifoCF#(
};
endmethod
method Bool notEmpty = (valid[1][deqP]);
method Bool notEmpty = valid[1][deqP];
interface SpeculationUpdate specUpdate;
method correctSpeculation = correctSpecF.enq;
method correctSpeculation(mask) = correctSpec._write(Valid(mask));
method incorrectSpeculation(kill_all, specTag) =
incorrectSpecF.enq(IncorrectSpeculation{kill_all: kill_all, specTag: specTag});
incorrectSpec._write(Valid(IncorrectSpeculation{kill_all: kill_all, specTag: specTag}));
endinterface
endmodule
@@ -437,8 +433,8 @@ module mkSearchableSpecFifoCF#(
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);
@@ -459,17 +455,13 @@ module mkSearchableSpecFifoCF#(
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<valueOf(size); i=i+1)
newSpecBits[i] = newSpecBits[i] & mask;
end
// Fold in IncorrectSpec update:
if (incorrectSpecF.notEmpty) begin
IncorrectSpeculation incSpec = incorrectSpecF.first();
incorrectSpecF.deq();
if (incorrectSpec matches tagged Valid .incSpec) begin
// clear entries
for (Integer i=0; i<valueOf(size); i=i+1)
if(incSpec.kill_all || newSpecBits[i][incSpec.specTag] == 1'b1)
@@ -540,8 +532,8 @@ module mkSearchableSpecFifoCF#(
endmethod
interface SpeculationUpdate specUpdate;
method correctSpeculation = correctSpecF.enq;
method correctSpeculation(mask) = correctSpec._write(Valid(mask));
method incorrectSpeculation(kill_all, specTag) =
incorrectSpecF.enq(IncorrectSpeculation{kill_all: kill_all, specTag: specTag});
incorrectSpec._write(Valid(IncorrectSpeculation{kill_all: kill_all, specTag: specTag}));
endinterface
endmodule

View File

@@ -51,6 +51,7 @@ import StoreBuffer::*;
import Exec::*;
import FP_Utils::*;
import CacheUtils::*; // For CLoadTags alignment
import RegFile::*; // Just for the interface
// I don't want to export auxiliary functions, so manually export all types
export LdQMemFunc(..);
@@ -439,6 +440,8 @@ interface SplitLSQ;
// Sc/Amo/Fence, and flush L1 cache.
method StQDeqEntry firstSt;
method Action deqSt;
// method for reporting the physical address of an entry used for tracing.
interface Vector#(SupSize, RegFile#(LdStQTag, Addr)) lookupPAddr;
`ifdef TSO_MM
// Kill loads when a cache line is evicted (TSO only)
method Action cacheEvict(LineAddr a);
@@ -949,17 +952,7 @@ module mkSplitLSQ(SplitLSQ);
// make wrongSpec conflict with all others (but not correctSpec method and
// findIssue)
RWire#(void) wrongSpec_hit_conflict <- mkRWire;
RWire#(void) wrongSpec_enqIss_conflict <- mkRWire;
RWire#(void) wrongSpec_enq_conflict <- mkRWire;
RWire#(void) wrongSpec_cacheEvict_conflict <- mkRWire;
RWire#(void) wrongSpec_update_conflict <- mkRWire;
RWire#(void) wrongSpec_issue_conflict <- mkRWire;
RWire#(void) wrongSpec_respLd_conflict <- mkRWire;
RWire#(void) wrongSpec_deqLd_conflict <- mkRWire;
RWire#(void) wrongSpec_deqSt_conflict <- mkRWire;
RWire#(void) wrongSpec_verify_conflict <- mkRWire;
RWire#(void) wrongSpec_wakeBySB_conflict <- mkRWire;
PulseWire wrongSpec_conflict <- mkPulseWire;
// make wrongSpec more urgent than firstSt (resolve bsc error)
Wire#(Bool) wrongSpec_urgent_firstSt <- mkDWire(True);
Map#(Bit#(10),Bit#(6),Int#(3),2) ldKillMap <- mkMapLossy(minBound);
@@ -1145,7 +1138,7 @@ module mkSplitLSQ(SplitLSQ);
end
endrule
rule enqIssueQ(issueLdInfo.wget matches tagged Valid .info);
rule enqIssueQ(issueLdInfo.wget matches tagged Valid .info &&& !wrongSpec_conflict);
if(verbose) begin
$display("[LSQ - enqIss] ", fshow(info));
end
@@ -1187,8 +1180,6 @@ module mkSplitLSQ(SplitLSQ);
spec_bits: ld_specBits_enqIss[info.tag]
});
ld_inIssueQ_enqIss[info.tag] <= True;
// make conflict with incorrect spec
wrongSpec_enqIss_conflict.wset(?);
endrule
// Verify SQ entry one by one
@@ -1211,7 +1202,8 @@ module mkSplitLSQ(SplitLSQ);
// NOTE that when SQ is full and all verified, verifyP will point to a
// valid and verified entry
rule verifySt(st_valid_verify[st_verifyP_verify] &&
!st_verified_verify[st_verifyP_verify]);
!st_verified_verify[st_verifyP_verify] &&
!wrongSpec_conflict);
StQTag verP = st_verifyP_verify;
// check if the entry can be verified. We should not fire this rule if
@@ -1261,9 +1253,6 @@ module mkSplitLSQ(SplitLSQ);
joinActions(map(setVerified, idxVec));
if(verbose) $display("[LSQ - verifySt] st_verifyP %d", verP);
// make conflict with incorrect spec
wrongSpec_verify_conflict.wset(?);
endrule
`ifdef BSIM
@@ -1429,6 +1418,16 @@ module mkSplitLSQ(SplitLSQ);
endinterface);
end
RegFile#(LdStQTag, Addr) lookupAPAddr = (interface RegFile;
method Addr sub(LdStQTag t);
case (t) matches
tagged Ld .l: return ld_paddr_deqLd[l];
tagged St .s: return st_paddr_deqSt[s];
endcase
endmethod
method upd = ?;
endinterface);
method ByteOrTagEn getOrigBE(LdStQTag t);
return (case(t) matches
tagged Ld .tag: (ld_byteOrTagEn[tag]);
@@ -1437,10 +1436,7 @@ module mkSplitLSQ(SplitLSQ);
endcase);
endmethod
method ActionValue#(LSQHitInfo) getHit(LdStQTag t);
// Conflict with wrong spec. This makes cache pipelineResp rule
// conflict with wrong spec, and can help avoid scheduling cycle.
wrongSpec_hit_conflict.wset(?);
method ActionValue#(LSQHitInfo) getHit(LdStQTag t) if (!wrongSpec_conflict);
return (case(t) matches
tagged Ld .tag: (LSQHitInfo {
waitWPResp: ld_waitWPResp_hit[tag],
@@ -1465,7 +1461,7 @@ module mkSplitLSQ(SplitLSQ);
MemInst mem_inst,
Maybe#(PhyDst) dst,
SpecBits spec_bits,
Bit#(16) pc_hash) if(ld_can_enq_wire);
Bit#(16) pc_hash) if(ld_can_enq_wire && !wrongSpec_conflict);
if(verbose) begin
$display("[LSQ - enqLd] enqP %d; ", ld_enqP,
"; ", fshow(inst_tag),
@@ -1518,14 +1514,12 @@ module mkSplitLSQ(SplitLSQ);
ld_olderSt_enq[ld_enqP] <= Invalid;
ld_olderStVerified_enq[ld_enqP] <= False;
end
// make conflict with incorrect spec
wrongSpec_enq_conflict.wset(?);
endmethod
method Action enqSt(InstTag inst_tag,
MemInst mem_inst,
Maybe#(PhyDst) dst,
SpecBits spec_bits) if(st_can_enq_wire);
SpecBits spec_bits) if(st_can_enq_wire && !wrongSpec_conflict);
if(verbose) begin
$display("[LSQ - enqSt] enqP %d; ", st_enqP,
"; ", fshow(inst_tag),
@@ -1554,8 +1548,6 @@ module mkSplitLSQ(SplitLSQ);
st_verified_enq[st_enqP] <= False;
st_specBits_enq[st_enqP] <= spec_bits;
st_atCommit_enq[st_enqP] <= False;
// make conflict with incorrect spec
wrongSpec_enq_conflict.wset(?);
endmethod
method Action updateData(StQTag t, MemTaggedData d);
@@ -1570,7 +1562,7 @@ module mkSplitLSQ(SplitLSQ);
method ActionValue#(LSQUpdateAddrResult) updateAddr(
LdStQTag lsqTag, Maybe#(Trap) fault,
Bool allowCap, Addr pa, Bool mmio, ByteOrTagEn shift_be
);
) if (!wrongSpec_conflict);
// index vec for vector functions
Vector#(LdQSize, LdQTag) idxVec = genWith(fromInteger);
@@ -1736,9 +1728,6 @@ module mkSplitLSQ(SplitLSQ);
end
end
// make conflict with incorrect spec
wrongSpec_update_conflict.wset(?);
// return waiting for wp resp bit: for deciding whether the updating Ld
// can be issued
return LSQUpdateAddrResult {
@@ -1753,7 +1742,7 @@ module mkSplitLSQ(SplitLSQ);
method ActionValue#(LSQIssueLdResult) issueLd(LdQTag tag,
Addr pa,
ByteOrTagEn shift_be,
SBSearchRes sbRes);
SBSearchRes sbRes) if (!wrongSpec_conflict);
if(verbose) begin
$display("[LSQ - issueLd] ", fshow(tag), "; ", fshow(pa),
"; ", fshow(shift_be), "; ", fshow(sbRes));
@@ -2022,9 +2011,6 @@ module mkSplitLSQ(SplitLSQ);
end
`endif
// make conflict with incorrect spec
wrongSpec_issue_conflict.wset(?);
return issRes;
endmethod
@@ -2041,7 +2027,7 @@ module mkSplitLSQ(SplitLSQ);
return issueLdQ.first.data;
endmethod
method ActionValue#(LSQRespLdResult) respLd(LdQTag t, MemTaggedData alignedData);
method ActionValue#(LSQRespLdResult) respLd(LdQTag t, MemTaggedData alignedData) if (!wrongSpec_conflict);
let res = LSQRespLdResult {
wrongPath: False,
dst: Invalid,
@@ -2090,8 +2076,6 @@ module mkSplitLSQ(SplitLSQ);
$display("[LSQ - respLd] ", fshow(t), "; ", fshow(alignedData),
"; ", fshow(res));
end
// make conflict with incorrect spec
wrongSpec_respLd_conflict.wset(?);
// return
return res;
endmethod
@@ -2116,7 +2100,7 @@ module mkSplitLSQ(SplitLSQ);
};
endmethod
method Action deqLd if(deqLdGuard);
method Action deqLd if(deqLdGuard && !wrongSpec_conflict);
LdQTag deqP = ld_deqP_deqLd;
if(verbose) $display("[LSQ - deqLd] deqP %d", deqP);
@@ -2163,9 +2147,6 @@ module mkSplitLSQ(SplitLSQ);
endfunction
Vector#(LdQSize, LdQTag) idxVec = genWith(fromInteger);
joinActions(map(setReady, idxVec));
// make conflict with incorrect spec
wrongSpec_deqLd_conflict.wset(?);
endmethod
method StQDeqEntry firstSt if(deqStGuard && wrongSpec_urgent_firstSt);
@@ -2186,7 +2167,7 @@ module mkSplitLSQ(SplitLSQ);
};
endmethod
method Action deqSt if(deqStGuard);
method Action deqSt if(deqStGuard && !wrongSpec_conflict);
StQTag deqP = st_deqP;
if(verbose) $display("[LSQ - deqSt] deqP %d", deqP);
@@ -2234,13 +2215,12 @@ module mkSplitLSQ(SplitLSQ);
endfunction
Vector#(LdQSize, LdQTag) idxVec = genWith(fromInteger);
joinActions(map(resetSt, idxVec));
// make conflict with incorrect spec
wrongSpec_deqSt_conflict.wset(?);
endmethod
interface lookupPAddr = replicate(lookupAPAddr);
`ifdef TSO_MM
method Action cacheEvict(LineAddr lineAddr);
method Action cacheEvict(LineAddr lineAddr) if (!wrongSpec_conflict);
if(verbose) $display("[LSQ - cacheEvict] ", fshow(lineAddr));
// kill a load if it satisfies the following conditions:
// (1) valid
@@ -2270,14 +2250,11 @@ module mkSplitLSQ(SplitLSQ);
doAssert(!ld_isMMIO_evict[killTag], "cannot kill MMIO");
doAssert(ld_memFunc[killTag] == Ld, "can only kill Ld");
end
// make conflict with incorrect spec
wrongSpec_cacheEvict_conflict.wset(?);
endmethod
`else
method Action wakeupLdStalledBySB(SBIndex sbIdx);
method Action wakeupLdStalledBySB(SBIndex sbIdx) if (!wrongSpec_conflict);
if(verbose) begin
$display("[LSQ - wakeupBySB] ", fshow(sbIdx));
end
@@ -2292,8 +2269,6 @@ module mkSplitLSQ(SplitLSQ);
endfunction
Vector#(LdQSize, LdQTag) idxVec = genWith(fromInteger);
joinActions(map(setReady, idxVec));
// make conflict with incorrect spec
wrongSpec_wakeBySB_conflict.wset(?);
endmethod
`endif
@@ -2438,17 +2413,7 @@ module mkSplitLSQ(SplitLSQ);
end
// make conflict with others
wrongSpec_hit_conflict.wset(?);
wrongSpec_enqIss_conflict.wset(?);
wrongSpec_enq_conflict.wset(?);
wrongSpec_update_conflict.wset(?);
wrongSpec_issue_conflict.wset(?);
wrongSpec_respLd_conflict.wset(?);
wrongSpec_deqLd_conflict.wset(?);
wrongSpec_deqSt_conflict.wset(?);
wrongSpec_verify_conflict.wset(?);
wrongSpec_cacheEvict_conflict.wset(?);
wrongSpec_wakeBySB_conflict.wset(?);
wrongSpec_conflict.send();
// more urgent than firstSt
wrongSpec_urgent_firstSt <= True;
endmethod

View File

@@ -14,6 +14,8 @@ export TourTrainInfo(..);
export TourGHistReg(..);
export mkTourGHistReg;
export mkTourPred;
export PCIndexSz;
export PCIndex;
// 4KB tournament predictor
@@ -30,6 +32,7 @@ typedef struct {
TourLocalHist localHist;
Bool globalTaken;
Bool localTaken;
PCIndex pcIndex;
} TourTrainInfo deriving(Bits, Eq, FShow);
// global history reg
@@ -54,6 +57,9 @@ module mkTourPred(DirPredictor#(TourTrainInfo));
// choice sat counters: large (taken) -- use local, small (not taken) -- use global
RegFile#(TourGlobalHist, Int#(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);
@@ -68,25 +74,27 @@ module mkTourPred(DirPredictor#(TourTrainInfo));
boundedPlus(cnt, (taken) ? 1 : -1);
TourGlobalHist curGHist = gHistReg.history; // global history: MSB is the latest branch
Reg#(Vector#(SupSize, Bool)) globalTakenVec <- mkRegU;
Reg#(Vector#(SupSize, Bool)) useLocalVec <- mkRegU;
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(Addr pc);
method ActionValue#(DirPredResult#(TourTrainInfo)) pred;
PCIndex pcIndex = getPCIndex(offsetPc(pc_reg, i));
// get local history & prediction
TourLocalHist localHist = localHistTab.sub(getPCIndex(pc));
TourLocalHist localHist = localHistTab.sub(pcIndex);
Bool localTaken = isTaken(localBht.sub(localHist));
// 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
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));

View File

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

View File

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