Skip to content

Commit

Permalink
[difftest] add memory write check
Browse files Browse the repository at this point in the history
[ipemu] move rtl logic from StoreUnit to TestBench

[ipemu] fix wrong storeUnitProbeValid in testBench

[difftest] add memory write check. wip

[ipemu] probe source should use selectIndex

[ipemu] fix wrong data width of StoreUnitProbeSlot

[ipemu] add mask ""

[difftest] fix mask with vec<bool> type

[difftest] fix wrong mask width

[ipemu] add other unit probe

[difftest] refactor the memory write

[ipemu] fix other unit probe
  • Loading branch information
Clo91eaf committed Jul 4, 2024
1 parent 27cfca4 commit 7b117fa
Show file tree
Hide file tree
Showing 11 changed files with 270 additions and 87 deletions.
35 changes: 35 additions & 0 deletions difftest/t1-simulator/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions difftest/t1-simulator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ anyhow = "1.0.79"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
lazy_static = "1.4.0"
num-bigint = "0.4.6"

120 changes: 76 additions & 44 deletions difftest/t1-simulator/src/difftest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,88 +82,120 @@ impl Difftest {

let event = self.dut.step()?;

let cycle = event.parameter.cycle.unwrap();
self.spike.cycle = cycle;
match &*event.event {
"peekTL" => {}
"memoryWrite" => {
let data = event.parameter.data.clone().unwrap();
let mask = event.parameter.mask.clone().unwrap();
let address = event.parameter.address.unwrap();
let source = event.parameter.source.unwrap();
self.spike.peek_memory_write(MemoryWriteEvent {
mask,
data,
source,
address,
cycle,
})
}
"issue" => {
let idx = event.parameter.idx.unwrap();
let cycle = event.parameter.cycle.unwrap();
self.spike.cycle = cycle;
self.peek_issue(IssueEvent { idx, cycle }).unwrap();
self.peek_issue(IssueEvent { idx, cycle })
}
"lsuEnq" => {
let enq = event.parameter.enq.unwrap();
let cycle = event.parameter.cycle.unwrap();
self.spike.cycle = cycle;
self.update_lsu_idx(LsuEnqEvent { enq, cycle }).unwrap();
self.update_lsu_idx(LsuEnqEvent { enq, cycle })
}
"vrfWriteFromLsu" => {
let idx = event.parameter.idx.unwrap();
let vd = event.parameter.vd.unwrap();
let offset = event.parameter.offset.unwrap();
let mask = event.parameter.mask.unwrap();
let data = event.parameter.data.unwrap();
let mask = event.parameter.mask.clone().unwrap();
let data = event.parameter.data.clone().unwrap();
let instruction = event.parameter.instruction.unwrap();
let lane = event.parameter.lane.unwrap();
let cycle = event.parameter.cycle.unwrap();
self.spike.cycle = cycle;
assert!(idx < self.spike.config.dlen / 32);

self
.spike
.peek_vrf_write_from_lsu(VrfWriteEvent {
idx: lane.trailing_zeros(),
vd,
offset,
mask,
data,
instruction,
cycle,
})
.unwrap();
assert!(data.len() <= 4, "data length should be less than 4");
let mut data_array = [0u8; 4];
data
.iter()
.enumerate()
.for_each(|(i, &byte)| data_array[i] = byte);
let data = u32::from_le_bytes(data_array);
// convert mask to u8
let mask = mask
.iter()
.rev()
.fold(0, |acc, &bit| (acc << 1) | bit as u8);

self.spike.peek_vrf_write_from_lsu(VrfWriteEvent {
idx: lane.trailing_zeros(),
vd,
offset,
mask,
data,
instruction,
cycle,
})
}
"vrfWriteFromLane" => {
let idx = event.parameter.idx.unwrap();
let vd = event.parameter.vd.unwrap();
let offset = event.parameter.offset.unwrap();
let mask = event.parameter.mask.unwrap();
let data = event.parameter.data.unwrap();
let mask = event.parameter.mask.clone().unwrap();
let data = event.parameter.data.clone().unwrap();
let instruction = event.parameter.instruction.unwrap();
let cycle = event.parameter.cycle.unwrap();
self.spike.cycle = cycle;
assert!(idx < self.spike.config.dlen / 32);
self
.spike
.peek_vrf_write_from_lane(VrfWriteEvent {
idx,
vd,
offset,
mask,
data,
instruction,
cycle,
})
.unwrap();

assert!(data.len() <= 4, "data length should be less than 4");
let mut array = [0u8; 4];
data
.iter()
.enumerate()
.for_each(|(i, &byte)| array[i] = byte);
let data = u32::from_le_bytes(array);
// convert mask to u8
let mask = mask
.iter()
.rev()
.fold(0, |acc, &bit| (acc << 1) | bit as u8);

self.spike.peek_vrf_write_from_lane(VrfWriteEvent {
idx,
vd,
offset,
mask,
data,
instruction,
cycle,
})
}
"inst" => {
let data = event.parameter.data.unwrap() as u32;
let cycle = event.parameter.cycle.unwrap();
self.spike.cycle = cycle;
let data = event.parameter.data.clone().unwrap();
// let vxsat = event.parameter.vxsat.unwrap();
// let rd_valid = event.parameter.rd_valid.unwrap();
// let rd = event.parameter.rd.unwrap();
// let mem = event.parameter.mem.unwrap();

assert!(data.len() <= 4, "data length should be less than 4");
let mut array = [0u8; 4];
data
.iter()
.enumerate()
.for_each(|(i, &byte)| array[i] = byte);
let data = u32::from_le_bytes(array);

let se = self.spike.to_rtl_queue.back().unwrap();
se.record_rd_write(data).unwrap();
se.check_is_ready_for_commit(cycle).unwrap();

self.spike.to_rtl_queue.pop_back();
Ok(())
}
_ => {
panic!("unknown event: {}", event.event)
}
}

Ok(())
}
}
69 changes: 54 additions & 15 deletions difftest/t1-simulator/src/difftest/dut.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,43 @@
use serde::Deserialize;
use num_bigint::BigUint;
use serde::{Deserialize, Deserializer};
use std::io::BufRead;
use std::path::Path;
use std::str::FromStr;

