Skip to content

Commit

Permalink
[difftest] update peek_tl event. wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Clo91eaf committed May 29, 2024
1 parent dcd300c commit 0c6cd9f
Show file tree
Hide file tree
Showing 5 changed files with 254 additions and 27 deletions.
6 changes: 4 additions & 2 deletions difftest/t1-simulator/src/difftest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,12 @@ impl Difftest {
let dready = event.parameter.dReady.unwrap();
// check align
let addr = event.parameter.address.unwrap();
let size = 1 << event.parameter.size.unwrap();
if addr % size != 0 {
let size = ( 1 << event.parameter.size.unwrap() ) as usize;
if addr as usize % size != 0 {
error!("unaligned access (addr={addr:08X}, size={size})")
}

let cycle = event.parameter.cycle.unwrap();
let opcode = Opcode::from_u32(opcode);
self
.spike
Expand All @@ -108,6 +109,7 @@ impl Difftest {
data,
corrupt,
dready,
cycle,
})
.unwrap();
}
Expand Down
24 changes: 13 additions & 11 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)]
#[derive(Deserialize, Debug, PartialEq)]
pub enum Opcode {
PutFullData = 0,
PutPartialData = 1,
Expand All @@ -28,8 +28,8 @@ pub struct Parameter {
pub enq: Option<u32>,
pub opcode: Option<u32>,
pub param: Option<u32>,
pub size: Option<u32>,
pub source: Option<u32>,
pub size: Option<usize>,
pub source: Option<u16>,
pub address: Option<u32>,
pub mask: Option<u32>,
pub data: Option<u32>,
Expand All @@ -43,6 +43,7 @@ pub struct Parameter {
pub rd_valid: Option<u32>,
pub rd: Option<u32>,
pub mem: Option<u32>,
pub cycle: Option<u64>,
}

#[derive(Deserialize, Debug)]
Expand All @@ -56,22 +57,23 @@ pub struct PeekTL {
pub idx: u32,
pub opcode: Opcode,
pub param: u32,
pub size: u32,
pub source: u32,
pub size: usize,
pub source: u16,
pub addr: u32,
pub mask: u32,
pub data: u32,
pub corrupt: u32,
pub dready: u32,
pub cycle: u64,
}

pub struct VrfWrite {
pub idx: u32,
pub vd: u32,
pub offset: u32,
pub mask: u32,
pub data: u32,
pub instruction: u32,
pub idx: u32,
pub vd: u32,
pub offset: u32,
pub mask: u32,
pub data: u32,
pub instruction: u32,
}

#[derive(Debug)]
Expand Down
235 changes: 227 additions & 8 deletions difftest/t1-simulator/src/difftest/spike.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use lazy_static::lazy_static;
use std::collections::VecDeque;
use std::collections::{HashMap, VecDeque};
use std::fs::File;
use std::io::Read;
use std::path::Path;
Expand Down Expand Up @@ -155,6 +155,76 @@ pub fn add_rtl_write(se: &mut SpikeEvent, vrf_write: VrfWrite, record_idx_base:
} // end if mask
}) // end for j
}

pub struct TLReqRecord {
data: Vec<u8>,
cycle: usize,
size_by_byte: usize,
addr: u32,
source: u16,

muxin_read_required: bool,
muxin_read_sent: bool,

se: SpikeEvent,

// For writes, as soon as the transaction is sent to the controller, the request is resolved, so we don't have to track the number
// of bytes that have been processed by the memory controller

// Only meaningful for writes, this is the number of bytes written by user.
bytes_received: usize,

// This is the number of bytes(or worth-of transaction for reads) sent to the memory controller
bytes_committed: usize,

// This is the number of bytes that have been processed by the memory controller
bytes_processed: usize,

// For read, number of bytes returned to user
bytes_returned: usize,

op: Opcode,
}

impl TLReqRecord {
pub fn new(
se: &SpikeEvent,
cycle: usize,
data: Vec<u8>,
size_by_byte: usize,
addr: u32,
source: u16,
op: Opcode,
burst_size: usize,
) -> Self {
TLReqRecord {
data,
cycle,
size_by_byte,
addr,
source,
muxin_read_required: op == Opcode::PutFullData && size_by_byte < burst_size,
muxin_read_sent: false,
se: se.clone(),
bytes_received: 0,
bytes_committed: 0,
bytes_processed: 0,
bytes_returned: 0,
op,
}
}

fn skip(&mut self) {
self.muxin_read_required = false;
self.bytes_committed = if self.op == Opcode::PutFullData {
self.bytes_received
} else {
self.size_by_byte
};
self.bytes_processed = self.bytes_committed;
}
}

