diff --git a/rocketemu/driver/result b/rocketemu/driver/result deleted file mode 120000 index 9b374c6d3f..0000000000 --- a/rocketemu/driver/result +++ /dev/null @@ -1 +0,0 @@ -/nix/store/2yl3kijw09n499mipba5irh61q1s18sb-riscv-tests-riscv32-none-elf-7878085d2546af0eb7af72a1df00996d5d8c43fb \ No newline at end of file diff --git a/rocketemu/offline/src/difftest.rs b/rocketemu/offline/src/difftest.rs index 66a0173d9b..573fbb7567 100644 --- a/rocketemu/offline/src/difftest.rs +++ b/rocketemu/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; @@ -29,61 +28,26 @@ impl Difftest { } pub fn diff(&mut self) -> anyhow::Result<()> { - self.runner.check_and_clear_fence(); - - let event = self.dut.step()?; - - match event { - JsonEvents::SimulationStart { cycle } => { - self.runner.cycle = *cycle; - Ok(()) - } - JsonEvents::SimulationStop { reason, cycle } => { - info!("simulation stopped at cycle {}, reason {}", cycle, reason); - self.runner.cycle = *cycle; - Ok(()) - } - JsonEvents::Issue { idx, cycle } => { - self.runner.cycle = *cycle; - self.runner.peek_issue(&IssueEvent { idx: *idx, cycle: *cycle }) - } - JsonEvents::MemoryWrite { mask, data, lsu_idx, address, cycle } => { - self.runner.cycle = *cycle; - self.runner.peek_memory_write(&MemoryWriteEvent { - mask: mask.clone(), - data: data.clone(), - lsu_idx: *lsu_idx, - address: *address, - cycle: *cycle, - }) - } - JsonEvents::LsuEnq { enq, cycle } => { - self.runner.cycle = *cycle; - self.runner.update_lsu_idx(&LsuEnqEvent { enq: *enq, cycle: *cycle }) - } - JsonEvents::VrfWrite { issue_idx, vd, offset, mask, data, lane, cycle } => { - self.runner.cycle = *cycle; - self.runner.peek_vrf_write(&VrfWriteEvent { - issue_idx: *issue_idx, - vd: *vd, - offset: *offset, - mask: mask.clone(), - data: data.clone(), - lane: *lane, - cycle: *cycle, - }) - } - JsonEvents::CheckRd { data, issue_idx, cycle } => { - self.runner.cycle = *cycle; - self.runner.check_rd(&CheckRdEvent { data: *data, issue_idx: *issue_idx, cycle: *cycle }) - } - JsonEvents::VrfScoreboardReport { count, issue_idx, cycle } => { - self.runner.cycle = *cycle; - self.runner.vrf_scoreboard_report(&VrfScoreboardReportEvent { - count: *count, - issue_idx: *issue_idx, - cycle: *cycle, - }) + loop { + let se = self.runner.spike_step(); + if se.is_exit() { + return Err(anyhow::anyhow!("exit detected")); + } + if se.is_rd_written() && se.rd_idx != 0 { + let event = self.dut.step()?; + + match event { + JsonEvents::RegWrite { addr, data, cycle } => { + self.runner.cycle = *cycle; + self.runner.check_reg_write( + &RegWriteEvent { addr: *addr, data: *data, cycle: *cycle }, + &se, + )? + } + JsonEvents::SimulationStop { reason, cycle } => { + return Err(anyhow::anyhow!("[{}] simulation stop: {}", *cycle, *reason)); + } + } } } } diff --git a/rocketemu/offline/src/json_events.rs b/rocketemu/offline/src/json_events.rs index 24652f04db..ed61c23daf 100644 --- a/rocketemu/offline/src/json_events.rs +++ b/rocketemu/offline/src/json_events.rs @@ -1,409 +1,39 @@ use common::spike_runner::SpikeRunner; -use num_bigint::BigUint; -use serde::{Deserialize, Deserializer}; -use spike_rs::spike_event::LSU_IDX_DEFAULT; -use tracing::{debug, info}; - -#[derive(Deserialize, Debug, PartialEq, Clone)] -pub enum Opcode { - PutFullData = 0, - PutPartialData = 1, - Get = 4, - // AccessAckData = 0, - // AccessAck = 0, -} - -fn bigint_to_vec_u8<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let s: &str = Deserialize::deserialize(deserializer)?; - let bigint = BigUint::parse_bytes(s.trim_start().as_bytes(), 16) - .ok_or_else(|| serde::de::Error::custom("Failed to parse BigUint from hex string"))?; - Ok(bigint.to_bytes_le()) -} - -fn bigint_to_vec_bool<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let s: &str = Deserialize::deserialize(deserializer)?; - let bigint = BigUint::parse_bytes(s.trim_start().as_bytes(), 16) - .ok_or_else(|| serde::de::Error::custom("Failed to parse BigUint from hex string"))?; - let bytes = bigint.to_bytes_le(); - let bools = bytes.iter().flat_map(|byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)).collect(); - - Ok(bools) -} - -fn hex_to_u32<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let s: &str = Deserialize::deserialize(deserializer)?; - let value = - u32::from_str_radix(s.trim_start_matches(' '), 16).map_err(serde::de::Error::custom)?; - - Ok(value) -} - -fn mask_display(mask: &Vec) -> String { - mask.into_iter().map(|&b| if b { '1' } else { '0' }).collect() -} +use serde::Deserialize; +use spike_rs::spike_event::SpikeEvent; +use tracing::info; #[derive(Deserialize, Debug)] #[serde(tag = "event")] pub(crate) enum JsonEvents { - SimulationStart { - cycle: u64, - }, - SimulationStop { - reason: u8, - cycle: u64, - }, - Issue { - idx: u8, - cycle: u64, - }, - LsuEnq { - enq: u32, - cycle: u64, - }, - VrfWrite { - issue_idx: u8, - vd: u32, - offset: u32, - #[serde(deserialize_with = "bigint_to_vec_bool", default)] - mask: Vec, - #[serde(deserialize_with = "bigint_to_vec_u8", default)] - data: Vec, - lane: u32, - cycle: u64, - }, - MemoryWrite { - #[serde(deserialize_with = "bigint_to_vec_bool", default)] - mask: Vec, - #[serde(deserialize_with = "bigint_to_vec_u8", default)] - data: Vec, - lsu_idx: u8, - #[serde(deserialize_with = "hex_to_u32", default)] - address: u32, - cycle: u64, - }, - CheckRd { - #[serde(deserialize_with = "hex_to_u32", default)] - data: u32, - issue_idx: u8, - cycle: u64, - }, - VrfScoreboardReport { - count: u32, - issue_idx: u8, - cycle: u64, - }, -} - -pub struct IssueEvent { - pub idx: u8, - pub cycle: u64, -} - -pub struct LsuEnqEvent { - pub enq: u32, - pub cycle: u64, -} - -pub struct VrfWriteEvent { - pub lane: u32, - pub vd: u32, - pub offset: u32, - pub mask: Vec, - pub data: Vec, - pub issue_idx: u8, - pub cycle: u64, -} - -pub struct MemoryWriteEvent { - pub mask: Vec, - pub data: Vec, - pub lsu_idx: u8, - pub address: u32, - pub cycle: u64, + RegWrite { addr: u32, data: u32, cycle: u64 }, + SimulationStop { reason: u8, cycle: u64 }, } -pub struct VrfScoreboardReportEvent { - pub count: u32, - pub issue_idx: u8, - pub cycle: u64, -} - -pub struct CheckRdEvent { +pub struct RegWriteEvent { + pub addr: u32, pub data: u32, - pub issue_idx: u8, pub cycle: u64, } pub(crate) trait JsonEventRunner { - fn peek_issue(&mut self, issue: &IssueEvent) -> anyhow::Result<()>; - - fn update_lsu_idx(&mut self, lsu_enq: &LsuEnqEvent) -> anyhow::Result<()>; - - fn peek_vrf_write(&mut self, vrf_write: &VrfWriteEvent) -> anyhow::Result<()>; - - fn vrf_scoreboard_report(&mut self, report: &VrfScoreboardReportEvent) -> anyhow::Result<()>; - - fn peek_memory_write(&mut self, memory_write: &MemoryWriteEvent) -> anyhow::Result<()>; - - fn check_and_clear_fence(&mut self); - - fn check_rd(&mut self, check_rd: &CheckRdEvent) -> anyhow::Result<()>; - - fn retire(&mut self, cycle: u64, issue_idx: u8) -> anyhow::Result<()>; + fn check_reg_write(&mut self, reg_write: &RegWriteEvent, se: &SpikeEvent) -> anyhow::Result<()>; } impl JsonEventRunner for SpikeRunner { - fn peek_issue(&mut self, issue: &IssueEvent) -> anyhow::Result<()> { - self.find_v_se_to_issue(); // ensure the front of queue is a new un-issued se - let se = self.commit_queue.front_mut().unwrap(); - if se.is_vfence() { - return Ok(()); - } - - se.issue_idx = issue.idx as u8; + fn check_reg_write(&mut self, reg_write: &RegWriteEvent, se: &SpikeEvent) -> anyhow::Result<()> { + let addr = reg_write.addr; + let data = reg_write.data; + let cycle = reg_write.cycle; + info!("[{cycle}] RegWrite: idx={addr:02x}, data={data:08x}",); info!( - "[{}] SpikePeekIssue: issue_idx={}, pc={:#x}, inst={}", - issue.cycle, issue.idx, se.pc, se.disasm + "[{cycle}] SpikeEvent: idx={:02x}, data={:08x}", + se.rd_idx, se.rd_bits ); + assert_eq!(addr, se.rd_idx, "addr should be equal to se.rd_idx"); + assert_eq!(data, se.rd_bits, "data should be equal to se.rd_bits"); Ok(()) } - - fn update_lsu_idx(&mut self, lsu_enq: &LsuEnqEvent) -> anyhow::Result<()> { - let enq = lsu_enq.enq; - assert!(enq > 0, "enq should be greater than 0"); - let cycle = lsu_enq.cycle; - - if let Some(se) = self - .commit_queue - .iter_mut() - .rev() - .find(|se| (se.is_vload() || se.is_vstore()) && se.lsu_idx == LSU_IDX_DEFAULT) - { - let index = enq.trailing_zeros() as u8; - se.lsu_idx = index; - info!( - "[{cycle}] UpdateLSUIdx: instr ({}) is allocated with lsu_idx: {index}", - se.describe_insn() - ); - } - Ok(()) - } - - fn peek_vrf_write(&mut self, vrf_write: &VrfWriteEvent) -> anyhow::Result<()> { - let cycle = vrf_write.cycle; - let vlen_in_bytes = self.vlen / 8; - let lane_number = self.dlen / 32; - let record_idx_base = (vrf_write.vd * vlen_in_bytes - + (vrf_write.lane + lane_number * vrf_write.offset) * 4) as usize; - - let mut retire_issue: Option = None; - - if let Some(se) = - self.commit_queue.iter_mut().rev().find(|se| se.issue_idx == vrf_write.issue_idx) - { - debug!( - "[{}] VrfWrite: lane={}, vd={}, idx_base={}, issue_idx={}, offset={}, mask={}, data={:x?} ({})", - vrf_write.cycle, - vrf_write.lane, - record_idx_base, - vrf_write.vd, - vrf_write.issue_idx, - vrf_write.offset, - mask_display(&vrf_write.mask), - vrf_write.data, - se.describe_insn() - ); - - if let Some(unretired_writes) = se.vrf_access_record.unretired_writes { - assert!( - unretired_writes > 0, - "[{}] unretired_writes should be greater than 0, issue_idx={} ({})", - vrf_write.cycle, - vrf_write.issue_idx, - se.describe_insn() - ); - if unretired_writes == 1 { - retire_issue = Some(vrf_write.issue_idx); - } - se.vrf_access_record.unretired_writes = Some(unretired_writes - 1); - } else { - se.vrf_access_record.retired_writes += 1; - } - - vrf_write.mask.iter().enumerate().filter(|(_, &mask)| mask).for_each(|(offset, _)| { - let written_byte = *vrf_write.data.get(offset).unwrap_or(&0); - - if let Some(record) = se.vrf_access_record.all_writes.get_mut(&(record_idx_base + offset)) { - assert_eq!( - record.byte, - written_byte, - "[{}] {offset}th byte incorrect ({:02x} record != {written_byte:02x} written) \ - for vrf write (lane={}, vd={}, offset={}, mask={}, data={:x?}) \ - issue_idx={} [vrf_idx={}] (disasm: {}, pc: {:#x}, bits: {:#x})", - vrf_write.cycle, - record.byte, - vrf_write.lane, - vrf_write.vd, - vrf_write.offset, - mask_display(&vrf_write.mask), - vrf_write.data, - se.issue_idx, - record_idx_base + offset, - se.disasm, - se.pc, - se.inst_bits - ); - record.executed = true; - } else { - debug!( - "[{}] cannot find vrf write record, maybe not changed (lane={}, vd={}, idx={}, offset={}, mask={}, data={:x?})", - vrf_write.cycle, - vrf_write.lane, - vrf_write.vd, - record_idx_base + offset, - vrf_write.offset, - mask_display(&vrf_write.mask), - vrf_write.data - ); - } - }) - } else { - info!( - "[{cycle}] RecordRFAccess: rtl detect vrf write on lane={}, vd={} \ - with no matched se (issue_idx={}), \ - maybe from committed load insn", - vrf_write.lane, vrf_write.vd, vrf_write.issue_idx - ); - } - - if let Some(issue_idx) = retire_issue { - self.retire(cycle, issue_idx).unwrap(); - } - - Ok(()) - } - - fn peek_memory_write(&mut self, memory_write: &MemoryWriteEvent) -> anyhow::Result<()> { - let data = memory_write.data.to_owned(); - let mask = memory_write.mask.to_owned(); - let cycle = memory_write.cycle; - let base_addr = memory_write.address; - let lsu_idx = memory_write.lsu_idx; - - if let Some(se) = self.commit_queue.iter_mut().find(|se| se.lsu_idx == lsu_idx) { - info!("[{cycle}] MemoryWrite: address={base_addr:08x}, size={}, data={data:x?}, mask={}, pc = {:#x}, disasm = {}", data.len(), mask_display(&mask), se.pc, se.disasm); - // compare with spike event record - mask.iter().enumerate() - .filter(|(_, &mask)| mask) - .for_each(|(offset, _)| { - let byte_addr = base_addr + offset as u32; - let data_byte = *data.get(offset).unwrap_or(&0); - let mem_write = - se.mem_access_record.all_writes.get_mut(&byte_addr).unwrap_or_else(|| { - panic!("[{cycle}] cannot find mem write of byte_addr {byte_addr:08x}") - }); - let single_mem_write_val = mem_write.writes[mem_write.num_completed_writes].val; - mem_write.num_completed_writes += 1; - assert_eq!(single_mem_write_val, data_byte, "[{cycle}] expect mem write of byte {single_mem_write_val:02X}, actual byte {data_byte:02X} (byte_addr={byte_addr:08X}, pc = {:#x}, disasm = {})", se.pc, se.disasm); - }); - return Ok(()); - } - - panic!("[{cycle}] cannot find se with instruction lsu_idx={lsu_idx}") - } - - fn vrf_scoreboard_report(&mut self, report: &VrfScoreboardReportEvent) -> anyhow::Result<()> { - let count = report.count; - let issue_idx = report.issue_idx; - let cycle = report.cycle; - - let mut should_retire: Option = None; - - if let Some(se) = self.commit_queue.iter_mut().rev().find(|se| se.issue_idx == issue_idx) { - assert!( - se.vrf_access_record.retired_writes <= count, - "[{cycle}] retired_writes({}) should be less than count({count}), issue_idx={issue_idx} ({})", - se.vrf_access_record.retired_writes, se.describe_insn() - ); - - // if instruction writes rd, it will retire in check_rd() - if count == se.vrf_access_record.retired_writes && !se.is_rd_written { - should_retire = Some(issue_idx); - } - // if all writes are committed, retire the se - se.vrf_access_record.unretired_writes = Some(count - se.vrf_access_record.retired_writes); - - info!( - "[{cycle}] VrfScoreboardReport: count={count}, issue_idx={issue_idx}, retired={} ({})", - se.vrf_access_record.retired_writes, - se.describe_insn() - ); - } else { - panic!("[{cycle}] cannot find se with instruction issue_idx={issue_idx}"); - } - - if let Some(issue_idx) = should_retire { - self.retire(cycle, issue_idx).unwrap(); - } - - Ok(()) - } - - /// after update, if instructions before fence are cleared, fence is also cleared - fn check_and_clear_fence(&mut self) { - if !self.commit_queue.is_empty() { - let se = self.commit_queue.back().unwrap(); - - if se.is_vfence() && self.commit_queue.len() == 1 { - self.commit_queue.pop_back(); - } - } - } - - fn check_rd(&mut self, check_rd: &CheckRdEvent) -> anyhow::Result<()> { - let data = check_rd.data; - let cycle = check_rd.cycle; - let issue_idx = check_rd.issue_idx; - - let se = - self.commit_queue.iter_mut().find(|se| se.issue_idx == issue_idx).unwrap_or_else(|| { - panic!("[{cycle}] cannot find se with instruction issue_idx={issue_idx}") - }); - - info!("[{cycle}] CheckRd: issue_idx={issue_idx}, data={data:x?}"); - - se.check_rd(data).expect("Failed to check_rd"); - - self.retire(cycle, issue_idx).unwrap(); - - Ok(()) - } - - fn retire(&mut self, cycle: u64, issue_idx: u8) -> anyhow::Result<()> { - if let Some(idx) = self.commit_queue.iter().position(|se| se.issue_idx == issue_idx) { - if let Some(se) = self.commit_queue.remove(idx) { - info!( - "[{cycle}] Retire: retire se with issue_idx={issue_idx}, ({})", - se.describe_insn() - ); - se.check_is_ready_for_commit(cycle).unwrap(); - } else { - panic!("[{cycle}] Retire: cannot remove se with instruction issue_idx={issue_idx}") - } - } else { - panic!("[{cycle}] Retire: cannot find se with instruction issue_idx={issue_idx}") - } - Ok(()) - } } diff --git a/rocketemu/spike_rs/src/spike_event.rs b/rocketemu/spike_rs/src/spike_event.rs index 611f7156b9..7f6a2f0305 100644 --- a/rocketemu/spike_rs/src/spike_event.rs +++ b/rocketemu/spike_rs/src/spike_event.rs @@ -95,6 +95,8 @@ pub struct SpikeEvent { pub vd_write_record: VdWriteRecord, pub mem_access_record: MemAccessRecord, pub vrf_access_record: VrfAccessRecord, + + pub exit: bool, } impl SpikeEvent { @@ -143,6 +145,8 @@ impl SpikeEvent { vd_write_record: Default::default(), mem_access_record: Default::default(), vrf_access_record: Default::default(), + + exit: false, } } @@ -210,6 +214,10 @@ impl SpikeEvent { self.opcode() == 0b0100011 || self.is_cw() } + pub fn is_rd_written(&self) -> bool { + self.is_rd_written + } + pub fn is_whole(&self) -> bool { self.mop() == 0 && self.lumop() == 8 } @@ -223,14 +231,7 @@ impl SpikeEvent { } pub fn is_exit(&self) -> bool { - let is_csr_type = self.opcode() == 0b1110011 && ((self.width() & 0b011) != 0); - let is_csr_write = is_csr_type && (((self.width() & 0b100) | self.rs1()) != 0); - - is_csr_write && self.csr() == 0x7cc - } - - pub fn is_vfence(&self) -> bool { - self.is_exit() // only exit instruction is treated as fence now + self.exit } pub fn is_rd_fp(&self) -> bool { @@ -282,114 +283,11 @@ impl SpikeEvent { pub fn describe_insn(&self) -> String { format!( "pc={:#x}, disasm='{}', bits={:#x}", - self.pc, self.disasm, self.inst_bits + self.pc as u32, self.disasm, self.inst_bits ) } - pub fn get_vrf_write_range(&self, vlen_in_bytes: u32) -> anyhow::Result<(u32, u32)> { - if self.is_vstore() { - return Ok((0, 0)); - } - - if self.is_vload() { - let vd_bytes_start = self.rd_idx * vlen_in_bytes; - if self.is_whole() { - return Ok((vd_bytes_start, vlen_in_bytes * (1 + self.vnf))); - } - let len = if self.vlmul() & 0b100 != 0 { - vlen_in_bytes * (1 + self.vnf) - } else { - (vlen_in_bytes * (1 + self.vnf)) << self.vlmul() - }; - return Ok((vd_bytes_start, len)); - } - - let vd_bytes_start = self.rd_idx * vlen_in_bytes; - - if self.is_mask_vd() { - return Ok((vd_bytes_start, vlen_in_bytes)); - } - - let len = if self.vlmul() & 0b100 != 0 { - vlen_in_bytes >> (8 - self.vlmul()) - } else { - vlen_in_bytes << self.vlmul() - }; - - Ok(( - vd_bytes_start, - if self.is_widening() { len * 2 } else { len }, - )) - } - - pub fn pre_log_arch_changes(&mut self, spike: &Spike, vlen: u32) -> anyhow::Result<()> { - if self.do_log_vrf { - self.rd_bits = spike.get_proc().get_rd(); - - // record the vrf writes before executing the insn - let vlen_in_bytes = vlen; - - let proc = spike.get_proc(); - let (start, len) = self.get_vrf_write_range(vlen_in_bytes).unwrap(); - self.vd_write_record.vd_bytes.resize(len as usize, 0u8); - for i in 0..len { - let offset = start + i; - let vreg_index = offset / vlen_in_bytes; - let vreg_offset = offset % vlen_in_bytes; - let cur_byte = proc.get_vreg_data(vreg_index, vreg_offset); - self.vd_write_record.vd_bytes[i as usize] = cur_byte; - } - } - - Ok(()) - } - - pub fn log_arch_changes(&mut self, spike: &Spike, vlen: u32) -> anyhow::Result<()> { - if self.do_log_vrf { - self.log_vrf_write(spike, vlen).unwrap(); - self.log_reg_write(spike).unwrap(); - } - self.log_mem_write(spike).unwrap(); - self.log_mem_read(spike).unwrap(); - - Ok(()) - } - - fn log_vrf_write(&mut self, spike: &Spike, vlen: u32) -> anyhow::Result<()> { - let proc = spike.get_proc(); - // record vrf writes - // note that we do not need log_reg_write to find records, we just decode the - // insn and compare bytes - let vlen_in_bytes = vlen / 8; - let (start, len) = self.get_vrf_write_range(vlen_in_bytes).unwrap(); - trace!("vrf write range: start: {start}, len: {len}"); - for i in 0..len { - let offset = start + i; - let origin_byte = self.vd_write_record.vd_bytes[i as usize]; - let vreg_index = offset / vlen_in_bytes; - let vreg_offset = offset % vlen_in_bytes; - let cur_byte = proc.get_vreg_data(vreg_index, vreg_offset); - if origin_byte != cur_byte { - self - .vrf_access_record - .all_writes - .entry(offset as usize) - .or_insert(SingleVrfWrite { byte: cur_byte, executed: false }); - trace!( - "SpikeVRFChange: vrf={:?}, change_from={origin_byte}, change_to={cur_byte}, vrf_idx={offset}", - vec![offset / vlen_in_bytes, offset % vlen_in_bytes], - ); - } else { - trace!( - "SpikeVRFChange: vrf={:?}, change_from={origin_byte}, not changed, vrf_idx={offset}", - vec![offset / vlen_in_bytes, offset % vlen_in_bytes], - ); - } - } - Ok(()) - } - - fn log_reg_write(&mut self, spike: &Spike) -> anyhow::Result<()> { + pub fn log_reg_write(&mut self, spike: &Spike) -> anyhow::Result<()> { let proc = spike.get_proc(); let state = proc.get_state(); // in spike, log_reg_write is arrange: @@ -405,29 +303,17 @@ impl SpikeEvent { // scalar rf let data = state.get_reg(self.rd_idx, false); self.is_rd_written = true; - if data != self.rd_bits { - trace!( - "ScalarRFChange: idx={}, change_from={}, change_to={data}", - self.rd_idx, - self.rd_bits - ); - self.rd_bits = data; - } + self.rd_bits = data; + trace!("ScalarRFChange: idx={:02x}, data={:08x}", self.rd_idx, self.rd_bits); } 0b0001 => { let data = state.get_reg(self.rd_idx, true); self.is_rd_written = true; - if data != self.rd_bits { - trace!( - "FloatRFChange: idx={}, change_from={}, change_to={data}", - self.rd_idx, - self.rd_bits - ); - self.rd_bits = data; - } + self.rd_bits = data; + trace!("FloatRFChange: idx={:02x}, data={:08x}", self.rd_idx, self.rd_bits); } _ => trace!( - "UnknownRegChange, idx={}, spike detect unknown reg change", + "UnknownRegChange, idx={:02x}, spike detect unknown reg change", state.get_reg_write_index(idx) ), }); @@ -455,69 +341,12 @@ impl SpikeEvent { }); }); trace!("SpikeMemWrite: addr={addr:x}, value={value:x}, size={size}"); + if addr == 0x4000_0000 && value == 0xdead_beef && size == 4 { + self.exit = true; + return; + } }); Ok(()) } - - fn log_mem_read(&mut self, spike: &Spike) -> anyhow::Result<()> { - let proc = spike.get_proc(); - let state = proc.get_state(); - - let mem_read_size = state.get_mem_read_size(); - (0..mem_read_size).for_each(|i| { - let (addr, size) = state.get_mem_read(i); - let mut value = 0; - (0..size).for_each(|offset| { - let byte = spike.mem_byte_on_addr(addr as usize + offset as usize).unwrap(); - value |= (byte as u64) << (offset * 8); - // record the read - self - .mem_access_record - .all_reads - .entry(addr + offset as u32) - .or_insert(MemReadRecord { reads: vec![], num_completed_reads: 0 }) - .reads - .push(SingleMemRead { val: byte, executed: false }); - }); - trace!("SpikeMemRead: addr={addr:08x}, value={value:08x}, size={size}"); - }); - - Ok(()) - } - - pub fn check_rd(&self, data: u32) -> anyhow::Result<()> { - // TODO: rtl should indicate whether resp_bits_data is valid - if self.is_rd_written { - assert_eq!( - data, self.rd_bits, - "expect to write rd[{}] = {}, actual {}", - self.rd_idx, self.rd_bits, data - ); - } - - Ok(()) - } - - pub fn check_is_ready_for_commit(&self, cycle: u64) -> anyhow::Result<()> { - for (addr, record) in &self.mem_access_record.all_writes { - assert_eq!( - record.num_completed_writes, - record.writes.len(), - "[{cycle}] expect to write mem {addr:#x}, not executed when commit, issue_idx={} ({})", - self.issue_idx, - self.describe_insn(), - ); - } - for (idx, record) in &self.vrf_access_record.all_writes { - assert!( - record.executed, - "[{cycle}] expect to write vrf {idx}, not executed when commit, issue_idx={} ({})", - self.issue_idx, - self.describe_insn() - ); - } - - Ok(()) - } } diff --git a/rocketemu/src/TestBench.scala b/rocketemu/src/TestBench.scala index 63d93a80d6..0350123371 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.rfWen)(printf(cf"""{"event":"RegWrite","addr":${rocketProbe.rfWaddr},"data":${rocketProbe.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/rocketemu/test_common/src/lib.rs b/rocketemu/test_common/src/lib.rs index ae582b77dc..17851612ec 100644 --- a/rocketemu/test_common/src/lib.rs +++ b/rocketemu/test_common/src/lib.rs @@ -41,7 +41,7 @@ pub static MEM_SIZE: usize = 1usize << 32; impl CommonArgs { pub fn to_spike_c_handler(&self) -> Box { let arch = &format!("vlen:{},elen:32", self.vlen); - let lvl = "M"; + let lvl = "MSU"; Spike::new(arch, &self.set, lvl, (self.dlen / 32) as usize, MEM_SIZE) } diff --git a/rocketemu/test_common/src/spike_runner.rs b/rocketemu/test_common/src/spike_runner.rs index 2d69d46429..24e0a2e29d 100644 --- a/rocketemu/test_common/src/spike_runner.rs +++ b/rocketemu/test_common/src/spike_runner.rs @@ -1,4 +1,3 @@ -use std::collections::VecDeque; use std::path::Path; use tracing::debug; @@ -11,16 +10,6 @@ use crate::CommonArgs; pub struct SpikeRunner { spike: Box, - /// commit queue - /// in the spike thread, spike should detech if this queue is full, if not - /// full, execute until a vector instruction, record the behavior of this - /// instruction, and send to commit queue. - /// Note: - /// - The event issued earliest is at the back of the queue - /// - The queue may contain at most one unissued event. If so, the unissued event must be at the - /// front of the queue, and it must be a fence - pub commit_queue: VecDeque, - /// config for v extension pub vlen: u32, pub dlen: u32, @@ -50,7 +39,6 @@ impl SpikeRunner { SpikeRunner { spike, - commit_queue: VecDeque::new(), vlen: args.vlen, dlen: args.dlen, cycle: 0, @@ -91,34 +79,14 @@ impl SpikeRunner { state.set_mcycle((self.cycle + self.spike_cycle) as usize); - let pc = state.get_pc(); - let disasm = proc.disassemble(); - let insn_bits = proc.get_insn(); - let mut event = SpikeEvent::new(spike, self.do_log_vrf); state.clear(); - let new_pc = if event.is_v() || event.is_exit() { - // inst is v / quit - debug!( - "SpikeStep: spike run vector insn ({}), is_vfence={}", - event.describe_insn(), - event.is_vfence(), - ); - event.pre_log_arch_changes(spike, self.vlen).unwrap(); - let new_pc_ = proc.func(); - event.log_arch_changes(spike, self.vlen).unwrap(); - new_pc_ - } else { - // inst is scalar - debug!( - "SpikeStep: spike run scalar insn (pc={:#x}, disasm={}, bits={:#x})", - pc, disasm, insn_bits, - ); - let new_pc_ = proc.func(); - event.log_mem_write(spike).unwrap(); - new_pc_ - }; + // inst is scalar + debug!("SpikeStep: spike run scalar insn ({})", event.describe_insn()); + let new_pc = proc.func(); + event.log_mem_write(spike).unwrap(); + event.log_reg_write(spike).unwrap(); state.handle_pc(new_pc).unwrap(); @@ -126,20 +94,4 @@ impl SpikeRunner { event } - - pub fn find_v_se_to_issue(&mut self) -> SpikeEvent { - if !self.commit_queue.is_empty() && self.commit_queue.front().unwrap().is_vfence() { - // if the front (latest) se is a vfence, return the vfence - self.commit_queue.front().unwrap().clone() - } else { - // else, loop until find a se, and push the se to the front - loop { - let se = self.spike_step(); - if se.is_v() { - self.commit_queue.push_front(se.clone()); - break se.clone(); - } - } - } - } }