Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cleanup: refactor t1emurocke dpi code to support various DLEN #855

Merged
merged 8 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
882 changes: 441 additions & 441 deletions .github/designs/rookidee/t1rocketemu.json

Large diffs are not rendered by default.

75 changes: 37 additions & 38 deletions designs/org.chipsalliance.t1.elaborator.t1rocketemu.TestBench.toml

Large diffs are not rendered by default.

74 changes: 37 additions & 37 deletions designs/org.chipsalliance.t1.elaborator.t1rocketv.T1RocketTile.toml

Large diffs are not rendered by default.

116 changes: 81 additions & 35 deletions difftest/dpi_t1rocketemu/src/dpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use dpi_common::plusarg::PlusArgMatcher;
use dpi_common::DpiTarget;
use std::ffi::{c_char, c_longlong};
use svdpi::SvScope;
use tracing::{debug, trace};
use tracing::{debug, info, trace};

use crate::drive::Driver;
use crate::OnlineArgs;
Expand All @@ -28,25 +28,26 @@ unsafe fn write_to_pointer(dst: *mut u8, data: &[u8]) {
}

unsafe fn fill_axi_read_payload(dst: *mut SvBitVecVal, dlen: u32, payload: &AxiReadPayload) {
let data_len = 256 * (dlen / 8) as usize;
assert!(payload.data.len() <= data_len);
assert!(payload.data.len() * 8 <= dlen as usize);
write_to_pointer(dst as *mut u8, &payload.data);
}

// Return (strobe in bit, data in byte)
// data_width: AXI width (count in bits)
// size: AXI transaction bytes ( data_width * (1 + MAX_AWLEN) / 8 )
unsafe fn load_from_payload(
payload: &*const SvBitVecVal,
data_width: usize,
size: usize,
data_width: u32,
size: u32,
) -> (Vec<bool>, &[u8]) {
let src = *payload as *mut u8;
let data_width_in_byte = std::cmp::max(size, 4);
let strb_width_per_byte = if data_width < 64 { 4 } else { 8 };
let strb_width_in_byte = size.div_ceil(strb_width_per_byte);
let data_width_in_byte = std::cmp::max(size, 4) as usize;
let strb_width_per_byte = (data_width / 8).min(8) as usize;
let strb_width_in_byte = (size as usize).div_ceil(strb_width_per_byte);

let payload_size_in_byte = strb_width_in_byte + data_width_in_byte; // data width in byte
let byte_vec = std::slice::from_raw_parts(src, payload_size_in_byte);
let strobe = &byte_vec[0..strb_width_in_byte];
let strobe = &byte_vec[..strb_width_in_byte];
let data = &byte_vec[strb_width_in_byte..];

let masks: Vec<bool> = strobe
Expand All @@ -56,18 +57,8 @@ unsafe fn load_from_payload(
mask
})
.collect();
assert_eq!(
masks.len(),
data.len(),
"strobe bit width is not aligned with data byte width"
);

debug!(
"load {payload_size_in_byte} byte from payload: raw_data={} strb={} data={}",
hex::encode(byte_vec),
hex::encode(strobe),
hex::encode(data),
);
assert_eq!(masks.len(), data.len());

(masks, data)
}
Expand All @@ -80,6 +71,7 @@ unsafe fn load_from_payload(
#[no_mangle]
unsafe extern "C" fn axi_write_highBandwidthAXI(
channel_id: c_longlong,
data_width: i64,
awid: c_longlong,
awaddr: c_longlong,
awlen: c_longlong,
Expand All @@ -99,16 +91,23 @@ unsafe extern "C" fn axi_write_highBandwidthAXI(
awlen={awlen}, awsize={awsize}, awburst={awburst}, awlock={awlock}, awcache={awcache}, \
awprot={awprot}, awqos={awqos}, awregion={awregion})"
);

TARGET.with(|driver| {
let (strobe, data) = load_from_payload(&payload, driver.dlen as usize, (1 << awsize) as usize);
driver.axi_write_high_bandwidth(awaddr as u32, awsize as u64, &strobe, data);
assert_eq!(data_width as u32, driver.dlen);
assert_eq!(awlen, 0);

let (strobe, data) = load_from_payload(&payload, driver.dlen, driver.dlen / 8);
driver.axi_write(awaddr as u32, awsize as u32, driver.dlen, &strobe, data);

driver.update_commit_cycle();
});
}