pub struct SpikeHandle {
spike: Spike,

Expand All @@ -169,6 +239,15 @@ pub struct SpikeHandle {

/// config for v extension
pub config: Config,

/// tl request record of bank, indexed by issue_idx
pub tl_req_record_of_bank: Vec<HashMap<usize, TLReqRecord>>,

/// the get_t() of a req response waiting for ready
pub tl_req_waiting_ready: Vec<Option<usize>>,

/// the get_t() of a req with ongoing burst
pub tl_req_ongoing_burst: Vec<Option<usize>>,
}

impl SpikeHandle {
Expand Down Expand Up @@ -198,6 +277,10 @@ impl SpikeHandle {
spike,
to_rtl_queue: VecDeque::new(),
config: Config { vlen, dlen },
// config.tl_bank_number = 13
tl_req_record_of_bank: (0..13).map(|_| HashMap::new()).collect(),
tl_req_waiting_ready: vec![None; 13],
tl_req_ongoing_burst: vec![None; 13],
}
}

Expand Down Expand Up @@ -397,8 +480,13 @@ impl SpikeHandle {
}

pub fn peek_tl(&mut self, peek_tl: PeekTL) -> anyhow::Result<()> {
let tl_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 base_addr = peek_tl.addr;
let size = peek_tl.size;
let lsu_idx = (peek_tl.source & 3) as u8;
if let Some(se) = self
.to_rtl_queue
Expand All @@ -407,8 +495,8 @@ impl SpikeHandle {
{
match peek_tl.opcode {
Opcode::Get => {
let mut actual_data = vec![0u8; size as usize];
for offset in 0..size {
let mut actual_data = vec![0u8; tl_size];
for offset in 0..tl_size {
let addr = base_addr + offset as u32;
match se.mem_access_record.all_reads.get_mut(&addr) {
Some(mem_read) => {
Expand All @@ -424,13 +512,144 @@ impl SpikeHandle {
}
}

let channel = peek_tl.idx;
let mask = peek_tl.mask;
let source = peek_tl.source;
let hex_actual_data = actual_data
.iter()
.fold(String::new(), |acc, x| acc + &format!("{:02X} ", x));
info!("SpikeReceiveTLReq: <- receive rtl mem get req: channel={channel}, base_addr={base_addr:08X}, size={size}, mask={mask:b}, source={source}, return_data={hex_actual_data}");
info!("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}");

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,
),
);

self
.tl_req_record_of_bank
.get_mut(tl_idx)
.unwrap()
.get_mut(&tl_cycle)
.unwrap()
.skip();
}

Opcode::PutFullData => {
let mut cur_record: Option<&mut TLReqRecord> = None;
// determine if it is a beat of ongoing burst
if let 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.as_ref().unwrap())
{
assert!(
record.bytes_received < record.size_by_byte,
"invalid record"
);
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"
);
info!(
"ReceiveTLReq: continue burst, channel: {tl_idx}, base_addr: {base_addr:08X}, offset: {}",
record.bytes_received
);
cur_record = Some(record);
}
}
}

// else create a new record
if cur_record.is_none() {
// 1 is dummy value, won't be effective whatsoever. 1 is to ensure that no sub-line write is possible
// here we do not use dramsim3.
let record = TLReqRecord::new(
se,
tl_cycle,
vec![0; tl_size],
tl_size,
base_addr,
tl_source,
Opcode::PutFullData,
1,
);
self
.tl_req_record_of_bank
.get_mut(tl_idx)
.unwrap()
.insert(tl_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);
}

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 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
// TODO: fix this
for offset in 0..actual_beat_size {
data[data_begin_pos + offset] = (tl_data >> (offset * 8)) as u8;
}
info!("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}");

// 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 {
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;
let mem_write = se
.mem_access_record
.all_writes
.get_mut(&byte_addr)
.expect(&format!(
"[{tl_cycle}] cannot find mem write of byte_addr {tl_cycle:08X}"
));
assert!(
mem_write.num_completed_writes < mem_write.writes.len(),
"written size should be smaller than 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);
}
}

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));
} else {
self.tl_req_ongoing_burst.remove(tl_idx);
}
}
_ => {
panic!("not implemented")
Expand Down
Loading

0 comments on commit 0c6cd9f

Please sign in to comment.