#[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<Option<Vec<u8>>, D::Error>
where
D: Deserializer<'de>,
{
let opt: Option<&str> = Option::deserialize(deserializer)?;
match opt {
Some(s) => {
let bigint =
BigUint::from_str(s.trim_start_matches(' ')).map_err(serde::de::Error::custom)?;
Ok(Some(bigint.to_bytes_le()))
}
None => Ok(None),
}
}

fn bigint_to_vec_bool<'de, D>(deserializer: D) -> Result<Option<Vec<bool>>, D::Error>
where
D: Deserializer<'de>,
{
let opt: Option<&str> = Option::deserialize(deserializer)?;
match opt {
Some(s) => {
let bigint =
BigUint::from_str(s.trim_start_matches(' ')).map_err(serde::de::Error::custom)?;
let bytes = bigint.to_bytes_le();
let bools = bytes
.iter()
.flat_map(|byte| (0..8).map(move |i| (byte >> i) & 1 == 1))
.collect();

Ok(Some(bools))
}
None => Ok(None),
}
}

#[derive(Deserialize, Debug)]
Expand All @@ -18,15 +47,17 @@ pub struct Parameter {
pub opcode: Option<u32>,
pub param: Option<u32>,
pub size: Option<usize>,
pub source: Option<u16>,
pub source: Option<u8>,
pub address: Option<u32>,
pub mask: Option<u32>,
pub data: Option<u64>,
#[serde(deserialize_with = "bigint_to_vec_bool", default)]
pub mask: Option<Vec<bool>>,
#[serde(deserialize_with = "bigint_to_vec_u8", default)]
pub data: Option<Vec<u8>>,
pub corrupt: Option<u32>,
pub dready: Option<u8>,
pub vd: Option<u32>,
pub offset: Option<u32>,
pub instruction: Option<u32>,
pub instruction: Option<u8>,
pub lane: Option<u32>,
pub vxsat: Option<u32>,
pub rd_valid: Option<u32>,
Expand All @@ -51,13 +82,21 @@ pub struct LsuEnqEvent {
pub cycle: usize,
}

pub struct MemoryWriteEvent {
pub mask: Vec<bool>,
pub data: Vec<u8>,
pub source: u8,
pub address: u32,
pub cycle: usize,
}

pub struct VrfWriteEvent {
pub idx: u32,
pub vd: u32,
pub offset: u32,
pub mask: u32,
pub data: u64,
pub instruction: u32,
pub mask: u8,
pub data: u32,
pub instruction: u8,
pub cycle: usize,
}

Expand Down
38 changes: 38 additions & 0 deletions difftest/t1-simulator/src/difftest/spike.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,4 +401,42 @@ impl SpikeHandle {
info!("[{cycle}] RecordRFAccess: index={} rtl detect vrf write which cannot find se, maybe from committed load insn", vrf_write.idx);
Ok(())
}

pub fn peek_memory_write(&mut self, memory_write: MemoryWriteEvent) -> anyhow::Result<()> {
let mut mask = memory_write.mask;
mask.resize(self.config.dlen as usize / 8, false);
let mut data = memory_write.data;
data.resize(self.config.dlen as usize / 8, 0u8);
let cycle = memory_write.cycle;
let base_addr = memory_write.address;
let source = memory_write.source;

if let Some(se) = self
.to_rtl_queue
.iter_mut()
.find(|se| se.lsu_idx == source)
{
info!("[{cycle}] MemoryWrite: address={base_addr:08x}, size={}, data={data:?}, mask={mask:?}, pc = {:#x}, disasm = {}", data.len(), se.pc, se.disasm);
// compare with spike event record
for offset in 0..data.len() {
if mask[offset] {
let byte_addr = base_addr + offset as u32;
let data_byte = data[offset];
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 source={source}")
}
}
Loading

0 comments on commit 7b117fa

Please sign in to comment.