diff --git a/rocketemu/src/TestBench.scala b/rocketemu/src/TestBench.scala index 1a6fc2d2b..035012337 100644 --- a/rocketemu/src/TestBench.scala +++ b/rocketemu/src/TestBench.scala @@ -74,7 +74,7 @@ class TestBench(generator: SerializableModuleGenerator[RocketTile, RocketTilePar // output probes val rocketProbe = probe.read(dut.io.rocketProbe) - when(rocketProbe.rob.trace.rfWen && rocketProbe.rob.trace.rfWaddr =/= 0.U)(printf(cf"""{"event":"RegWrite","addr":${rocketProbe.rob.trace.rfWaddr},"data":${rocketProbe.rob.trace.rfWdata},"cycle":${simulationTime}}\n""")) + when(rocketProbe.rfWen && rocketProbe.rfWaddr =/= 0.U)(printf(cf"""{"event":"RegWrite","addr":${rocketProbe.rfWaddr},"data":${rocketProbe.rfWdata},"cycle":${simulationTime}}\n""")) // Memory Drivers val instFetchAXI = dut.io.instructionFetchAXI.viewAs[AXI4ROIrrevocableVerilog] diff --git a/rocketv/src/RocketCore.scala b/rocketv/src/RocketCore.scala index f573bcc3c..29fe04016 100644 --- a/rocketv/src/RocketCore.scala +++ b/rocketv/src/RocketCore.scala @@ -1096,8 +1096,8 @@ class Rocket(val parameter: RocketParameter) probeWire.rfWdata := rfWdata // TODO: add wait enable - // probeWire.waitEn := - // probeWire.waitAddr := + probeWire.waitWen := wbSetSboard && wbWen + probeWire.waitWaddr := wbWaddr // FIXME: vectorCSR probeWire.isVector := io.t1.map { t1 => diff --git a/t1rocketemu/.rustfmt.toml b/t1rocketemu/.rustfmt.toml index 7b6c82e24..bf1a32fd3 100644 --- a/t1rocketemu/.rustfmt.toml +++ b/t1rocketemu/.rustfmt.toml @@ -1,4 +1,4 @@ hard_tabs = false tab_spaces = 2 chain_width = 100 -struct_lit_width = 50 \ No newline at end of file +struct_lit_width = 50 diff --git a/t1rocketemu/offline/src/difftest.rs b/t1rocketemu/offline/src/difftest.rs index 5b2891e38..f1eb0cfd1 100644 --- a/t1rocketemu/offline/src/difftest.rs +++ b/t1rocketemu/offline/src/difftest.rs @@ -1,6 +1,5 @@ use common::spike_runner::SpikeRunner; use std::path::Path; -use tracing::info; use common::rtl_config::RTLConfig; use common::CommonArgs; @@ -48,6 +47,14 @@ impl Difftest { self.runner.cycle = *cycle; self.runner.peek_reg_write(&RegWriteEvent { idx: *idx, data: *data, cycle: *cycle }) } + JsonEvents::RegWriteWait { idx, cycle } => { + self.runner.cycle = *cycle; + self.runner.peek_reg_write_wait(&RegWriteWaitEvent { idx: *idx, cycle: *cycle }) + } + JsonEvents::FregWrite { idx, data, cycle } => { + self.runner.cycle = *cycle; + self.runner.peek_freg_write(&RegWriteEvent { idx: *idx, data: *data, cycle: *cycle }) + } JsonEvents::Issue { idx, cycle } => { self.runner.cycle = *cycle; self.runner.peek_issue(&IssueEvent { idx: *idx, cycle: *cycle }) diff --git a/t1rocketemu/offline/src/json_events.rs b/t1rocketemu/offline/src/json_events.rs index 8bf41bdf4..81fe0a1cf 100644 --- a/t1rocketemu/offline/src/json_events.rs +++ b/t1rocketemu/offline/src/json_events.rs @@ -61,6 +61,17 @@ pub(crate) enum JsonEvents { data: u32, cycle: u64, }, + RegWriteWait { + idx: u8, + cycle: u64, + }, + FregWrite { + idx: u8, + #[serde(deserialize_with = "str_to_u32", default)] + data: u32, + cycle: u64, + }, + Issue { idx: u8, cycle: u64, @@ -109,6 +120,11 @@ pub struct RegWriteEvent { pub cycle: u64, } +pub struct RegWriteWaitEvent { + pub idx: u8, + pub cycle: u64, +} + pub struct IssueEvent { pub idx: u8, pub cycle: u64, @@ -152,6 +168,10 @@ pub struct CheckRdEvent { pub(crate) trait JsonEventRunner { fn peek_reg_write(&mut self, reg_write: &RegWriteEvent) -> anyhow::Result<()>; + fn peek_reg_write_wait(&mut self, reg_write: &RegWriteWaitEvent) -> anyhow::Result<()>; + + fn peek_freg_write(&mut self, reg_write: &RegWriteEvent) -> anyhow::Result<()>; + fn peek_issue(&mut self, issue: &IssueEvent) -> anyhow::Result<()>; fn update_lsu_idx(&mut self, lsu_enq: &LsuEnqEvent) -> anyhow::Result<()>; @@ -175,7 +195,20 @@ impl JsonEventRunner for SpikeRunner { let idx = reg_write.idx; let data = reg_write.data; - let se = self.find_rf_se(); + if let Some(board_data) = self.rf_board[idx as usize] { + info!( + "[{cycle}] RegWrite: Hit board! idx={idx}, rtl data={data:#08x}, board data={board_data:#08x}", + ); + + assert!( + data == board_data, + "rtl data({data:#x}) should be equal to board data({board_data:#x})" + ); + + return Ok(()); + } + + let se = self.find_reg_se(); info!( "[{cycle}] RegWrite: rtl idx={idx}, data={data:#08x}; se idx={}, data={:#08x} ({})", @@ -198,6 +231,58 @@ impl JsonEventRunner for SpikeRunner { Ok(()) } + fn peek_reg_write_wait(&mut self, reg_write: &RegWriteWaitEvent) -> anyhow::Result<()> { + let cycle = reg_write.cycle; + let idx = reg_write.idx; + + let se = self.find_reg_se(); + + info!( + "[{cycle}] RegWriteWait: rtl idx={idx}; se idx={}, data={:#08x} ({})", + se.rd_idx, + se.rd_bits, + se.describe_insn() + ); + + assert!( + idx as u32 == se.rd_idx, + "rtl idx({idx:#x}) should be equal to spike idx({:#x})", + se.rd_idx + ); + + self.rf_board[idx as usize] = Some(se.rd_bits); + + Ok(()) + } + + fn peek_freg_write(&mut self, reg_write: &RegWriteEvent) -> anyhow::Result<()> { + let cycle = reg_write.cycle; + let idx = reg_write.idx; + let data = reg_write.data; + + let se = self.find_freg_se(); + + info!( + "[{cycle}] FregWrite: rtl idx={idx}, data={data:#08x}; se idx={}, data={:#08x} ({})", + se.rd_idx, + se.rd_bits, + se.describe_insn() + ); + + assert!( + idx as u32 == se.rd_idx, + "rtl idx({idx:#x}) should be equal to spike idx({:#x})", + se.rd_idx + ); + assert!( + data == se.rd_bits, + "rtl data({data:#x}) should be equal to spike data({:#x})", + se.rd_bits + ); + + Ok(()) + } + fn peek_issue(&mut self, issue: &IssueEvent) -> anyhow::Result<()> { let mut se = self.find_v_se(); // ensure the front of queue is a new un-issued se diff --git a/t1rocketemu/spike_rs/src/spike_event.rs b/t1rocketemu/spike_rs/src/spike_event.rs index 7743b0f92..f91932760 100644 --- a/t1rocketemu/spike_rs/src/spike_event.rs +++ b/t1rocketemu/spike_rs/src/spike_event.rs @@ -92,6 +92,7 @@ pub struct SpikeEvent { // mutable states pub is_rd_written: bool, + pub is_fd_written: bool, pub vd_write_record: VdWriteRecord, pub mem_access_record: MemAccessRecord, pub vrf_access_record: VrfAccessRecord, @@ -142,6 +143,7 @@ impl SpikeEvent { rd_bits: Default::default(), is_rd_written: false, + is_fd_written: false, vd_write_record: Default::default(), mem_access_record: Default::default(), vrf_access_record: Default::default(), @@ -418,7 +420,7 @@ impl SpikeEvent { 0b0001 => { self.rd_idx = rd_idx_type >> 4; let data = state.get_reg(self.rd_idx, true); - self.is_rd_written = true; + self.is_fd_written = true; self.rd_bits = data; trace!( "FloatRFChange: idx={:#02x}, data={:08x}", diff --git a/t1rocketemu/src/TestBench.scala b/t1rocketemu/src/TestBench.scala index 3b110e50a..aa1fd6f6b 100644 --- a/t1rocketemu/src/TestBench.scala +++ b/t1rocketemu/src/TestBench.scala @@ -9,7 +9,6 @@ import chisel3.experimental.dataview.DataViewable import chisel3.util.circt.dpi.{RawClockedNonVoidFunctionCall, RawUnclockedNonVoidFunctionCall} import chisel3.util.{HasExtModuleInline, Mux1H, PopCount, Queue, UIntToOH, Valid} import org.chipsalliance.amba.axi4.bundle._ -import org.chipsalliance.rocketv.RocketROB import org.chipsalliance.t1.t1rocketemu.dpi._ import org.chipsalliance.t1.tile.{T1RocketTile, T1RocketTileParameter} @@ -177,33 +176,30 @@ class TestBench(generator: SerializableModuleGenerator[T1RocketTile, T1RocketTil // output the probes // rocket reg write - when(rocketProbe.rfWen && !rocketProbe.isVector)( + when(rocketProbe.rfWen && !rocketProbe.isVector && rocketProbe.rfWaddr =/= 0.U)( printf( cf"""{"event":"RegWrite","idx":${rocketProbe.rfWaddr},"data":"${rocketProbe.rfWdata}%x","cycle":${simulationTime}}\n""" ) ) - // TODO: refactor this wait logic - // when(rocketProbe.waitWen && !rocketProbe.isVector)( // should this judge vector? - // printf( - // cf"""{"event":"RegWriteWait","idx":${rocketProbe.waitWaddr},"cycle":${simulationTime}}\n""" - // ) - // ) + when(rocketProbe.waitWen && !rocketProbe.isVector && rocketProbe.waitWaddr =/= 0.U)( // should this judge vector? + printf( + cf"""{"event":"RegWriteWait","idx":${rocketProbe.waitWaddr},"cycle":${simulationTime}}\n""" + ) + ) // [[option]] rocket fpu reg write t1RocketProbe.fpuProbe.foreach { fpu => - when(fpu.rfWen)( + when(fpu.pipeWrite.rfWen)( printf( - cf"""{"event":"FregWrite","idx":${fpu.rfWaddr},"data":"${fpu.rfWdata}%x","cycle":${simulationTime}}\n""" + cf"""{"event":"FregWrite","idx":${fpu.pipeWrite.rfWaddr},"data":"${fpu.pipeWrite.rfWdata}%x","cycle":${simulationTime}}\n""" + ) + ) + when(fpu.loadOrVectorWrite.rfWen && !rocketProbe.isVector)( + printf( + cf"""{"event":"FregWrite","idx":${fpu.loadOrVectorWrite.rfWaddr},"data":"${fpu.loadOrVectorWrite.rfWdata}%x","cycle":${simulationTime}}\n""" ) ) - - // TODO: refactor this wait logic - // when(fpu.waitWen && !fpu.isVector)( // should this judge vector? - // printf( - // cf"""{"event":"FregWriteWait","idx":${fpu.waitWaddr},"cycle":${simulationTime}}\n""" - // ) - // ) } // t1 vrf write diff --git a/t1rocketemu/test_common/src/spike_runner.rs b/t1rocketemu/test_common/src/spike_runner.rs index 3b8189c74..5d6758b2b 100644 --- a/t1rocketemu/test_common/src/spike_runner.rs +++ b/t1rocketemu/test_common/src/spike_runner.rs @@ -25,10 +25,12 @@ pub struct SpikeRunner { /// dependency, the vector instruction should be issued in order. pub vector_queue: VecDeque, - /// vector queue to arrange the order of vector instructions, because of the register write - /// dependency, the vector instruction should be issued in order. + /// scalar queue to arrange the order of scalar reg / freg write instructions pub scalar_queue: VecDeque, + /// scalar queue to arrange the order of scalar reg / freg write instructions + pub float_queue: VecDeque, + /// config for v extension pub vlen: u32, pub dlen: u32, @@ -37,6 +39,8 @@ pub struct SpikeRunner { pub cycle: u64, pub do_log_vrf: bool, + + pub rf_board: Vec>, } impl SpikeRunner { @@ -58,10 +62,12 @@ impl SpikeRunner { commit_queue: VecDeque::new(), vector_queue: VecDeque::new(), scalar_queue: VecDeque::new(), + float_queue: VecDeque::new(), vlen: args.vlen, dlen: args.dlen, cycle: 0, do_log_vrf, + rf_board: vec![None; 32], } } @@ -122,7 +128,7 @@ impl SpikeRunner { event } - pub fn find_rf_se(&mut self) -> SpikeEvent { + pub fn find_reg_se(&mut self) -> SpikeEvent { if !self.scalar_queue.is_empty() { // return the back (oldest) scalar insn self.scalar_queue.pop_back().unwrap() @@ -130,7 +136,28 @@ impl SpikeRunner { // else, loop until find a se, and push the se to the front loop { let se = self.spike_step(); - if se.is_scalar() && se.is_rd_written && se.rd_idx != 0 { + if se.is_scalar() && se.is_rd_written { + return se; + } else if se.is_fd_written { + self.float_queue.push_front(se.clone()); + } else if se.is_v() { + self.vector_queue.push_front(se.clone()); + } + } + } + } + + pub fn find_freg_se(&mut self) -> SpikeEvent { + if !self.float_queue.is_empty() { + // return the back (oldest) float insn + self.float_queue.pop_back().unwrap() + } else { + // else, loop until find a se, and push the se to the front + loop { + let se = self.spike_step(); + if se.is_scalar() && se.is_rd_written { + self.scalar_queue.push_front(se.clone()); + } else if se.is_fd_written { return se; } else if se.is_v() { self.vector_queue.push_front(se.clone()); @@ -147,8 +174,10 @@ impl SpikeRunner { // else, loop until find a se, and push the se to the front loop { let se = self.spike_step(); - if se.is_scalar() && se.is_rd_written && se.rd_idx != 0 { + if se.is_scalar() && se.is_rd_written { self.scalar_queue.push_front(se.clone()); + } else if se.is_fd_written { + self.float_queue.push_front(se.clone()); } else if se.is_v() { return se; }