Skip to content

Commit

Permalink
[difftest] fix wrong tl_req_ongoing_burst update
Browse files Browse the repository at this point in the history
  • Loading branch information
Clo91eaf committed May 30, 2024
1 parent 4298a67 commit b03f146
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 80 deletions.
4 changes: 2 additions & 2 deletions difftest/t1-simulator/src/difftest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl Difftest {
let mask = event.parameter.mask.unwrap();
let data = event.parameter.data.unwrap();
let corrupt = event.parameter.corrupt.unwrap();
let dready = event.parameter.dready.unwrap();
let dready = event.parameter.dready.unwrap() != 0;
let cycle = event.parameter.cycle.unwrap();
// check align
let addr = event.parameter.address.unwrap();
Expand All @@ -107,7 +107,7 @@ impl Difftest {
let opcode = Opcode::from_u32(opcode);
self
.spike
.peek_tl(PeekTLEvent {
.peek_tl(&PeekTLEvent {
idx,
opcode,
param,
Expand Down
6 changes: 3 additions & 3 deletions difftest/t1-simulator/src/difftest/dut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use serde::Deserialize;
use std::io::BufRead;
use std::path::Path;

#[derive(Deserialize, Debug, PartialEq)]
#[derive(Deserialize, Debug, PartialEq, Clone)]
pub enum Opcode {
PutFullData = 0,
PutPartialData = 1,
Expand Down Expand Up @@ -34,7 +34,7 @@ pub struct Parameter {
pub mask: Option<u32>,
pub data: Option<u32>,
pub corrupt: Option<u32>,
pub dready: Option<u32>,
pub dready: Option<u8>,
pub vd: Option<u32>,
pub offset: Option<u32>,
pub instruction: Option<u32>,
Expand Down Expand Up @@ -73,7 +73,7 @@ pub struct PeekTLEvent {
pub mask: u32,
pub data: u32,
pub corrupt: u32,
pub dready: u32,
pub dready: bool,
pub cycle: usize,
}

Expand Down
190 changes: 116 additions & 74 deletions difftest/t1-simulator/src/difftest/spike.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use super::dut::*;

const MSHR: usize = 3;
const LSU_IDX_DEFAULT: u8 = 0xff;
const DATAPATH_WIDTH_IN_BYTES: usize = 8; // 8 = config.datapath_width_in_bytes = beatbyte = lsuBankParameters(0).beatbyte for blastoise

// read the addr from spike memory
// caller should make sure the address is valid
Expand Down Expand Up @@ -156,6 +157,7 @@ pub fn add_rtl_write(se: &mut SpikeEvent, vrf_write: VrfWriteEvent, record_idx_b
}) // end for j
}

#[derive(Debug, Clone)]
pub struct TLReqRecord {
data: Vec<u8>,
cycle: usize,
Expand Down Expand Up @@ -223,6 +225,23 @@ impl TLReqRecord {
};
self.bytes_processed = self.bytes_committed;
}

fn commit_tl_respones(&mut self, tl_bytes: usize) -> anyhow::Result<()> {
self.bytes_returned += tl_bytes;

Ok(())
}

fn done_return(&mut self) -> anyhow::Result<bool> {
if self.muxin_read_required {
return Ok(false);
}
if self.op == Opcode::PutFullData {
return Ok(self.bytes_returned > 0);
} else {
return Ok(self.bytes_returned >= self.size_by_byte);
}
}
}

pub struct SpikeHandle {
Expand Down Expand Up @@ -480,14 +499,57 @@ impl SpikeHandle {
Ok(())
}

pub fn peek_tl(&mut self, peek_tl: &PeekTLEvent) -> anyhow::Result<()> {
// config.tl_bank_number
assert!(peek_tl.idx < 13);
self.receive_tl_d_ready(peek_tl).unwrap();
self.receive_tl_req(peek_tl).unwrap();
Ok(())
}

pub fn receive_tl_d_ready(&mut self, peek_tl: &PeekTLEvent) -> anyhow::Result<()> {
let idx = peek_tl.idx as usize;
if !peek_tl.dready {
return Ok(());
}

if let Some(addr) = self.tl_req_waiting_ready[idx] {
let req_record = self.tl_req_record_of_bank[idx]
.get_mut(&addr)
.expect(&format!(
"cannot find current request with addr {:08X}",
addr
));

req_record
.commit_tl_respones(DATAPATH_WIDTH_IN_BYTES)
.unwrap();

if req_record.done_return().unwrap() {
info!(
"ReceiveTlDReady channel: {idx}, addr: {addr:08x}, -> tl response for {} reaches d_ready",
match req_record.op {
Opcode::Get => "Get",
_ => "PutFullData",
}
);
}

self.tl_req_waiting_ready[idx] = None;

// TODO(Meow): add this check back
// panic!(format!("unknown opcode {}", req_record.op as i32));
}
Ok(())
}
// the info in peek tl should have cycle to debug
pub fn peek_tl(&mut self, peek_tl: PeekTLEvent) -> anyhow::Result<()> {
let tl_idx = peek_tl.idx as usize;
pub fn receive_tl_req(&mut self, peek_tl: &PeekTLEvent) -> anyhow::Result<()> {
let idx = peek_tl.idx as usize;
let tl_data = peek_tl.data;
let tl_mask = peek_tl.mask;
let tl_cycle = peek_tl.cycle as usize;
let tl_size = peek_tl.size;
let tl_source = peek_tl.source;
let mask = peek_tl.mask;
let cycle = peek_tl.cycle as usize;
let size = peek_tl.size;
let source = peek_tl.source;
let base_addr = peek_tl.addr;
let lsu_idx = (peek_tl.source & 3) as u8;
if let Some(se) = self
Expand All @@ -497,8 +559,8 @@ impl SpikeHandle {
{
match peek_tl.opcode {
Opcode::Get => {
let mut actual_data = vec![0u8; tl_size];
for offset in 0..tl_size {
let mut actual_data = vec![0u8; size];
for offset in 0..size {
let addr = base_addr + offset as u32;
match se.mem_access_record.all_reads.get_mut(&addr) {
Some(mem_read) => {
Expand All @@ -507,7 +569,7 @@ impl SpikeHandle {
}
None => {
// TODO: check if the cache line should be accessed
warn!("[{tl_cycle}] ReceiveTLReq addr: {addr:08X} insn: {} send falsy data 0xDE for accessing unexpected memory", format!("{:x}", se.inst_bits));
warn!("[{cycle}] ReceiveTLReq addr: {addr:08X} insn: {} send falsy data 0xDE for accessing unexpected memory", format!("{:x}", se.inst_bits));
actual_data[offset as usize] = 0xDE; // falsy data
}
}
Expand All @@ -516,31 +578,25 @@ impl SpikeHandle {
let hex_actual_data = actual_data
.iter()
.fold(String::new(), |acc, x| acc + &format!("{:02X} ", x));
info!("[{tl_cycle}] SpikeReceiveTLReq: <- receive rtl mem get req: channel={tl_idx}, base_addr={base_addr:08X}, size={tl_size}, mask={tl_mask:b}, source={tl_source}, return_data={hex_actual_data}");
info!("[{cycle}] SpikeReceiveTLReq: <- receive rtl mem get req: channel={idx}, base_addr={base_addr:08X}, size={size}, mask={mask:b}, source={source}, return_data={hex_actual_data}");

self
.tl_req_record_of_bank
.get_mut(tl_idx as usize)
.unwrap()
.insert(
tl_cycle,
TLReqRecord::new(
se,
tl_cycle,
actual_data,
tl_size,
base_addr,
tl_source,
Opcode::Get,
1,
),
);
trace!("get tl_req_record_of_bank[{idx}] insert [{cycle}]");
self.tl_req_record_of_bank[idx].insert(
cycle,
TLReqRecord::new(
se,
cycle,
actual_data,
size,
base_addr,
source,
Opcode::Get,
1,
),
);

self
.tl_req_record_of_bank
.get_mut(tl_idx)
.unwrap()
.get_mut(&tl_cycle)
self.tl_req_record_of_bank[idx]
.get_mut(&cycle)
.unwrap()
.skip();
}
Expand All @@ -549,26 +605,19 @@ impl SpikeHandle {
let mut cur_record: Option<&mut TLReqRecord> = None;
// determine if it is a beat of ongoing burst
// the first Some match the result of get, the second Some match the result determined by if the
// tl_req_ongoing_burst[tl_idx] is Some / None
if let Some(Some(tl_req_ongoing_burst)) = self.tl_req_ongoing_burst.get(tl_idx) {
if let Some(record) = self
.tl_req_record_of_bank
.get_mut(tl_idx)
.unwrap()
.get_mut(tl_req_ongoing_burst)
{
assert!(
record.bytes_received < record.size_by_byte,
"[{tl_cycle}] invalid record"
);
// tl_req_ongoing_burst[idx] is Some / None
if let Some(tl_req_ongoing_burst) = self.tl_req_ongoing_burst[idx] {
if let Some(record) = self.tl_req_record_of_bank[idx].get_mut(&tl_req_ongoing_burst) {
if record.bytes_received < record.size_by_byte {
assert_eq!(record.addr, base_addr, "inconsistent burst addr");
assert_eq!(record.size_by_byte, tl_size, "inconsistent burst size");
assert_eq!(record.size_by_byte, size, "inconsistent burst size");
info!(
"[{tl_cycle}] ReceiveTLReq: continue burst, channel: {tl_idx}, base_addr: {base_addr:08X}, offset: {}",
"[{cycle}] ReceiveTLReq: continue burst, channel: {idx}, base_addr: {base_addr:08X}, offset: {}",
record.bytes_received
);
cur_record = Some(record);
} else {
panic!("[{cycle}] invalid record")
}
}
}
Expand All @@ -579,46 +628,39 @@ impl SpikeHandle {
// here we do not use dramsim3.
let record = TLReqRecord::new(
se,
tl_cycle,
vec![0; tl_size],
tl_size,
cycle,
vec![0; size],
size,
base_addr,
tl_source,
source,
Opcode::PutFullData,
1,
);
self
.tl_req_record_of_bank
.get_mut(tl_idx)
.unwrap()
.insert(tl_cycle, record);
trace!("put full is none: get tl_req_record_of_bank[{idx}] insert [{cycle}]");
self.tl_req_record_of_bank[idx].insert(cycle, record);

// record moved into self.tl_req_record_of_bank, so we should get it from there
cur_record = self
.tl_req_record_of_bank
.get_mut(tl_idx)
.unwrap()
.get_mut(&tl_cycle);
cur_record = self.tl_req_record_of_bank[idx].get_mut(&cycle);
}

let mut data = vec![0u8; tl_size];
// datapath_width_in_bytes = 32(datapath_width) / 8(bit / byte)
let actual_beat_size = std::cmp::min(tl_size, 4); // since tl require alignment
let mut data = vec![0u8; size];
let actual_beat_size = std::cmp::min(size, DATAPATH_WIDTH_IN_BYTES); // since tl require alignment
let data_begin_pos = cur_record.as_ref().unwrap().bytes_received;

// receive put data
// if actual beat size is bigger than 4, there maybe some problems
// if actual beat size is bigger than 8, there maybe some problems
// TODO: fix this
for offset in 0..actual_beat_size {
data[data_begin_pos + offset] = (tl_data >> (offset * 8)) as u8;
}
info!("[{tl_cycle}] RTLMemPutReq: <- receive rtl mem put req, channel: {tl_idx}, base_addr: {base_addr:08X}, offset: {data_begin_pos}, size: {tl_size}, source: {tl_source:04X}, data: {tl_data:08X}, mask: {tl_mask:04X}");
info!("[{cycle}] RTLMemPutReq: <- receive rtl mem put req, channel: {idx}, base_addr: {base_addr:08X}, offset: {data_begin_pos}, size: {size}, source: {source:04X}, data: {tl_data:08X}, mask: {mask:04X}");

// compare with spike event record
for offset in 0..actual_beat_size {
// config.datapath_width_in_bytes - 1 = 3
let byte_lane_idx = (base_addr & 3) + offset as u32;
if tl_mask >> byte_lane_idx & 1 != 0 {
// if byte_lane_idx > 32, there maybe some problem
if (mask >> byte_lane_idx) & 1 != 0 {
let byte_addr =
base_addr + cur_record.as_ref().unwrap().bytes_received as u32 + offset as u32;
let tl_data_byte = (tl_data >> 8 * byte_lane_idx) as u8;
Expand All @@ -627,28 +669,28 @@ impl SpikeHandle {
.all_writes
.get_mut(&byte_addr)
.expect(&format!(
"[{tl_cycle}] cannot find mem write of byte_addr {tl_cycle:08X}"
"[{cycle}] cannot find mem write of byte_addr {byte_addr:08x}"
));
assert!(
mem_write.num_completed_writes < mem_write.writes.len(),
"[{tl_cycle}] written size should be smaller than completed writes"
"[{cycle}] written size:{} should be smaller than completed writes:{}",
mem_write.writes.len(),
mem_write.num_completed_writes
);
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, tl_data_byte, "[{tl_cycle}] expect mem write of byte {single_mem_write_val:02X}, actual byte {tl_data_byte:02X} (channel={tl_idx}, byte_addr={byte_addr:08X}, pc = {:#x}, disasm = {})", se.pc, se.disasm);
assert_eq!(single_mem_write_val, tl_data_byte, "[{cycle}] expect mem write of byte {single_mem_write_val:02X}, actual byte {tl_data_byte:02X} (channel={idx}, byte_addr={byte_addr:08X}, pc = {:#x}, disasm = {})", se.pc, se.disasm);
}
}

cur_record.as_mut().unwrap().bytes_received += actual_beat_size;
cur_record.as_mut().unwrap().skip();

// update tl_req_ongoing_burst
if cur_record.as_ref().unwrap().bytes_received < tl_size {
self
.tl_req_ongoing_burst
.insert(tl_idx, Some(cur_record.as_ref().unwrap().cycle));
if cur_record.as_ref().unwrap().bytes_received < size {
self.tl_req_ongoing_burst[idx] = Some(cur_record.as_ref().unwrap().cycle);
} else {
self.tl_req_ongoing_burst.remove(tl_idx);
self.tl_req_ongoing_burst[idx] = None;
}
}
_ => {
Expand Down
2 changes: 1 addition & 1 deletion ipemu/src/TestBench.scala
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class TestBench(generator: SerializableModuleGenerator[T1, T1Parameter]) extends

withClockAndReset(clock, reset) {
// count cycle for peek tl
val cycleCounter = RegInit(0.U(64.W))
val cycleCounter = RegInit(0.U(32.W))
cycleCounter := cycleCounter + 1.U

// memory write
Expand Down

0 comments on commit b03f146

Please sign in to comment.