Changes necessary to trace memory operations.

This is not thoroughly tested, as we quickly throw an exception due to out-of-bounds memory and need some RVFI-DII control flow fixup to proceed further.
This commit is contained in:
Jonathan Woodruff
2019-11-29 10:50:38 +00:00
parent 96d092c300
commit 83e54f9b53
7 changed files with 125 additions and 22 deletions

View File

@@ -175,8 +175,7 @@ module mkCore#(CoreId coreId)(Core);
// ================================================================
// If using Direct Instruction Injection then make a
// bridge that can insert instructions as if it were
// an instruction cache.
// bridge that can insert instructions.
`ifdef RVFI_DII
Toooba_RVFI_DII_Bridge_IFC rvfi_bridge <- mkTooobaRVFIDIIBridge;
mkConnection(rvfi_bridge.dii, fetchStage.dii);

View File

@@ -84,6 +84,9 @@ typedef struct {
ControlFlow controlFlow;
// speculation
Maybe#(SpecTag) spec_tag;
`ifdef RVFI
ExtraTraceBundle traceBundle;
`endif
} AluExeToFinish deriving(Bits, Eq, FShow);
// XXX currently ALU/Br should not have any exception, so we don't have cause feild above
@@ -137,7 +140,14 @@ interface AluExeInput;
method Addr rob_getPC(InstTag t);
method Addr rob_getPredPC(InstTag t);
method Bit #(32) rob_getOrig_Inst (InstTag t);
method Action rob_setExecuted(InstTag t, Maybe#(Data) csrData, ControlFlow cf);
method Action rob_setExecuted(
InstTag t,
Maybe#(Data) csrData,
ControlFlow cf
`ifdef RVFI
, ExtraTraceBundle tb
`endif
);
// Fetch stage
method Action fetch_train_predictors(FetchTrainBP train);
@@ -292,7 +302,13 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline);
tag: x.tag,
dpTrain: x.dpTrain,
data: exec_result.data,
csrData: isValid(x.dInst.csr) ? Valid (exec_result.csrData) : Invalid,
csrData: isValid(x.dInst.csr) ? Valid (exec_result.csrData) : tagged Invalid,
`ifdef RVFI
traceBundle: ExtraTraceBundle{
regWriteData: exec_result.data,
memByteEn: replicate(False)
},
`endif
controlFlow: exec_result.controlFlow,
spec_tag: x.spec_tag
},
@@ -317,6 +333,9 @@ module mkAluExePipeline#(AluExeInput inIfc)(AluExePipeline);
x.tag,
x.csrData,
x.controlFlow
`ifdef RVFI
, x.traceBundle
`endif
);
// handle spec tags for branch predictions

View File

@@ -132,6 +132,20 @@ typedef struct {
`ifdef RVFI
function RVFI_DII_Execution#(DataSz,DataSz) genRVFI(ToReorderBuffer rot);
Addr addr = 0;
Addr next_pc = rot.pc + 4;
Data data = rot.traceBundle.regWriteData;
case (rot.ppc_vaddr_csrData) matches
tagged VAddr .vaddr: addr = vaddr;
tagged PPC .ppc: next_pc = ppc;
tagged CSRData .csrdata: data = csrdata;
endcase
ByteEn rmask = replicate(False);
ByteEn wmask = replicate(False);
case (rot.lsqTag) matches
tagged Ld .l: rmask = rot.traceBundle.memByteEn;
tagged St .s: wmask = rot.traceBundle.memByteEn;
endcase
return RVFI_DII_Execution {
rvfi_order: 0, // Instruction number? InstID maybe?
rvfi_trap: isValid(rot.trap),
@@ -143,14 +157,14 @@ function RVFI_DII_Execution#(DataSz,DataSz) genRVFI(ToReorderBuffer rot);
rvfi_rs1_data: ?,
rvfi_rs2_data: ?,
rvfi_pc_rdata: rot.pc,
rvfi_pc_wdata: rot.pc + 4,
rvfi_pc_wdata: next_pc,
rvfi_mem_wdata: 0,
rvfi_rd_addr: rot.orig_inst[11:7],
rvfi_rd_wdata: ?,
rvfi_mem_addr: 0,
rvfi_mem_rmask: 0,
rvfi_mem_wmask: 0,
rvfi_mem_rdata: 0
rvfi_rd_wdata: ((rot.orig_inst[11:7]==0) ? 0:data),
rvfi_mem_addr: addr,
rvfi_mem_rmask: pack(rmask),
rvfi_mem_wmask: pack(wmask),
rvfi_mem_rdata: data
};
endfunction
`endif

View File

@@ -461,6 +461,20 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
let x = dTlbResp.inst;
let {paddr, cause} = dTlbResp.resp;
`ifdef RVFI_DII
// TestRIG expects us throw an access fault for any memory access outside of a 64-KiB memory at 0x8000000.
if (!isValid(cause) && (paddr < 'h80000000 || paddr >= 'h80010000)) begin
case(x.mem_func)
Ld, Lr: begin
cause = Valid (LoadAccessFault);
end
default: begin
cause = Valid (StoreAccessFault);
end
endcase
end
`endif
if(verbose) $display("[doFinishMem] ", fshow(dTlbResp));
if(isValid(cause) && verbose) $display(" [doFinishMem - dTlb response] PAGEFAULT!");

View File

@@ -44,6 +44,13 @@ typedef union tagged {
Data CSRData; // for Csr inst, store csr_data
} PPCVAddrCSRData deriving(Bits, Eq, FShow);
`ifdef RVFI
typedef struct {
Data regWriteData;
ByteEn memByteEn;
} ExtraTraceBundle deriving(Bits, Eq, FShow);
`endif
typedef struct {
Addr pc;
Bit #(32) orig_inst; // original 16b or 32b instruction ([1:0] will distinguish 16b or 32b)
@@ -75,6 +82,9 @@ typedef struct {
// speculation
SpecBits spec_bits;
`ifdef RVFI
ExtraTraceBundle traceBundle;
`endif
} ToReorderBuffer deriving(Bits, Eq, FShow);
typedef enum {
@@ -83,7 +93,13 @@ typedef enum {
} RobInstState deriving (Bits, Eq, FShow);
interface Row_setExecuted_doFinishAlu;
method Action set(Maybe#(Data) csrData, ControlFlow cf);
method Action set(
Maybe#(Data) csrData,
ControlFlow cf
`ifdef RVFI
, ExtraTraceBundle tb
`endif
);
endinterface
interface Row_setExecuted_doFinishFpuMulDiv;
@@ -186,6 +202,9 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
Ehr#(2, Bool) nonMMIOStDone <- mkEhr(?);
Reg#(Bool) epochIncremented <- mkRegU;
Ehr#(3, SpecBits) spec_bits <- mkEhr(?);
`ifdef RVFI
Ehr#(TAdd#(2, aluExeNum), (ExtraTraceBundle)) traceBundle <- mkEhr(?);
`endif
// wires to get stale (EHR port 0) values of PPC
Wire#(Addr) predPcWire <- mkBypassWire;
@@ -197,7 +216,13 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
Vector#(aluExeNum, Row_setExecuted_doFinishAlu) aluSetExe;
for(Integer i = 0; i < valueof(aluExeNum); i = i+1) begin
aluSetExe[i] = (interface Row_setExecuted_doFinishAlu;
method Action set(Maybe#(Data) csrData, ControlFlow cf);
method Action set(
Maybe#(Data) csrData,
ControlFlow cf
`ifdef RVFI
, ExtraTraceBundle tb
`endif
);
// inst is done
rob_inst_state[state_finishAlu_port(i)] <= Executed;
// update PPC or csrData (vaddr is always useless for ALU results)
@@ -207,6 +232,9 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
else begin
ppc_vaddr_csrData[pvc_finishAlu_port(i)] <= PPC (cf.nextPc);
end
`ifdef RVFI
traceBundle[pvc_finishAlu_port(i)] <= tb;
`endif
doAssert(isValid(csr) == isValid(csrData), "csr valid should match");
endmethod
endinterface);
@@ -281,6 +309,9 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
ldKilled[ldKill_enq_port] <= Invalid;
lsqAtCommitNotified[lsqNotified_enq_port] <= False;
nonMMIOStDone[nonMMIOSt_enq_port] <= False;
`ifdef RVFI
traceBundle[pvc_enq_port] <= x.traceBundle;
`endif
// check
doAssert(!isValid(x.ldKilled), "ld killed must be false");
doAssert(x.memAccessAtCommit == False, "mem access at commit must be false");
@@ -307,6 +338,9 @@ module mkReorderBufferRowEhr(ReorderBufferRowEhr#(aluExeNum, fpuMulDivExeNum)) p
lsqAtCommitNotified: lsqAtCommitNotified[lsqNotified_deq_port],
nonMMIOStDone: nonMMIOStDone[nonMMIOSt_deq_port],
epochIncremented: epochIncremented,
`ifdef RVFI
traceBundle: traceBundle[pvc_deq_port],
`endif
spec_bits: spec_bits[sb_deq_port]
};
endmethod
@@ -379,7 +413,13 @@ endinterface
// not raise false conflicts between the superscalar enq/deq actions
interface ROB_setExecuted_doFinishAlu;
method Action set(InstTag x, Maybe#(Data) csrData, ControlFlow cf);
method Action set(InstTag x,
Maybe#(Data) csrData,
ControlFlow cf
`ifdef RVFI
, ExtraTraceBundle tb
`endif
);
endinterface
interface ROB_setExecuted_doFinishFpuMulDiv;
@@ -891,11 +931,22 @@ module mkSupReorderBuffer#(
for(Integer i = 0; i < valueof(aluExeNum); i = i+1) begin
aluSetExeIfc[i] = (interface ROB_setExecuted_doFinishAlu;
method Action set(
InstTag x, Maybe#(Data) csrData, ControlFlow cf
InstTag x,
Maybe#(Data) csrData,
ControlFlow cf
`ifdef RVFI
, ExtraTraceBundle tb
`endif
) if(
all(id, readVReg(setExeAlu_SB_enq)) // ordering: < enq
);
row[x.way][x.ptr].setExecuted_doFinishAlu[i].set(csrData, cf);
row[x.way][x.ptr].setExecuted_doFinishAlu[i].set(
csrData,
cf
`ifdef RVFI
, tb
`endif
);
endmethod
endinterface);
end

View File

@@ -61,10 +61,11 @@ module mkTooobaRVFIDIIBridge(Toooba_RVFI_DII_Bridge_IFC);
// DII state
FIFOF#(Tuple2#(Bit#(32), Dii_Id)) dii_in <- mkUGFIFOF;
Reg#(InstsAndIDs) buff <- mkConfigRegU;
FIFOF#(InstsAndIDs) instrs <- mkSizedFIFOF(128);
FIFOF#(InstsAndIDs) instrs <- mkSizedFIFOF(2048);
PulseWire putFromBridge <- mkPulseWire;
// RVFI state
FIFO#(Rvfi_Traces) report_vectors <- mkSizedFIFO(128);
FIFO#(RVFI_DII_Execution#(DataSz,DataSz)) reports <- mkSizedFIFO(256);
FIFO#(Rvfi_Traces) report_vectors <- mkSizedFIFO(2048);
FIFO#(RVFI_DII_Execution#(DataSz,DataSz)) reports <- mkFIFO;
// Request ID
FIFO#(Dii_Id) seq_req <- mkFIFO;
@@ -93,7 +94,7 @@ module mkTooobaRVFIDIIBridge(Toooba_RVFI_DII_Bridge_IFC);
InstsAndIDs cb = buff;
Bit#(32) ins = nop;
Dii_Id id = ?;
if (dii_in.notEmpty) {ins, id} = dii_in.first;
if (dii_in.notEmpty) {ins, id} <- toGet(dii_in).get;
cb.insts[buffLvl] = tagged Valid ins;
cb.ids[buffLvl] = id;
if (buffLvl == -1) begin
@@ -106,14 +107,19 @@ module mkTooobaRVFIDIIBridge(Toooba_RVFI_DII_Bridge_IFC);
interface Toooba_RVFI_DII_Server rvfi_dii_server;
interface Get seqReq = toGet(seq_req);
interface Put inst = toPut(dii_in);
interface Put inst;
method Action put(Tuple2#(Bit#(32), Dii_Id) in) if (dii_in.notFull);
dii_in.enq(in);
putFromBridge.send();
endmethod
endinterface
interface Get trace_report = toGet(reports);
endinterface
interface Server dii;
interface Put request = toPut(seq_req);
interface Get response;
method ActionValue#(InstsAndIDs) get;
method ActionValue#(InstsAndIDs) get if (!putFromBridge);
InstsAndIDs insts = instrs.first();
instrs.deq();
if (verbose)