/// evaluate at AR fire at corresponding channel_id.
#[no_mangle]
unsafe extern "C" fn axi_read_highBandwidthAXI(
channel_id: c_longlong,
data_width: i64,
arid: c_longlong,
araddr: c_longlong,
arlen: c_longlong,
Expand All @@ -128,15 +127,22 @@ unsafe extern "C" fn axi_read_highBandwidthAXI(
arprot={arprot}, arqos={arqos}, arregion={arregion})"
);
TARGET.with(|driver| {
let response = driver.axi_read_high_bandwidth(araddr as u32, arsize as u64);
fill_axi_read_payload(payload, driver.dlen, &response);
let dlen = driver.dlen;
assert_eq!(data_width as u32, dlen);
assert_eq!(arlen, 0);

let response = driver.axi_read(araddr as u32, arsize as u32, dlen);
fill_axi_read_payload(payload, dlen, &response);

driver.update_commit_cycle();
});
}

/// evaluate after AW and W is finished at corresponding channel_id.
#[no_mangle]
unsafe extern "C" fn axi_write_highOutstandingAXI(
channel_id: c_longlong,
data_width: i64,
awid: c_longlong,
awaddr: c_longlong,
awlen: c_longlong,
Expand All @@ -156,15 +162,21 @@ unsafe extern "C" fn axi_write_highOutstandingAXI(
awprot={awprot}, awqos={awqos}, awregion={awregion})"
);
TARGET.with(|driver| {
let (strobe, data) = load_from_payload(&payload, 32, (1 << awsize) as usize);
driver.axi_write_high_outstanding(awaddr as u32, awsize as u64, &strobe, data);
assert_eq!(data_width, 32);
assert_eq!(awlen, 0);

let (strobe, data) = load_from_payload(&payload, 32, 32 / 8);
driver.axi_write(awaddr as u32, awsize as u32, 32, &strobe, data);

driver.update_commit_cycle();
});
}

/// evaluate at AR fire at corresponding channel_id.
#[no_mangle]
unsafe extern "C" fn axi_read_highOutstandingAXI(
channel_id: c_longlong,
data_width: i64,
arid: c_longlong,
araddr: c_longlong,
arlen: c_longlong,
Expand All @@ -184,14 +196,20 @@ unsafe extern "C" fn axi_read_highOutstandingAXI(
arprot={arprot}, arqos={arqos}, arregion={arregion})"
);
TARGET.with(|driver| {
let response = driver.axi_read_high_outstanding(araddr as u32, arsize as u64);
fill_axi_read_payload(payload, driver.dlen, &response);
assert_eq!(data_width, 32);
assert_eq!(arlen, 0);

let response = driver.axi_read(araddr as u32, arsize as u32, 32);
fill_axi_read_payload(payload, 32, &response);

driver.update_commit_cycle();
});
}

