Merge branch 'CHERI' into jdw57_prediction
This commit is contained in:
Submodule libs/BlueStuff updated: df2529dd42...a6e2273920
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user