Don't decode redirected streams until they are non-speculative.
This commit is contained in:
@@ -89,7 +89,7 @@ BSC_COMPILATION_FLAGS += \
|
||||
-D RISCV \
|
||||
-D PERFORMANCE_MONITORING \
|
||||
-D RAS_HIT_TRACING \
|
||||
-D TSO_MM \
|
||||
-D TSO_MM -D NO_SPEC_TRAINING -D NO_SPEC_REDIRECT \
|
||||
-keep-fires -aggressive-conditions -no-warn-action-shadowing -check-assert \
|
||||
-suppress-warnings G0020 -steps-max-intervals 10000000 \
|
||||
-steps-warn-interval 1000000 \
|
||||
|
||||
@@ -353,7 +353,8 @@ module mkCore#(CoreId coreId)(Core);
|
||||
end
|
||||
GlobalSpecUpdate#(CorrectSpecPortNum, ConflictWrongSpecPortNum) globalSpecUpdate <- mkGlobalSpecUpdate(
|
||||
joinSpeculationUpdate(
|
||||
append(append(append(vec(regRenamingTable.specUpdate,
|
||||
append(append(append(vec(fetchStage.specUpdate,
|
||||
regRenamingTable.specUpdate,
|
||||
specTagManager.specUpdate,
|
||||
fix.memExeIfc.specUpdate), aluSpecUpdate), fpuMulDivSpecUpdate), btqSpecUpdate)
|
||||
),
|
||||
@@ -417,15 +418,16 @@ module mkCore#(CoreId coreId)(Core);
|
||||
method setRegReadyAggr = writeAggr(aluWrAggrPort(i));
|
||||
interface sendBypass = sendBypassIfc;
|
||||
method writeRegFile = writeCons(aluWrConsPort(i));
|
||||
method Action redirect(CapMem new_pc, SpecTag spec_tag, InstTag inst_tag);
|
||||
method Action redirect(CapMem new_pc, SpecTag spec_tag, InstTag inst_tag, SpecBits spec_bits);
|
||||
if (verbose) begin
|
||||
$display("[ALU redirect - %d] ", i, fshow(new_pc),
|
||||
"; ", fshow(spec_tag), "; ", fshow(inst_tag));
|
||||
end
|
||||
epochManager.incrementEpoch;
|
||||
fetchStage.redirect(new_pc
|
||||
fetchStage.redirect(new_pc,
|
||||
spec_bits
|
||||
`ifdef RVFI_DII
|
||||
, inst_tag.dii_next_pid
|
||||
, inst_tag.dii_next_pid
|
||||
`endif
|
||||
);
|
||||
globalSpecUpdate.incorrectSpec(False, spec_tag, inst_tag);
|
||||
@@ -1447,7 +1449,7 @@ module mkCore#(CoreId coreId)(Core);
|
||||
l2Tlb.updateVMInfo(vmI, vmD);
|
||||
|
||||
let startpc = csrf.dpc_read;
|
||||
fetchStage.redirect (cast(startpc));
|
||||
fetchStage.redirect (cast(startpc), 0);
|
||||
renameStage.debug_resume;
|
||||
commitStage.debug_resume;
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ interface AluExeInput;
|
||||
// write reg file & set conservative sb
|
||||
method Action writeRegFile(PhyRIndx dst, CapPipe data);
|
||||
// redirect
|
||||
method Action redirect(CapMem new_pc, SpecTag spec_tag, InstTag inst_tag);
|
||||
method Action redirect(CapMem new_pc, SpecTag spec_tag, InstTag inst_tag, SpecBits spec_bits);
|
||||
// spec update
|
||||
method Action correctSpec(SpecTag t);
|
||||
|
||||
@@ -484,7 +484,7 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline);
|
||||
if (x.controlFlow.mispredict) (* nosplit *) begin
|
||||
// wrong branch predictin, we must have spec tag
|
||||
doAssert(isValid(x.spec_tag), "mispredicted branch must have spec tag");
|
||||
inIfc.redirect(cast(x.controlFlow.nextPc), validValue(x.spec_tag), x.tag);
|
||||
inIfc.redirect(cast(x.controlFlow.nextPc), validValue(x.spec_tag), x.tag, exeToFin.spec_bits);
|
||||
// must be a branch, train branch predictor
|
||||
doAssert(x.iType == Jr || x.iType == CJALR || x.iType == CCall || x.iType == Br, "only jr, br, cjalr, and ccall can mispredict");
|
||||
inIfc.fetch_train_predictors(ToSpecFifo {
|
||||
|
||||
@@ -118,7 +118,9 @@ interface CommitInput;
|
||||
method Action setReconcileD; // recocile D$
|
||||
// redirect
|
||||
method Action killAll;
|
||||
method Action redirectPc(CapMem trap_pc
|
||||
method Action redirectPc(
|
||||
CapMem trap_pc,
|
||||
SpecBits specBits
|
||||
`ifdef RVFI_DII
|
||||
, Dii_Parcel_Id dii_pid
|
||||
`endif
|
||||
@@ -157,6 +159,13 @@ typedef struct {
|
||||
SpecBits specBits;
|
||||
} RenameErrInfo deriving(Bits, Eq, FShow);
|
||||
|
||||
typedef struct {
|
||||
CapMem trap_pc;
|
||||
`ifdef RVFI_DII
|
||||
Dii_Parcel_Id dii_pid;
|
||||
`endif
|
||||
} RedirectInfo deriving(Bits, Eq, FShow);
|
||||
|
||||
interface CommitStage;
|
||||
// performance
|
||||
method Data getPerf(ComStagePerfType t);
|
||||
@@ -519,6 +528,8 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
// cycle handles trap, redirect and handles system consistency
|
||||
Reg#(Maybe#(CommitTrap)) commitTrap <- mkReg(Invalid); // saves new pc here
|
||||
|
||||
FIFO#(RedirectInfo) redirectQ <- mkFIFO;
|
||||
|
||||
// maintain system consistency when system state (CSR) changes or for security
|
||||
function Action makeSystemConsistent(Bool flushTlb,
|
||||
Bool flushSecurity,
|
||||
@@ -780,11 +791,11 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
// trap handling & redirect
|
||||
let trap_updates <- csrf.trap(trap.trap, cast(trap.pc), trap.addr, trap.orig_inst);
|
||||
CapPipe new_pc = cast(trap_updates.new_pcc);
|
||||
inIfc.redirectPc(cast(new_pc)
|
||||
redirectQ.enq(RedirectInfo{trap_pc: cast(new_pc)
|
||||
`ifdef RVFI_DII
|
||||
, trap.x.dii_pid + (is_16b_inst(trap.orig_inst) ? 1 : 2)
|
||||
, dii_pid: trap.x.dii_pid + (is_16b_inst(trap.orig_inst) ? 1 : 2)
|
||||
`endif
|
||||
);
|
||||
});
|
||||
`ifdef RVFI
|
||||
Rvfi_Traces rvfis = replicate(tagged Invalid);
|
||||
rvfis[0] = genRVFI(trap.x, traceCnt, getTSB(), getAddr(new_pc));
|
||||
@@ -825,11 +836,11 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
|
||||
// kill everything, redirect, and increment epoch
|
||||
inIfc.killAll;
|
||||
inIfc.redirectPc(x.pc
|
||||
`ifdef RVFI_DII
|
||||
, x.dii_pid
|
||||
`endif
|
||||
);
|
||||
redirectQ.enq(RedirectInfo{trap_pc: x.pc
|
||||
`ifdef RVFI_DII
|
||||
, dii_pid: x.dii_pid
|
||||
`endif
|
||||
});
|
||||
inIfc.incrementEpoch;
|
||||
|
||||
// the killed Ld should have claimed phy reg, we should not commit it;
|
||||
@@ -945,11 +956,12 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
m_ret_updates = tagged Valid ret_updates;
|
||||
`endif
|
||||
end
|
||||
inIfc.redirectPc(next_pc
|
||||
`ifdef RVFI_DII
|
||||
, x.dii_pid + (is_16b_inst(x.orig_inst) ? 1 : 2)
|
||||
`endif
|
||||
);
|
||||
redirectQ.enq(RedirectInfo{trap_pc: next_pc
|
||||
`ifdef RVFI_DII
|
||||
, x.dii_pid + (is_16b_inst(x.orig_inst) ? 1 : 2)
|
||||
`endif
|
||||
});
|
||||
|
||||
|
||||
`ifdef RVFI
|
||||
Rvfi_Traces rvfis = replicate(tagged Invalid);
|
||||
@@ -1343,6 +1355,15 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
|
||||
`endif
|
||||
endrule
|
||||
|
||||
rule pass_redirect;
|
||||
RedirectInfo ri <- toGet(redirectQ).get;
|
||||
inIfc.redirectPc(ri.trap_pc, 0
|
||||
`ifdef RVFI_DII
|
||||
, ri.rii_pid
|
||||
`endif
|
||||
);
|
||||
endrule
|
||||
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
|
||||
@@ -62,6 +62,8 @@ import Vector::*;
|
||||
import Assert::*;
|
||||
import Cntrs::*;
|
||||
import ConfigReg::*;
|
||||
import HasSpecBits::*;
|
||||
import SpecFifo::*;
|
||||
import TlbTypes::*;
|
||||
import ITlb::*;
|
||||
import CCTypes::*;
|
||||
@@ -131,7 +133,9 @@ interface FetchStage;
|
||||
|
||||
// redirection methods
|
||||
method Action setWaitRedirect;
|
||||
method Action redirect(CapMem pc
|
||||
method Action redirect(
|
||||
CapMem pc,
|
||||
SpecBits specBits
|
||||
`ifdef RVFI_DII
|
||||
, Dii_Parcel_Id parcel_id
|
||||
`endif
|
||||
@@ -144,6 +148,7 @@ interface FetchStage;
|
||||
CapMem pc, CapMem next_pc, IType iType, Bool taken,
|
||||
PredTrainInfo trainInfo, Bool mispred, Bool isCompressed
|
||||
);
|
||||
interface SpeculationUpdate specUpdate;
|
||||
|
||||
// security
|
||||
method Bool emptyForFlush;
|
||||
@@ -336,7 +341,7 @@ module mkFetchStage(FetchStage);
|
||||
Integer verbosity = 0;
|
||||
|
||||
// Basic State Elements
|
||||
Reg#(Bool) started <- mkReg(False);
|
||||
Reg#(Bool) started <- mkConfigReg(False);
|
||||
|
||||
// Stall fetch when trap happens or system inst is renamed
|
||||
// All inst younger than the trap/system inst will be killed
|
||||
@@ -364,7 +369,14 @@ module mkFetchStage(FetchStage);
|
||||
function CapMem decompressPc(PcCompressed p) = {pcBlocks.lookup(p.idx),p.lsb};
|
||||
// Epochs
|
||||
Ehr#(2, Bool) decode_epoch <- mkEhr(False);
|
||||
Reg#(Epoch) f_main_epoch <- mkReg(0); // fetch estimate of main epoch
|
||||
// fetch estimate of main epoch
|
||||
Reg#(Epoch) f_main_epoch <- mkConfigReg(0);
|
||||
SpecFifo#(2, Bit#(0), 1, 1) main_epoch_spec <- mkSpecFifoUG(True);
|
||||
function Action set_main_epoch(Epoch e, SpecBits sb) = (action
|
||||
f_main_epoch <= e;
|
||||
if (main_epoch_spec.notEmpty) main_epoch_spec.deq;
|
||||
main_epoch_spec.enq(ToSpecFifo{data: ?, spec_bits: sb});
|
||||
endaction);
|
||||
|
||||
// Pipeline Stage FIFOs
|
||||
Fifo#(2, Fetch1ToFetch2) f12f2 <- mkCFFifo;
|
||||
@@ -549,12 +561,6 @@ module mkFetchStage(FetchStage);
|
||||
$display("Fetch3: Nothing else from Fetch2");
|
||||
end
|
||||
|
||||
let drop_f22f3 = f22f3.notEmpty
|
||||
&& ( fetch3In.main_epoch != f_main_epoch
|
||||
|| fetch3In.decode_epoch != decode_epoch[1]);
|
||||
|
||||
let parse_f22f3 = !drop_f22f3;
|
||||
|
||||
// Get ICache/MMIO response if no exception
|
||||
// In case of exception, we still need to process at least inst_data[0]
|
||||
// (it will be turned to an exception later), so inst_data[0] must be
|
||||
@@ -593,7 +599,15 @@ module mkFetchStage(FetchStage);
|
||||
end
|
||||
endrule: doFetch3
|
||||
|
||||
function Bool isCurrent(Fetch3ToDecode in) = (in.main_epoch == f_main_epoch && in.decode_epoch == decode_epoch[0]);
|
||||
Bool delay_epoch = False;
|
||||
`ifdef NO_SPEC_REDIRECT
|
||||
// Delay decode if the head of this buffer matches the current epoch;
|
||||
// this means the source of this epoch is still speculative.
|
||||
delay_epoch = (main_epoch_spec.first.spec_bits != 0);
|
||||
`endif
|
||||
function Bool isCurrent(Fetch3ToDecode in) = (main_epoch_spec.notEmpty &&
|
||||
in.main_epoch == f_main_epoch &&
|
||||
in.decode_epoch == decode_epoch[0]);
|
||||
|
||||
rule doDecodeFlush(f32d.deqS[0].canDeq && !isCurrent(f32d.deqS[0].first));
|
||||
for (Integer i = 0; i < valueOf(SupSizeX2); i = i + 1)
|
||||
@@ -603,7 +617,12 @@ module mkFetchStage(FetchStage);
|
||||
end
|
||||
endrule: doDecodeFlush
|
||||
|
||||
rule doDecode(f32d.deqS[0].canDeq && isCurrent(f32d.deqS[0].first));
|
||||
rule printStuff;
|
||||
$display("main_epoch_spec.first.spec_bits: %x, main_epoch_spec.notEmpty: %x, isCurrent: %x, f_main_epoch: %x, next_epoch: %x",
|
||||
main_epoch_spec.first.spec_bits, main_epoch_spec.notEmpty, isCurrent(f32d.deqS[0].first), f_main_epoch, f32d.deqS[0].first.main_epoch);
|
||||
endrule
|
||||
|
||||
rule doDecode(f32d.deqS[0].canDeq && isCurrent(f32d.deqS[0].first) && !delay_epoch);
|
||||
Vector#(SupSize, Maybe#(InstrFromFetch3)) decodeIn = replicate(Invalid);
|
||||
// Express the incoming fragments as a vector of maybes.
|
||||
Vector#(SupSizeX2, Maybe#(Fetch3ToDecode)) frags;
|
||||
@@ -886,6 +905,7 @@ module mkFetchStage(FetchStage);
|
||||
started <= True;
|
||||
waitForRedirect[0] <= False;
|
||||
waitForFlush[0] <= False;
|
||||
set_main_epoch(0,0);
|
||||
endmethod
|
||||
method Action stop();
|
||||
started <= False;
|
||||
@@ -895,18 +915,20 @@ module mkFetchStage(FetchStage);
|
||||
waitForRedirect[0] <= True;
|
||||
endmethod
|
||||
method Action redirect(
|
||||
CapMem new_pc
|
||||
CapMem new_pc,
|
||||
SpecBits specBits
|
||||
`ifdef RVFI_DII
|
||||
, Dii_Parcel_Id dii_pid
|
||||
`endif
|
||||
);
|
||||
if (verbose) $display("Redirect: newpc %h, old f_main_epoch %d, new f_main_epoch %d",new_pc,f_main_epoch,f_main_epoch+1);
|
||||
//if (verbose)
|
||||
$display("Redirect: newpc %h, old f_main_epoch %d, new f_main_epoch %d, specBits %x",new_pc,f_main_epoch,f_main_epoch+1, specBits);
|
||||
pc_reg[pc_redirect_port] <= new_pc;
|
||||
`ifdef RVFI_DII
|
||||
dii_pid_reg[pc_redirect_port] <= dii_pid;
|
||||
if (verbose) $display("%t Redirect: dii_pid_reg %d", $time(), dii_pid);
|
||||
`endif
|
||||
f_main_epoch <= (f_main_epoch == fromInteger(valueOf(NumEpochs)-1)) ? 0 : f_main_epoch + 1;
|
||||
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;
|
||||
// this redirect may be caused by a trap/system inst in commit stage
|
||||
@@ -958,6 +980,8 @@ module mkFetchStage(FetchStage);
|
||||
end
|
||||
endmethod
|
||||
|
||||
interface SpeculationUpdate specUpdate = main_epoch_spec.specUpdate;
|
||||
|
||||
// security
|
||||
method Bool emptyForFlush;
|
||||
return empty_for_flush;
|
||||
|
||||
@@ -46,10 +46,10 @@ export mkBht;
|
||||
typedef Bit#(0) BhtTrainInfo; // no training info needs to be remembered
|
||||
|
||||
// Local BHT Typedefs
|
||||
typedef 2048 BhtEntries;
|
||||
typedef 128 BhtEntries;
|
||||
typedef Bit#(TLog#(BhtEntries)) BhtIndex;
|
||||
|
||||
//(* synthesize *)
|
||||
(* synthesize *)
|
||||
module mkBht(DirPredictor#(BhtTrainInfo));
|
||||
// Read and Write ordering doesn't matter since this is a predictor
|
||||
// mkRegFileWCF is the RegFile version of mkConfigReg
|
||||
|
||||
Reference in New Issue
Block a user