#[no_mangle]
unsafe extern "C" fn axi_write_loadStoreAXI(
channel_id: c_longlong,
data_width: i64,
awid: c_longlong,
awaddr: c_longlong,
awlen: c_longlong,
Expand All @@ -210,15 +228,32 @@ unsafe extern "C" fn axi_write_loadStoreAXI(
awprot={awprot}, awqos={awqos}, awregion={awregion})"
);
TARGET.with(|driver| {
let data_width = if awsize <= 2 { 32 } else { 8 * (1 << awsize) } as usize;
let (strobe, data) = load_from_payload(&payload, data_width, (driver.dlen / 8) as usize);
driver.axi_write_load_store(awaddr as u32, awsize as u64, &strobe, data);
assert_eq!(data_width, 32);
assert_eq!(awlen, 0);

let (strobe, data) = load_from_payload(&payload, 32, 8 * 32 / 8);
let strobe = &strobe[..4];
let data = &data[..4];
driver.axi_write(awaddr as u32, awsize as u32, 32, strobe, data);

driver.update_commit_cycle();

// TODO: move it to MMIO device
if awaddr as u32 == crate::EXIT_POS {
let exit_data = u32::from_le_bytes(data.try_into().expect("slice with incorrect length"));
if exit_data == crate::EXIT_CODE {
info!("driver is ready to quit");
driver.success = true;
driver.quit = true;
}
}
});
}

#[no_mangle]
unsafe extern "C" fn axi_read_loadStoreAXI(
channel_id: c_longlong,
data_width: i64,
arid: c_longlong,
araddr: c_longlong,
arlen: c_longlong,
Expand All @@ -245,14 +280,20 @@ unsafe extern "C" fn axi_read_loadStoreAXI(
arprot={arprot}, arqos={arqos}, arregion={arregion})"
);
TARGET.with(|driver| {
let response = driver.axi_read_load_store(araddr as u32, arsize as u64);
fill_axi_read_payload(payload, driver.dlen, &response);
assert_eq!(data_width, 32);
assert_eq!(arlen, 0);

let response = driver.axi_read(araddr as u32, arsize as u32, 32);
fill_axi_read_payload(payload, 8 * 32, &response);

driver.update_commit_cycle();
});
}

#[no_mangle]
unsafe extern "C" fn axi_read_instructionFetchAXI(
channel_id: c_longlong,
data_width: i64,
arid: c_longlong,
araddr: c_longlong,
arlen: c_longlong,
Expand All @@ -279,8 +320,13 @@ unsafe extern "C" fn axi_read_instructionFetchAXI(
arprot={arprot}, arqos={arqos}, arregion={arregion})"
);
TARGET.with(|driver| {
let response = driver.axi_read_instruction_fetch(araddr as u32, arsize as u64);
fill_axi_read_payload(payload, driver.dlen, &response);
assert_eq!(data_width, 256);
assert_eq!(arlen, 0);

assert_eq!(8 * (1 << arsize), data_width);

let response = driver.axi_read(araddr as u32, arsize as u32, 256);
fill_axi_read_payload(payload, 256, &response);
});
}

Expand Down
104 changes: 9 additions & 95 deletions difftest/dpi_t1rocketemu/src/drive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,116 +130,30 @@ impl Driver {
Ok((elf.ehdr.e_entry, mem, fn_sym_tab))
}

pub(crate) fn axi_read_high_bandwidth(&mut self, addr: u32, arsize: u64) -> AxiReadPayload {
let size = 1 << arsize;
let data = self.shadow_bus.read_mem_axi(addr, size, self.dlen / 8);
let data_hex = hex::encode(&data);
self.last_commit_cycle = get_t();
trace!(
"[{}] axi_read_high_bandwidth (addr={addr:#x}, size={size}, data={data_hex})",
get_t()
);
AxiReadPayload { data }
}

pub(crate) fn axi_write_high_bandwidth(
&mut self,
addr: u32,
awsize: u64,
strobe: &[bool],
data: &[u8],
) {
let size = 1 << awsize;
self.shadow_bus.write_mem_axi(addr, size, self.dlen / 8, &strobe, data);
let data_hex = hex::encode(data);
self.last_commit_cycle = get_t();
trace!(
"[{}] axi_write_high_bandwidth (addr={addr:#x}, size={size}, data={data_hex})",
get_t()
);
}

pub(crate) fn axi_read_high_outstanding(&mut self, addr: u32, arsize: u64) -> AxiReadPayload {
let size = 1 << arsize;
assert!(size <= 4);
let data = self.shadow_bus.read_mem_axi(addr, size, 4);
let data_hex = hex::encode(&data);
self.last_commit_cycle = get_t();
trace!(
"[{}] axi_read_high_outstanding (addr={addr:#x}, size={size}, data={data_hex})",
get_t()
);
AxiReadPayload { data }
}

