From 4d6d6ff641162bcbf9bfdfa4500828c9af239f4c Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Tue, 19 Sep 2017 22:59:28 -0700 Subject: [PATCH] Add instruction-trace port --- src/main/scala/groundtest/TraceGen.scala | 1 + src/main/scala/rocket/CSR.scala | 37 ++++++++++++++++----- src/main/scala/rocket/IBuf.scala | 2 -- src/main/scala/rocket/RocketCore.scala | 42 +++++++++++------------- src/main/scala/tile/BaseTile.scala | 7 ++++ src/main/scala/tile/Core.scala | 1 + src/main/scala/tile/RocketTile.scala | 5 ++- 7 files changed, 62 insertions(+), 33 deletions(-) diff --git a/src/main/scala/groundtest/TraceGen.scala b/src/main/scala/groundtest/TraceGen.scala index f9876c66..f1779776 100644 --- a/src/main/scala/groundtest/TraceGen.scala +++ b/src/main/scala/groundtest/TraceGen.scala @@ -65,6 +65,7 @@ case class TraceGenParams( memStart: BigInt, //p(ExtMem).base numGens: Int) extends GroundTestTileParams { def build(i: Int, p: Parameters): GroundTestTile = new TraceGenTile(i, this)(p) + val trace = false } trait HasTraceGenParams { diff --git a/src/main/scala/rocket/CSR.scala b/src/main/scala/rocket/CSR.scala index 929ce31a..6fa70545 100644 --- a/src/main/scala/rocket/CSR.scala +++ b/src/main/scala/rocket/CSR.scala @@ -149,6 +149,16 @@ class PerfCounterIO(implicit p: Parameters) extends CoreBundle val inc = UInt(INPUT, log2Ceil(1+retireWidth)) } +class TracedInstruction(implicit p: Parameters) extends CoreBundle { + val valid = Bool() + val addr = UInt(width = coreMaxAddrBits) + val insn = UInt(width = iLen) + val priv = UInt(width = 3) + val exception = Bool() + val cause = UInt(width = 1 + log2Ceil(xLen)) + val tval = UInt(width = coreMaxAddrBits max iLen) +} + class CSRFileIO(implicit p: Parameters) extends CoreBundle with HasRocketCoreParameters { val interrupts = new TileInterrupts().asInput @@ -192,6 +202,8 @@ class CSRFileIO(implicit p: Parameters) extends CoreBundle val bp = Vec(nBreakpoints, new BP).asOutput val pmp = Vec(nPMPs, new PMP).asOutput val counters = Vec(nPerfCounters, new PerfCounterIO) + val inst = Vec(retireWidth, UInt(width = iLen)).asInput + val trace = Vec(retireWidth, new TracedInstruction).asOutput } class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Parameters) extends CoreModule()(p) @@ -506,15 +518,14 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param assert(!io.singleStep || io.retire <= UInt(1)) assert(!reg_singleStepped || io.retire === UInt(0)) + val epc = ~(~io.pc | (coreInstBytes-1)) + val write_badaddr = cause isOneOf (Causes.illegal_instruction, Causes.breakpoint, + Causes.misaligned_load, Causes.misaligned_store, Causes.misaligned_fetch, + Causes.load_access, Causes.store_access, Causes.fetch_access, + Causes.load_page_fault, Causes.store_page_fault, Causes.fetch_page_fault) + val badaddr_value = Mux(write_badaddr, io.badaddr, 0.U) + when (exception) { - val epc = ~(~io.pc | (coreInstBytes-1)) - - val write_badaddr = cause isOneOf (Causes.illegal_instruction, Causes.breakpoint, - Causes.misaligned_load, Causes.misaligned_store, Causes.misaligned_fetch, - Causes.load_access, Causes.store_access, Causes.fetch_access, - Causes.load_page_fault, Causes.store_page_fault, Causes.fetch_page_fault) - val badaddr_value = Mux(write_badaddr, io.badaddr, 0.U) - when (trapToDebug) { when (!reg_debug) { reg_debug := true @@ -756,6 +767,16 @@ class CSRFile(perfEventSets: EventSets = new EventSets(Seq()))(implicit p: Param } } + for (((t, insn), i) <- (io.trace zip io.inst).zipWithIndex) { + t.exception := io.retire >= i && exception + t.valid := io.retire > i || t.exception + t.insn := insn + t.addr := io.pc + t.priv := Cat(reg_debug, reg_mstatus.prv) + t.cause := Cat(cause(xLen-1), cause(log2Ceil(xLen)-1, 0)) + t.tval := badaddr_value + } + def chooseInterrupt(masks: Seq[UInt]): (Bool, UInt) = { val nonstandard = supported_interrupts.getWidth-1 to 12 by -1 // MEI, MSI, MTI, SEI, SSI, STI, UEI, USI, UTI diff --git a/src/main/scala/rocket/IBuf.scala b/src/main/scala/rocket/IBuf.scala index 4623b65b..b24002de 100644 --- a/src/main/scala/rocket/IBuf.scala +++ b/src/main/scala/rocket/IBuf.scala @@ -16,7 +16,6 @@ class Instruction(implicit val p: Parameters) extends ParameterizedBundle with H val rvc = Bool() val inst = new ExpandedInstruction val raw = UInt(width = 32) - val cinst = UInt(width = 32) require(coreInstBits == (if (usingCompressed) 16 else 32)) } @@ -96,7 +95,6 @@ class IBuf(implicit p: Parameters) extends CoreModule { exp.io.in := curInst io.inst(i).bits.inst := exp.io.out io.inst(i).bits.raw := curInst - io.inst(i).bits.cinst := Mux(exp.io.rvc, curInst & 0xFFFF, curInst) if (usingCompressed) { val replay = ic_replay(j) || (!exp.io.rvc && (btbHitMask(j) || ic_replay(j+1))) diff --git a/src/main/scala/rocket/RocketCore.scala b/src/main/scala/rocket/RocketCore.scala index 15d2ac6e..e57484be 100644 --- a/src/main/scala/rocket/RocketCore.scala +++ b/src/main/scala/rocket/RocketCore.scala @@ -136,7 +136,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) val ex_reg_replay = Reg(Bool()) val ex_reg_pc = Reg(UInt()) val ex_reg_inst = Reg(Bits()) - val ex_reg_cinst = Reg(Bits()) + val ex_reg_raw_inst = Reg(UInt()) val mem_reg_xcpt_interrupt = Reg(Bool()) val mem_reg_valid = Reg(Bool()) @@ -153,7 +153,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) val mem_reg_sfence = Reg(Bool()) val mem_reg_pc = Reg(UInt()) val mem_reg_inst = Reg(Bits()) - val mem_reg_cinst = Reg(Bits()) + val mem_reg_raw_inst = Reg(UInt()) val mem_reg_wdata = Reg(Bits()) val mem_reg_rs2 = Reg(Bits()) val take_pc_mem = Wire(Bool()) @@ -167,7 +167,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) val wb_reg_sfence = Reg(Bool()) val wb_reg_pc = Reg(UInt()) val wb_reg_inst = Reg(Bits()) - val wb_reg_cinst = Reg(Bits()) + val wb_reg_raw_inst = Reg(UInt()) val wb_reg_wdata = Reg(Bits()) val wb_reg_rs2 = Reg(Bits()) val take_pc_wb = Wire(Bool()) @@ -178,7 +178,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) // decode stage val ibuf = Module(new IBuf) val id_expanded_inst = ibuf.io.inst.map(_.bits.inst) - val id_nonexpanded_inst = ibuf.io.inst.map(_.bits.cinst) + val id_raw_inst = ibuf.io.inst.map(_.bits.raw) val id_inst = id_expanded_inst.map(_.bits) ibuf.io.imem <> io.imem.resp ibuf.io.kill := take_pc @@ -335,7 +335,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) } } when (id_illegal_insn) { - val inst = Mux(ibuf.io.inst(0).bits.rvc, ibuf.io.inst(0).bits.raw(15, 0), ibuf.io.inst(0).bits.raw) + val inst = Mux(ibuf.io.inst(0).bits.rvc, id_raw_inst(0)(15, 0), id_raw_inst(0)) ex_reg_rs_bypass(0) := false ex_reg_rs_lsb(0) := inst(log2Ceil(bypass_sources.size)-1, 0) ex_reg_rs_msb(0) := inst >> log2Ceil(bypass_sources.size) @@ -344,7 +344,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) when (!ctrl_killd || csr.io.interrupt || ibuf.io.inst(0).bits.replay) { ex_reg_cause := id_cause ex_reg_inst := id_inst(0) - ex_reg_cinst := id_nonexpanded_inst(0) + ex_reg_raw_inst := id_raw_inst(0) ex_reg_pc := ibuf.io.pc ex_reg_btb_resp := ibuf.io.btb_resp } @@ -405,7 +405,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) mem_reg_cause := ex_cause mem_reg_inst := ex_reg_inst - mem_reg_cinst := ex_reg_cinst + mem_reg_raw_inst := ex_reg_raw_inst mem_reg_pc := ex_reg_pc mem_reg_wdata := alu.io.out @@ -453,7 +453,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) } wb_reg_cause := mem_cause wb_reg_inst := mem_reg_inst - wb_reg_cinst := mem_reg_cinst + wb_reg_raw_inst := mem_reg_raw_inst wb_reg_pc := mem_reg_pc } @@ -513,10 +513,11 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) when (rf_wen) { rf.write(rf_waddr, rf_wdata) } // hook up control/status regfile - csr.io.decode.csr := ibuf.io.inst(0).bits.raw(31,20) + csr.io.decode.csr := id_raw_inst(0)(31,20) csr.io.exception := wb_xcpt csr.io.cause := wb_cause csr.io.retire := wb_valid + csr.io.inst(0) := Cat(Mux(wb_reg_rvc, 0.U, wb_reg_inst >> 16), wb_reg_raw_inst(15, 0)) csr.io.interrupts := io.interrupts csr.io.hartid := io.hartid io.fpu.fcsr_rm := csr.io.fcsr_rm @@ -530,6 +531,7 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) csr.io.rw.addr := wb_reg_inst(31,20) csr.io.rw.cmd := Mux(wb_reg_valid, wb_ctrl.csr, CSR.N) csr.io.rw.wdata := wb_reg_wdata + io.trace := csr.io.trace val hazard_targets = Seq((id_ctrl.rxs1 && id_raddr1 =/= UInt(0), id_raddr1), (id_ctrl.rxs2 && id_raddr2 =/= UInt(0), id_raddr2), @@ -664,28 +666,24 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) csr.io.counters foreach { c => c.inc := RegNext(perfEvents.evaluate(c.eventSel)) } if (enableCommitLog) { - val pc = Wire(SInt(width=xLen)) - pc := wb_reg_pc.asSInt - val inst = wb_reg_inst - val cinst = wb_reg_cinst - val rd = RegNext(RegNext(RegNext(id_waddr))) + val t = csr.io.trace(0) + val rd = wb_waddr val wfd = wb_ctrl.wfd val wxd = wb_ctrl.wxd val has_data = wb_wen && !wb_set_sboard - val priv = csr.io.status.prv - when (wb_valid) { + when (t.valid) { when (wfd) { - printf ("%d 0x%x (0x%x) f%d p%d 0xXXXXXXXXXXXXXXXX\n", priv, pc, cinst, rd, rd+UInt(32)) + printf ("%d 0x%x (0x%x) f%d p%d 0xXXXXXXXXXXXXXXXX\n", t.priv, t.addr, t.insn, rd, rd+UInt(32)) } .elsewhen (wxd && rd =/= UInt(0) && has_data) { - printf ("%d 0x%x (0x%x) x%d 0x%x\n", priv, pc, cinst, rd, rf_wdata) + printf ("%d 0x%x (0x%x) x%d 0x%x\n", t.priv, t.addr, t.insn, rd, rf_wdata) } .elsewhen (wxd && rd =/= UInt(0) && !has_data) { - printf ("%d 0x%x (0x%x) x%d p%d 0xXXXXXXXXXXXXXXXX\n", priv, pc, cinst, rd, rd) + printf ("%d 0x%x (0x%x) x%d p%d 0xXXXXXXXXXXXXXXXX\n", t.priv, t.addr, t.insn, rd, rd) } .otherwise { - printf ("%d 0x%x (0x%x)\n", priv, pc, cinst) + printf ("%d 0x%x (0x%x)\n", t.priv, t.addr, t.insn) } } @@ -695,11 +693,11 @@ class Rocket(implicit p: Parameters) extends CoreModule()(p) } else { printf("C%d: %d [%d] pc=[%x] W[r%d=%x][%d] R[r%d=%x] R[r%d=%x] inst=[%x] DASM(%x)\n", - io.hartid, csr.io.time(31,0), wb_valid, wb_reg_pc, + io.hartid, csr.io.time(31,0), csr.io.trace(0).valid, csr.io.trace(0).addr(vaddrBitsExtended-1, 0), Mux(rf_wen && !(wb_set_sboard && wb_wen), rf_waddr, UInt(0)), rf_wdata, rf_wen, wb_reg_inst(19,15), Reg(next=Reg(next=ex_rs(0))), wb_reg_inst(24,20), Reg(next=Reg(next=ex_rs(1))), - wb_reg_cinst, wb_reg_cinst) + csr.io.trace(0).insn, csr.io.trace(0).insn) } val max_core_cycles = PlusArg("max-core-cycles", diff --git a/src/main/scala/tile/BaseTile.scala b/src/main/scala/tile/BaseTile.scala index 89ac5168..644ccb6a 100644 --- a/src/main/scala/tile/BaseTile.scala +++ b/src/main/scala/tile/BaseTile.scala @@ -21,6 +21,7 @@ trait TileParams { val dcache: Option[DCacheParams] val rocc: Seq[RoCCParams] val btb: Option[BTBParams] + val trace: Boolean } trait HasTileParameters { @@ -37,6 +38,7 @@ trait HasTileParameters { def xLen: Int = p(XLen) def xBytes: Int = xLen / 8 + def iLen: Int = 32 def pgIdxBits: Int = 12 def pgLevelBits: Int = 10 - log2Ceil(xLen / 32) def vaddrBits: Int = pgIdxBits + pgLevels * pgLevelBits @@ -92,6 +94,10 @@ trait HasExternallyDrivenTileConstants extends Bundle with HasTileParameters { val reset_vector = UInt(INPUT, resetVectorLen) } +trait CanHaveInstructionTracePort extends Bundle with HasTileParameters { + val trace = tileParams.trace.option(Vec(tileParams.core.retireWidth, new TracedInstruction).asOutput) +} + /** Base class for all Tiles that use TileLink */ abstract class BaseTile(tileParams: TileParams)(implicit p: Parameters) extends BareTile with HasTileParameters @@ -102,6 +108,7 @@ abstract class BaseTile(tileParams: TileParams)(implicit p: Parameters) extends class BaseTileBundle[+L <: BaseTile](_outer: L) extends BareTileBundle(_outer) with HasTileLinkMasterPortBundle with HasExternallyDrivenTileConstants + with CanHaveInstructionTracePort class BaseTileModule[+L <: BaseTile, +B <: BaseTileBundle[L]](_outer: L, _io: () => B) extends BareTileModule(_outer, _io) with HasTileParameters diff --git a/src/main/scala/tile/Core.scala b/src/main/scala/tile/Core.scala index a4133c8f..97112513 100644 --- a/src/main/scala/tile/Core.scala +++ b/src/main/scala/tile/Core.scala @@ -75,5 +75,6 @@ trait HasCoreIO extends HasTileParameters { val ptw = new DatapathPTWIO().flip val fpu = new FPUCoreIO().flip val rocc = new RoCCCoreIO().flip + val trace = Vec(coreParams.retireWidth, new TracedInstruction).asOutput } } diff --git a/src/main/scala/tile/RocketTile.scala b/src/main/scala/tile/RocketTile.scala index 72467826..a05e3ebd 100644 --- a/src/main/scala/tile/RocketTile.scala +++ b/src/main/scala/tile/RocketTile.scala @@ -19,6 +19,7 @@ case class RocketTileParams( btb: Option[BTBParams] = Some(BTBParams()), dataScratchpadBytes: Int = 0, boundaryBuffers: Boolean = false, + trace: Boolean = false, name: Option[String] = Some("tile"), externalMasterBuffers: Int = 0, externalSlaveBuffers: Int = 0) extends TileParams { @@ -139,6 +140,7 @@ class RocketTileModule(outer: RocketTile) extends BaseTileModule(outer, () => ne val core = Module(p(BuildCore)(outer.p)) decodeCoreInterrupts(core.io.interrupts) // Decode the interrupt vector core.io.hartid := io.hartid // Pass through the hartid + io.trace.foreach { _ := core.io.trace } outer.frontend.module.io.cpu <> core.io.imem outer.frontend.module.io.reset_vector := io.reset_vector outer.frontend.module.io.hartid := io.hartid @@ -196,7 +198,7 @@ abstract class RocketTileWrapper(rtp: RocketTileParams, hartid: Int)(implicit p: } lazy val module = new LazyModuleImp(this) { - val io = new CoreBundle with HasExternallyDrivenTileConstants { + val io = new CoreBundle with HasExternallyDrivenTileConstants with CanHaveInstructionTracePort { val master = masterNode.bundleOut val slave = slaveNode.bundleIn val asyncInterrupts = asyncIntNode.bundleIn @@ -206,6 +208,7 @@ abstract class RocketTileWrapper(rtp: RocketTileParams, hartid: Int)(implicit p: // signals that do not change based on crossing type: rocket.module.io.hartid := io.hartid rocket.module.io.reset_vector := io.reset_vector + io.trace.foreach { _ := rocket.module.io.trace.get } } }