diff --git a/rocketv/src/RocketCore.scala b/rocketv/src/RocketCore.scala index a215753d6..dabe4a002 100644 --- a/rocketv/src/RocketCore.scala +++ b/rocketv/src/RocketCore.scala @@ -16,9 +16,12 @@ import org.chipsalliance.rvdecoderdb.Instruction class RocketProbe(param: RocketParameter) extends Bundle { // reg file - val rfWen = Bool() - val rfWaddr = UInt(param.lgNXRegs.W) - val rfWdata = UInt(param.xLen.W) + val rfWen: Bool = Bool() + val rfWaddr: UInt = UInt(param.lgNXRegs.W) + val rfWdata: UInt = UInt(param.xLen.W) + + // rocket is idle + val idle: Bool = Bool() } object RocketParameter { @@ -412,6 +415,10 @@ class Rocket(val parameter: RocketParameter) def minFLen: Int = parameter.minFLen.getOrElse(0) def hasDataECC: Boolean = parameter.hasDataECC + // probe defination + val probeWire = Wire(new RocketProbe(parameter)) + define(io.rocketProbe, ProbeValue(probeWire)) + // Signal outside from internal clock domain. val longLatencyStall = Reg(Bool()) @@ -1063,6 +1070,10 @@ class Rocket(val parameter: RocketParameter) ) when(rfWen) { rf.write(rfWaddr, rfWdata) } + probeWire.rfWen := rfWen + probeWire.rfWaddr := rfWaddr + probeWire.rfWdata := rfWdata + // hook up control/status regfile csr.io.ungatedClock := io.clock csr.io.decode(0).inst := idInstruction @@ -1392,9 +1403,10 @@ class Rocket(val parameter: RocketParameter) // Maintain vector counter // There may be 4 instructions in the pipe - val (_, vectorFull) = counterManagement(countWidth, 4)(t1IssueQueue.io.enq.valid, t1.issue.fire) + val (vectorEmpty, vectorFull) = counterManagement(countWidth, 4)(t1IssueQueue.io.enq.valid, t1.issue.fire) vectorLSUEmpty.foreach(_ := lsuEmpty) vectorQueueFull.foreach(_ := vectorFull) + probeWire.idle := vectorEmpty t1XRDRetireQueue.io.enq.valid := t1.retire.rd.valid t1XRDRetireQueue.io.enq.bits := t1.retire.rd.bits @@ -1475,12 +1487,6 @@ class Rocket(val parameter: RocketParameter) // todo: perfEvents here. // csr.io.counters.foreach { c => c.inc := RegNext(perfEvents.evaluate(c.eventSel)) } - // probe xrf write - val probeWire = Wire(new RocketProbe(parameter)) - define(io.rocketProbe, ProbeValue(probeWire)) - probeWire.rfWen := rfWen - probeWire.rfWaddr := rfWaddr - probeWire.rfWdata := rfWdata } def checkExceptions(x: Seq[(Bool, UInt)]) = diff --git a/t1/src/T1.scala b/t1/src/T1.scala index 676ab423a..3729c136d 100644 --- a/t1/src/T1.scala +++ b/t1/src/T1.scala @@ -309,6 +309,7 @@ class T1Probe(parameter: T1Parameter) extends Bundle { val laneProbes: Vec[LaneProbe] = Vec(parameter.laneNumber, new LaneProbe(parameter.laneParam)) val issue: ValidIO[UInt] = Valid(UInt(parameter.instructionIndexBits.W)) val retire: ValidIO[UInt] = Valid(UInt(parameter.xLen.W)) + val idle: Bool = Bool() } class T1Interface(parameter: T1Parameter) extends Record { @@ -1737,6 +1738,7 @@ class T1(val parameter: T1Parameter) probeWire.issue.bits := instructionCounter probeWire.retire.valid := io.retire.rd.valid probeWire.retire.bits := io.retire.rd.bits.rdData + probeWire.idle := slots.map(_.state.idle).reduce(_ && _) // new V Request from core // val requestValidProbe: Bool = IO(Output(Probe(Bool()))) diff --git a/t1rocketemu/offline/src/difftest.rs b/t1rocketemu/offline/src/difftest.rs index 5e59ca60f..23b7facf8 100644 --- a/t1rocketemu/offline/src/difftest.rs +++ b/t1rocketemu/offline/src/difftest.rs @@ -39,9 +39,10 @@ impl Difftest { Ok(()) } JsonEvents::SimulationStop { reason, cycle } => { - info!("simulation stopped at cycle {}, reason {}", cycle, reason); - self.runner.cycle = *cycle; - Ok(()) + anyhow::bail!("error: simulation stopped at cycle {}, reason {}", cycle, reason) + } + JsonEvents::SimulationEnd { cycle } => { + anyhow::bail!("simulation quit successfullly cycle {}", cycle); } JsonEvents::RegWrite { idx, data, cycle } => { self.runner.cycle = *cycle; diff --git a/t1rocketemu/offline/src/dut.rs b/t1rocketemu/offline/src/dut.rs index a4cc80821..d505aa690 100644 --- a/t1rocketemu/offline/src/dut.rs +++ b/t1rocketemu/offline/src/dut.rs @@ -39,7 +39,7 @@ impl Dut { pub fn step(&mut self) -> anyhow::Result<&JsonEvents> { let event = match self.events.get(self.idx as usize) { Some(event) => event, - None => return Err(anyhow::anyhow!("no more events")), + None => anyhow::bail!("error: simulation stopped with no more events"), }; self.idx += 1; diff --git a/t1rocketemu/offline/src/json_events.rs b/t1rocketemu/offline/src/json_events.rs index 585c5372a..00200f0ce 100644 --- a/t1rocketemu/offline/src/json_events.rs +++ b/t1rocketemu/offline/src/json_events.rs @@ -48,6 +48,9 @@ pub(crate) enum JsonEvents { SimulationStart { cycle: u64, }, + SimulationEnd { + cycle: u64, + }, SimulationStop { reason: u8, cycle: u64, diff --git a/t1rocketemu/offline/src/main.rs b/t1rocketemu/offline/src/main.rs index 0328e2cf3..c9382462d 100644 --- a/t1rocketemu/offline/src/main.rs +++ b/t1rocketemu/offline/src/main.rs @@ -49,7 +49,7 @@ fn main() -> anyhow::Result<()> { match diff.diff() { Ok(_) => {} Err(e) => { - info!("Simulation quit/error with {}", e); + info!("{}", e); return Ok(()); } } diff --git a/t1rocketemu/online_dpi/src/dpi.rs b/t1rocketemu/online_dpi/src/dpi.rs index 25488f6a4..632c96a30 100644 --- a/t1rocketemu/online_dpi/src/dpi.rs +++ b/t1rocketemu/online_dpi/src/dpi.rs @@ -295,6 +295,16 @@ unsafe extern "C" fn cosim_watchdog(reason: *mut c_char) { } } +/// evaluate at every cycle, return quit_flag = false to continue simulation, +#[no_mangle] +unsafe extern "C" fn cosim_quit(quit_flag: *mut bool) { + // watchdog dpi call would be called before initialization, guard on null target + let mut driver = DPI_TARGET.lock().unwrap(); + if let Some(driver) = driver.as_mut() { + *quit_flag = driver.quit as bool + } +} + #[no_mangle] unsafe extern "C" fn get_resetvector(resetvector: *mut c_longlong) { let mut driver = DPI_TARGET.lock().unwrap(); @@ -313,9 +323,6 @@ mod dpi_export { #[cfg(feature = "trace")] /// `export "DPI-C" function dump_wave(input string file)` pub fn dump_wave(path: *const c_char); - - /// 'export "DPI-C" function quit()' - pub fn quit(); } } @@ -329,12 +336,3 @@ pub(crate) fn dump_wave(scope: crate::svdpi::SvScope, path: &str) { dpi_export::dump_wave(path_cstring.as_ptr()); } } - -pub(crate) fn quit(scope: crate::svdpi::SvScope) { - use crate::svdpi; - - svdpi::set_scope(scope); - unsafe { - dpi_export::quit(); - } -} \ No newline at end of file diff --git a/t1rocketemu/online_dpi/src/drive.rs b/t1rocketemu/online_dpi/src/drive.rs index db3909ede..4844810e0 100644 --- a/t1rocketemu/online_dpi/src/drive.rs +++ b/t1rocketemu/online_dpi/src/drive.rs @@ -123,6 +123,8 @@ pub(crate) struct Driver { last_commit_cycle: u64, shadow_mem: ShadowMem, + + pub(crate) quit: bool, } #[cfg(feature = "trace")] @@ -185,6 +187,8 @@ impl Driver { last_commit_cycle: 0, shadow_mem, + + quit: false } } @@ -345,8 +349,8 @@ impl Driver { if addr == EXIT_POS { let exit_data_slice = data[..4].try_into().expect("slice with incorrect length"); if u32::from_le_bytes(exit_data_slice) == EXIT_CODE { - info!("exit successfully"); - self.quit() + info!("driver is ready to quit"); + self.quit = true; } } } @@ -399,8 +403,4 @@ impl Driver { fn start_dump_wave(&mut self) { dump_wave(self.scope, &self.wave_path); } - - fn quit(&mut self) { - quit(self.scope) - } } diff --git a/t1rocketemu/src/TestBench.scala b/t1rocketemu/src/TestBench.scala index c8907f1e1..31c97dcff 100644 --- a/t1rocketemu/src/TestBench.scala +++ b/t1rocketemu/src/TestBench.scala @@ -6,7 +6,7 @@ package org.chipsalliance.t1.t1rocketemu import chisel3._ import chisel3.experimental.{BaseModule, ExtModule, SerializableModuleGenerator} import chisel3.experimental.dataview.DataViewable -import chisel3.util.circt.dpi.RawUnclockedNonVoidFunctionCall +import chisel3.util.circt.dpi.{RawClockedNonVoidFunctionCall, RawUnclockedNonVoidFunctionCall} import chisel3.util.{HasExtModuleInline, PopCount, UIntToOH, Valid} import org.chipsalliance.amba.axi4.bundle._ import org.chipsalliance.t1.t1rocketemu.dpi._ @@ -34,11 +34,6 @@ class TestBench(generator: SerializableModuleGenerator[T1RocketTile, T1RocketTil |`endif | endfunction; | - | export "DPI-C" function quit; - | function quit(); - | $$finish; - | endfunction; - | | import "DPI-C" context function void t1rocket_cosim_init(); | initial begin | t1rocket_cosim_init(); @@ -224,7 +219,9 @@ class TestBench(generator: SerializableModuleGenerator[T1RocketTile, T1RocketTil ) // t1 lsu enq - when(t1Probe.lsuProbe.reqEnq.orR)(printf(cf"""{"event":"LsuEnq","enq":${t1Probe.lsuProbe.reqEnq},"cycle":${simulationTime}}\n""")) + when(t1Probe.lsuProbe.reqEnq.orR)( + printf(cf"""{"event":"LsuEnq","enq":${t1Probe.lsuProbe.reqEnq},"cycle":${simulationTime}}\n""") + ) // t1 vrf scoreboard val vrfWriteScoreboard: Seq[Valid[UInt]] = Seq.tabulate(2 * generator.parameter.t1Parameter.chainingSize) { _ => @@ -264,4 +261,11 @@ class TestBench(generator: SerializableModuleGenerator[T1RocketTile, T1RocketTil scoreboard.bits := 0.U } } + + // t1 quit + val quitFlag: Bool = RegInit(false.B) + quitFlag := RawClockedNonVoidFunctionCall("cosim_quit", Bool())(clock, !quitFlag) + when(quitFlag && t1Probe.idle && rocketProbe.idle) { + stop(cf"""{"event":"SimulationEnd", "cycle":${simulationTime}}\n""") + } }