diff --git a/build.sc b/build.sc index 80d7f11f79d..790f028377e 100644 --- a/build.sc +++ b/build.sc @@ -157,6 +157,7 @@ class Emulator(top: String, config: String) extends Module { Seq( "SimDTM.cc", "SimJTAG.cc", + "debug_rob.cc", "emulator.cc", "remote_bitbang.cc", ).map(c => PathRef(csrcDir().path / c)) diff --git a/emulator/Makefile b/emulator/Makefile index 6dd7518c7f6..95fd1ebac56 100644 --- a/emulator/Makefile +++ b/emulator/Makefile @@ -8,7 +8,7 @@ output_dir = $(sim_dir)/output include $(base_dir)/Makefrag -CXXSRCS := emulator SimDTM SimJTAG remote_bitbang +CXXSRCS := emulator SimDTM SimJTAG remote_bitbang debug_rob CXXFLAGS := $(CXXFLAGS) -std=c++17 -I$(RISCV)/include LDFLAGS := $(LDFLAGS) -L$(RISCV)/lib -Wl,-rpath,$(RISCV)/lib -L$(abspath $(sim_dir)) -lfesvr -lpthread diff --git a/src/main/resources/csrc/debug_rob.cc b/src/main/resources/csrc/debug_rob.cc new file mode 100644 index 00000000000..3ddb15c373c --- /dev/null +++ b/src/main/resources/csrc/debug_rob.cc @@ -0,0 +1,125 @@ +#include +#include +#include +#include + +#define WDATA_BITS (512) +#define WDATA_BYTES (WDATA_BITS / 8) + +typedef struct tagged_wb_data_t { + uint64_t tag; + uint8_t data[WDATA_BYTES]; +}; + +typedef struct tagged_traced_insn_t { + uint64_t iaddr; + uint64_t insn; + uint8_t priv; + bool exception; + bool interrupt; + uint64_t cause; + uint64_t tval; + uint8_t wdata[WDATA_BYTES]; + + bool waiting; + uint64_t wb_tag; +}; + +typedef struct debug_rob_t { + std::deque rob; + std::deque wb_datas; +}; + +std::map debug_robs; + +extern "C" void debug_rob_push_trace(int hartid, + char should_wb, + char has_wb, + long long int wb_tag, + char trace_valid, + long long int trace_iaddr, + long long int trace_insn, + int trace_priv, + char trace_exception, + char trace_interrupt, + long long int trace_cause, + long long int trace_tval, + long long int* trace_wdata) { + + if (debug_robs.find(hartid) == debug_robs.end()) + debug_robs[hartid] = new debug_rob_t; + + if (!trace_valid) return; + + tagged_traced_insn_t* insn = new tagged_traced_insn_t; + insn->iaddr = trace_iaddr; + insn->insn = trace_insn; + insn->priv = trace_priv; + insn->exception = trace_exception; + insn->interrupt = trace_interrupt; + insn->cause = trace_cause; + insn->tval = trace_tval; + insn->waiting = should_wb && !has_wb; + insn->wb_tag = wb_tag; + memcpy(insn->wdata, trace_wdata, WDATA_BYTES); + + debug_robs[hartid]->rob.push_back(insn); +} + +extern "C" void debug_rob_push_wb(int hartid, + char valid, + long long int wb_tag, + long long int* wb_data) { + if (debug_robs.find(hartid) == debug_robs.end()) + debug_robs[hartid] = new debug_rob_t; + + if (!valid) return; + + tagged_wb_data_t* data = new tagged_wb_data_t; + data->tag = wb_tag; + memcpy(data->data, wb_data, WDATA_BYTES); + debug_robs[hartid]->wb_datas.push_back(data); +} + +extern "C" void debug_rob_pop_trace(int hartid, + char* trace_valid, + long long int* trace_iaddr, + long long int* trace_insn, + int* trace_priv, + char* trace_exception, + char* trace_interrupt, + long long int* trace_cause, + long long int* trace_tval, + long long int* trace_wdata) { + *trace_valid = 0; + if (debug_robs.find(hartid) == debug_robs.end()) return; + if (debug_robs[hartid]->rob.empty()) return; + + tagged_traced_insn_t* front = debug_robs[hartid]->rob.front(); + std::deque &wb_datas = debug_robs[hartid]->wb_datas; + if (front->waiting) { + for (auto it = wb_datas.begin(); it != wb_datas.end(); it++) { + if ((*it)->tag == front->wb_tag) { + memcpy(front->wdata, (*it)->data, WDATA_BYTES); + front->waiting = false; + wb_datas.erase(it); + break; + } + } + } + + if (front->waiting) return; + + *trace_valid = true; + *trace_iaddr = front->iaddr; + *trace_insn = front->insn; + *trace_priv = front->priv; + *trace_exception = front->exception; + *trace_interrupt = front->interrupt; + *trace_cause = front->cause; + *trace_tval = front->tval; + memcpy(trace_wdata, front->wdata, WDATA_BYTES); + debug_robs[hartid]->rob.pop_front(); +} + + diff --git a/src/main/resources/vsrc/debug_rob.v b/src/main/resources/vsrc/debug_rob.v new file mode 100644 index 00000000000..e57e30cc11b --- /dev/null +++ b/src/main/resources/vsrc/debug_rob.v @@ -0,0 +1,156 @@ +import "DPI-C" function void debug_rob_push_trace(input int hartid, + input bit should_wb, + input bit has_wb, + input longint wb_tag, + input bit trace_valid, + input longint trace_iaddr, + input longint trace_insn, + input int trace_priv, + input bit trace_exception, + input bit trace_interrupt, + input longint trace_cause, + input longint trace_tval, + input longint trace_wdata[8]); + +import "DPI-C" function void debug_rob_push_wb(input int hartid, + input bit valid, + input longint wb_tag, + input longint wb_data[8]); + +import "DPI-C" function void debug_rob_pop_trace(input int hartid, + output bit trace_valid, + output longint trace_iaddr, + output longint trace_insn, + output int trace_priv, + output bit trace_exception, + output bit trace_interrupt, + output longint trace_cause, + output longint trace_tval, + output longint trace_wdata[8]); + + +module DebugROBPushTrace ( + input clock, + input reset, + input [31:0] hartid, + input should_wb, + input has_wb, + input [63:0] wb_tag, + input trace_valid, + input [63:0] trace_iaddr, + input [63:0] trace_insn, + input [2:0] trace_priv, + input trace_exception, + input trace_interrupt, + input [63:0] trace_cause, + input [63:0] trace_tval, + input [511:0] trace_wdata); + + longint __trace_wdata[8]; + genvar i; + + for (i = 0; i < 8; i = i + 1) + assign __trace_wdata[i] = trace_wdata[(i+1)*64-1:i*64]; + + always @(posedge clock) begin + if (!reset) begin + debug_rob_push_trace(hartid, + should_wb, has_wb, wb_tag, + trace_valid, trace_iaddr, trace_insn, + trace_priv, trace_exception, trace_interrupt, + trace_cause, trace_tval, __trace_wdata); + end + end +endmodule; // DebugROBPushTrace + +module DebugROBPushWb ( + input clock, + input reset, + input [31:0] hartid, + input valid, + input [63:0] wb_tag, + input [511:0] wb_data); + + longint __wb_data[8]; + genvar i; + + for (i = 0; i < 8; i = i + 1) + assign __wb_data[i] = wb_data[(i+1)*64-1:i*64]; + + always @(posedge clock) begin + if (!reset) begin + debug_rob_push_wb(hartid, valid, wb_tag, __wb_data); + end + end +endmodule; // DebugROBPushWb + +module DebugROBPopTrace ( + input clock, + input reset, + input [31:0] hartid, + output trace_valid, + output [63:0] trace_iaddr, + output [63:0] trace_insn, + output [2:0] trace_priv, + output trace_exception, + output trace_interrupt, + output [63:0] trace_cause, + output [63:0] trace_tval, + output [511:0] trace_wdata); + + bit r_reset; + + bit __trace_valid; + longint __trace_iaddr; + longint __trace_insn; + int __trace_priv; + bit __trace_exception; + bit __trace_interrupt; + longint __trace_cause; + longint __trace_tval; + longint __trace_wdata[8]; + + reg __trace_valid_reg; + reg [63:0] __trace_iaddr_reg; + reg [63:0] __trace_insn_reg; + reg [2:0] __trace_priv_reg; + reg __trace_exception_reg; + reg __trace_interrupt_reg; + reg [63:0] __trace_cause_reg; + reg [63:0] __trace_tval_reg; + reg [511:0] __trace_wdata_reg; + + always @(posedge clock) begin + __trace_valid_reg <= __trace_valid; + __trace_iaddr_reg <= __trace_iaddr; + __trace_insn_reg <= __trace_insn; + __trace_priv_reg <= __trace_priv; + __trace_exception_reg <= __trace_exception; + __trace_interrupt_reg <= __trace_interrupt; + __trace_cause_reg <= __trace_cause; + __trace_tval_reg <= __trace_tval; + __trace_wdata_reg <= {__trace_wdata[7], __trace_wdata[6], __trace_wdata[5], __trace_wdata[4], + __trace_wdata[3], __trace_wdata[2], __trace_wdata[1], __trace_wdata[0]}; + end // always @ (posedge clock) + + assign trace_valid = __trace_valid_reg; + assign trace_iaddr = __trace_iaddr_reg; + assign trace_insn = __trace_insn_reg; + assign trace_priv = __trace_priv_reg; + assign trace_exception = __trace_exception_reg; + assign trace_interrupt = __trace_interrupt_reg; + assign trace_cause = __trace_cause_reg; + assign trace_tval = __trace_tval_reg; + assign trace_wdata = __trace_wdata_reg; + + always @(negedge clock) begin + r_reset <= reset; + if (!reset && !r_reset) begin + debug_rob_pop_trace(hartid, + __trace_valid, __trace_iaddr, __trace_insn, + __trace_priv, __trace_exception, __trace_interrupt, + __trace_cause, __trace_tval, __trace_wdata); + end + end +endmodule; // DebugROBPopTrace + diff --git a/src/main/scala/rocket/CSR.scala b/src/main/scala/rocket/CSR.scala index 326e50a1db8..ead04f4d376 100644 --- a/src/main/scala/rocket/CSR.scala +++ b/src/main/scala/rocket/CSR.scala @@ -1527,6 +1527,7 @@ class CSRFile( t.cause := cause t.interrupt := cause(xLen-1) t.tval := io.tval + t.wdata.foreach(_ := DontCare) } def chooseInterrupt(masksIn: Seq[UInt]): (Bool, UInt) = { diff --git a/src/main/scala/rocket/DebugROB.scala b/src/main/scala/rocket/DebugROB.scala new file mode 100644 index 00000000000..1740b8c073a --- /dev/null +++ b/src/main/scala/rocket/DebugROB.scala @@ -0,0 +1,104 @@ +// See LICENSE.Berkeley for license details. +// See LICENSE.SiFive for license details. + +package freechips.rocketchip.rocket + +import chisel3._ +import chisel3.util._ +import chisel3.experimental.{IntParam} +import org.chipsalliance.cde.config.{Parameters} +import freechips.rocketchip.tile.{HasCoreParameters} + + +class WidenedTracedInstruction extends Bundle { + val valid = Bool() + val iaddr = UInt(64.W) + val insn = UInt(64.W) + val priv = UInt(3.W) + val exception = Bool() + val interrupt = Bool() + val cause = UInt(64.W) + val tval = UInt(64.W) + val wdata = UInt(512.W) +} + +// "DebugROB" classes provide an in-order commit log +// with wdata populated. +// These is not synthesizable, they use a C++ blackbox to implement the +// write-back reordering +class DebugROBPushTrace(implicit val p: Parameters) extends BlackBox with HasBlackBoxResource with HasCoreParameters { + require(traceHasWdata && (vLen max xLen) <= 512) + val io = IO(new Bundle { + val clock = Input(Clock()) + val reset = Input(Bool()) + val hartid = Input(UInt(32.W)) + val should_wb = Input(Bool()) + val has_wb = Input(Bool()) + val wb_tag = Input(UInt(64.W)) + val trace = Input(new WidenedTracedInstruction) + }) + addResource("/csrc/debug_rob.cc") + addResource("/vsrc/debug_rob.v") +} + +class DebugROBPushWb(implicit val p: Parameters) extends BlackBox + with HasBlackBoxResource with HasCoreParameters { + require(traceHasWdata && (vLen max xLen) <= 512) + val io = IO(new Bundle { + val clock = Input(Clock()) + val reset = Input(Bool()) + val hartid = Input(UInt(32.W)) + val valid = Input(Bool()) + val wb_tag = Input(UInt(64.W)) + val wb_data = Input(UInt(512.W)) + }) + addResource("/csrc/debug_rob.cc") + addResource("/vsrc/debug_rob.v") +} + +class DebugROBPopTrace(implicit val p: Parameters) extends BlackBox with HasBlackBoxResource with HasCoreParameters { + require(traceHasWdata && (vLen max xLen) <= 512) + val io = IO(new Bundle { + val clock = Input(Clock()) + val reset = Input(Bool()) + val hartid = Input(UInt(32.W)) + val trace = Output(new WidenedTracedInstruction) + }) + addResource("/csrc/debug_rob.cc") + addResource("/vsrc/debug_rob.v") +} + +object DebugROB { + def pushTrace(clock: Clock, reset: Reset, + hartid: UInt, trace: TracedInstruction, + should_wb: Bool, has_wb: Bool, wb_tag: UInt)(implicit p: Parameters) = { + val debug_rob_push_trace = Module(new DebugROBPushTrace) + debug_rob_push_trace.io.clock := clock + debug_rob_push_trace.io.reset := reset + debug_rob_push_trace.io.hartid := hartid + debug_rob_push_trace.io.should_wb := should_wb + debug_rob_push_trace.io.has_wb := has_wb + debug_rob_push_trace.io.wb_tag := wb_tag + debug_rob_push_trace.io.trace := trace + } + def popTrace(clock: Clock, reset: Reset, + hartid: UInt)(implicit p: Parameters): TracedInstruction = { + val debug_rob_pop_trace = Module(new DebugROBPopTrace) + debug_rob_pop_trace.io.clock := clock + debug_rob_pop_trace.io.reset := reset + debug_rob_pop_trace.io.hartid := hartid + val trace = Wire(new TracedInstruction) + trace := debug_rob_pop_trace.io.trace + trace + } + def pushWb(clock: Clock, reset: Reset, + hartid: UInt, valid: Bool, tag: UInt, data: UInt)(implicit p: Parameters) { + val debug_rob_push_wb = Module(new DebugROBPushWb) + debug_rob_push_wb.io.clock := clock + debug_rob_push_wb.io.reset := reset + debug_rob_push_wb.io.hartid := hartid + debug_rob_push_wb.io.valid := valid + debug_rob_push_wb.io.wb_tag := tag + debug_rob_push_wb.io.wb_data := data + } +} diff --git a/src/main/scala/rocket/RocketCore.scala b/src/main/scala/rocket/RocketCore.scala index 6c01985aab3..0fdf4fbce3f 100644 --- a/src/main/scala/rocket/RocketCore.scala +++ b/src/main/scala/rocket/RocketCore.scala @@ -53,7 +53,8 @@ case class RocketCoreParams( mvendorid: Int = 0, // 0 means non-commercial implementation mimpid: Int = 0x20181004, // release date in BCD mulDiv: Option[MulDivParams] = Some(MulDivParams()), - fpu: Option[FPUParams] = Some(FPUParams()) + fpu: Option[FPUParams] = Some(FPUParams()), + debugROB: Boolean = false // if enabled, uses a C++ debug ROB to generate trace-with-wdata ) extends CoreParams { val lgPauseCycles = 5 val haveFSDirty = false @@ -810,7 +811,22 @@ class Rocket(tile: RocketTile)(implicit p: Parameters) extends CoreModule()(p) csr.io.rw.addr := wb_reg_inst(31,20) csr.io.rw.cmd := CSR.maskCmd(wb_reg_valid, wb_ctrl.csr) csr.io.rw.wdata := wb_reg_wdata - io.trace := csr.io.trace + if (rocketParams.debugROB) { + val csr_trace_with_wdata = WireInit(csr.io.trace(0)) + csr_trace_with_wdata.wdata.get := rf_wdata + DebugROB.pushTrace(clock, reset, + io.hartid, csr_trace_with_wdata, + (wb_ctrl.wfd || (wb_ctrl.wxd && wb_waddr =/= 0.U)) && !csr.io.trace(0).exception, + wb_ctrl.wxd && wb_wen && !wb_set_sboard, + wb_waddr + Mux(wb_ctrl.wfd, 32.U, 0.U)) + + io.trace(0) := DebugROB.popTrace(clock, reset, io.hartid) + + DebugROB.pushWb(clock, reset, io.hartid, ll_wen, rf_waddr, rf_wdata) + } else { + io.trace := csr.io.trace + } + for (((iobpw, wphit), bp) <- io.bpwatch zip wb_reg_wphit zip csr.io.bp) { iobpw.valid(0) := wphit iobpw.action := bp.control.action diff --git a/src/main/scala/subsystem/Configs.scala b/src/main/scala/subsystem/Configs.scala index 215ae26b0a6..8b15ef5ab54 100644 --- a/src/main/scala/subsystem/Configs.scala +++ b/src/main/scala/subsystem/Configs.scala @@ -430,6 +430,14 @@ class WithCryptoSM extends Config((site, here, up) => { } }) +class WithRocketDebugROB(enable: Boolean = true) extends Config((site, here, up) => { + case TilesLocated(InSubsystem) => up(TilesLocated(InSubsystem), site) map { + case tp: RocketTileAttachParams => tp.copy(tileParams = tp.tileParams.copy( + core = tp.tileParams.core.copy(debugROB = enable) + )) + } +}) + class WithBootROMFile(bootROMFile: String) extends Config((site, here, up) => { case BootROMLocated(x) => up(BootROMLocated(x), site).map(_.copy(contentFileName = bootROMFile)) }) diff --git a/src/main/scala/tile/FPU.scala b/src/main/scala/tile/FPU.scala index 8af72581fc0..0ebeb0a9275 100644 --- a/src/main/scala/tile/FPU.scala +++ b/src/main/scala/tile/FPU.scala @@ -726,9 +726,9 @@ class FPUFMAPipe(val latency: Int, val t: FType) class FPU(cfg: FPUParams)(implicit p: Parameters) extends FPUModule()(p) { val io = IO(new FPUIO) - val useClockGating = coreParams match { - case r: RocketCoreParams => r.clockGate - case _ => false + val (useClockGating, useDebugROB) = coreParams match { + case r: RocketCoreParams => (r.clockGate, r.debugROB) + case _ => (false, false) } val clock_en_reg = Reg(Bool()) val clock_en = clock_en_reg || io.cp_req.valid @@ -796,7 +796,9 @@ class FPU(cfg: FPUParams)(implicit p: Parameters) extends FPUModule()(p) { regfile(load_wb_tag) := wdata assert(consistent(wdata)) if (enableCommitLog) - printf("f%d p%d 0x%x\n", load_wb_tag, load_wb_tag + 32.U, load_wb_data) + printf("f%d p%d 0x%x\n", load_wb_tag, load_wb_tag + 32.U, ieee(wdata)) + if (useDebugROB) + DebugROB.pushWb(clock, reset, io.hartid, load_wb, load_wb_tag + 32.U, ieee(wdata)) frfWriteBundle(0).wrdst := load_wb_tag frfWriteBundle(0).wrenf := true.B frfWriteBundle(0).wrdata := ieee(wdata) @@ -940,6 +942,10 @@ class FPU(cfg: FPUParams)(implicit p: Parameters) extends FPUModule()(p) { frfWriteBundle(1).wrenf := true.B frfWriteBundle(1).wrdata := ieee(wdata) } + if (useDebugROB) { + DebugROB.pushWb(clock, reset, io.hartid, (!wbInfo(0).cp && wen(0)) || divSqrt_wen, waddr + 32.U, ieee(wdata)) + } + when (wbInfo(0).cp && wen(0)) { io.cp_resp.bits.data := wdata io.cp_resp.valid := true.B diff --git a/vsim/Makefrag b/vsim/Makefrag index 4f89a341365..51d75fc30ae 100644 --- a/vsim/Makefrag +++ b/vsim/Makefrag @@ -17,6 +17,7 @@ sim_vsrcs = \ $(vsrc)/$(TB).v \ $(vsrc)/SimDTM.v \ $(vsrc)/SimJTAG.v \ + $(vsrc)/debug_rob.v \ $(bb_vsrcs) # C sources @@ -24,6 +25,7 @@ sim_vsrcs = \ sim_csrcs = \ $(csrc)/SimDTM.cc \ $(csrc)/SimJTAG.cc \ + $(csrc)/debug_rob.cc \ $(csrc)/remote_bitbang.cc #--------------------------------------------------------------------