pub(crate) fn axi_write_high_outstanding(
&mut self,
addr: u32,
awsize: u64,
strobe: &[bool],
data: &[u8],
) {
let size = 1 << awsize;
self.shadow_bus.write_mem_axi(addr, size, 4, strobe, data);
let data_hex = hex::encode(data);
pub fn update_commit_cycle(&mut self) {
self.last_commit_cycle = get_t();
trace!(
"[{}] axi_write_high_outstanding (addr={addr:#x}, size={size}, data={data_hex})",
get_t()
);
}

pub(crate) fn axi_read_load_store(&mut self, addr: u32, arsize: u64) -> AxiReadPayload {
// data_width: AXI width (count in bits)
pub(crate) fn axi_read(&mut self, addr: u32, arsize: u32, data_width: u32) -> AxiReadPayload {
let bus_size = data_width / 8;
let size = 1 << arsize;
let bus_size = if size == 32 { 32 } else { 4 };
let data = self.shadow_bus.read_mem_axi(addr, size, bus_size);
let data_hex = hex::encode(&data);
self.last_commit_cycle = get_t();
trace!(
"[{}] axi_read_load_store (addr={addr:#x}, size={size}, data={data_hex})",
get_t()
);
AxiReadPayload { data }
}

pub(crate) fn axi_write_load_store(
// data_width: AXI width (count in bits)
pub(crate) fn axi_write(
&mut self,
addr: u32,
awsize: u64,
awsize: u32,
data_width: u32,
strobe: &[bool],
data: &[u8],
) {
let bus_size = data_width / 8;
let size = 1 << awsize;
let bus_size = if size == 32 { 32 } else { 4 };
self.shadow_bus.write_mem_axi(addr, size, bus_size, strobe, data);
let data_hex = hex::encode(data);
self.last_commit_cycle = get_t();

trace!(
"[{}] axi_write_load_store (addr={addr:#x}, size={size}, data={data_hex})",
get_t()
);

// check exit with code
if addr == EXIT_POS {
let exit_data_slice = data[..4].try_into().expect("slice with incorrect length");
if u32::from_le_bytes(exit_data_slice) == EXIT_CODE {
info!("driver is ready to quit");
self.success = true;
self.quit = true;
}
}
}

pub(crate) fn axi_read_instruction_fetch(&mut self, addr: u32, arsize: u64) -> AxiReadPayload {
let size = 1 << arsize;
let data = self.shadow_bus.read_mem_axi(addr, size, 32);
let data_hex = hex::encode(&data);
trace!(
"[{}] axi_read_instruction_fetch (addr={addr:#x}, size={size}, data={data_hex})",
get_t()
);
AxiReadPayload { data }
}

pub(crate) fn watchdog(&mut self) -> u8 {
Expand Down
4 changes: 2 additions & 2 deletions difftest/dpi_t1rocketemu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ impl OnlineArgs {
}

// quit signal
const EXIT_POS: u32 = 0x4000_0000;
const EXIT_CODE: u32 = 0xdead_beef;
pub const EXIT_POS: u32 = 0x4000_0000;
pub const EXIT_CODE: u32 = 0xdead_beef;

// keep in sync with TestBench.ClockGen
// the value is measured in simulation time unit
Expand Down
2 changes: 1 addition & 1 deletion t1/src/lsu/LSU.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ case class LSUParameter(
val maskGroupWidth: Int = maxOffsetPerLaneAccess

/** see [[VParameter.maskGroupSize]]. */
val maskGroupSize: Int = vLen / datapathWidth
val maskGroupSize: Int = vLen / maskGroupWidth

/** hardware width of [[maskGroupSize]] */
val maskGroupSizeBits: Int = log2Ceil(maskGroupSize)
Expand Down
Loading
Loading