Skip to content

Commit

Permalink
[difftest] add ShadowBus devices emulation
Browse files Browse the repository at this point in the history
  • Loading branch information
OceanS2000 committed Oct 14, 2024
1 parent 725d01b commit bfa241a
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 0 deletions.
148 changes: 148 additions & 0 deletions difftest/dpi_t1rocket/src/bus.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
mod mem;

use mem::*;
use tracing::{debug, error, trace};

trait ShadowDevice: Send + Sync {
fn new() -> Box<dyn ShadowDevice>
where
Self: Sized;
fn read_mem(&self, addr: usize, size: usize) -> &[u8];
fn write_mem(&mut self, addr: usize, data: u8);
fn write_mem_chunk(&mut self, addr: usize, size: usize, strobe: Option<&[bool]>, data: &[u8]);
}

struct ShadowBusDevice {
base: usize,
size: usize,
device: Box<dyn ShadowDevice>,
}

const MAX_DEVICES: usize = 3;

pub(crate) struct ShadowBus {
devices: [ShadowBusDevice; MAX_DEVICES],
}

impl ShadowBus {
/// Initiate the devices on the bus as specified in `tests/t1.ld`
/// NOTE: For some reason DDR is not aligned in the address space
pub fn new() -> Self {
const DDR_SIZE: usize = 0x80000000;
const SCALAR_SIZE: usize = 0x20000000;
const SRAM_SIZE: usize = 0x00400000;

Self {
devices: [
ShadowBusDevice {
base: 0x20000000,
size: SCALAR_SIZE,
device: MemDevice::<SCALAR_SIZE>::new(),
},
ShadowBusDevice {
base: 0x40000000,
size: DDR_SIZE,
device: MemDevice::<DDR_SIZE>::new(),
},
ShadowBusDevice {
base: 0xc0000000,
size: SRAM_SIZE,
device: MemDevice::<SRAM_SIZE>::new(),
},
],
}
}

pub fn read_mem_axi(&self, addr: u32, size: u32, bus_size: u32) -> Vec<u8> {
assert!(
addr % size == 0 && bus_size % size == 0,
"unaligned access addr={addr:#x} size={size}B dlen={bus_size}B"
);

let start = addr as usize;
let end = (addr + size) as usize;

let handler = self.devices.iter().find(|d| match d {
ShadowBusDevice { base, size, device: _ } => *base <= start && end <= (*base + *size),
});

match handler {
Some(ShadowBusDevice { base, size: _, device }) => {
let offset = start - *base;
let data = device.read_mem(offset, size as usize);

if size < bus_size {
let mut data_padded = vec![0; bus_size as usize];
let start = (addr % bus_size) as usize;
let end = start + data.len();
data_padded[start..end].copy_from_slice(data);

data_padded
} else {
data.to_vec()
}
}
None => {
error!("read addr={addr:#x} size={size}B dlen={bus_size}B leads to nowhere!");
vec![0; bus_size as usize]
}
}
}

pub fn write_mem_axi(
&mut self,
addr: u32,
size: u32,
bus_size: u32,
masks: &[bool],
data: &[u8],
) {
assert!(
addr % size == 0 && bus_size % size == 0,
"unaligned write access addr={addr:#x} size={size}B dlen={bus_size}B"
);

if !masks.iter().any(|x| *x) {
trace!("Mask 0 write detected");
return;
}

let start = (addr & ((!bus_size) + 1)) as usize;
let end = start + bus_size as usize;

let handler = self.devices.iter_mut().find(|d| match d {
ShadowBusDevice { base, size, device: _ } => *base <= start && end <= (*base + *size),
});

match handler {
Some(ShadowBusDevice { base, size: _, device }) => {
let offset = start - *base;
device.write_mem_chunk(offset, size as usize, Option::from(masks), data);
}
None => {
error!("write addr={addr:#x} size={size}B dlen={bus_size}B leads to nowhere!");
}
}
}

pub fn load_mem_seg(&mut self, vaddr: usize, data: &[u8]) {
let handler = self
.devices
.iter_mut()
.find(|d| match d {
ShadowBusDevice { base, size, device: _ } => {
*base <= vaddr as usize && (vaddr as usize + data.len()) <= (*base + *size)
}
})
.unwrap_or_else(|| {
panic!(
"fail reading ELF into mem with vaddr={:#x}, len={}B: load memory to nowhere",
vaddr,
data.len()
)
});

let offset = vaddr - handler.base;
handler.device.write_mem_chunk(offset, data.len(), None, data)
}
}
44 changes: 44 additions & 0 deletions difftest/dpi_t1rocket/src/bus/mem.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use super::ShadowDevice;

pub(super) struct MemDevice<const SIZE: usize> {
mem: [u8; SIZE],
}

impl<const SIZE: usize> ShadowDevice for MemDevice<SIZE> {
fn new() -> Box<dyn ShadowDevice>
where
Self: Sized,
{
Box::new(Self { mem: [0; SIZE] })
}

fn read_mem(&self, addr: usize, size: usize) -> &[u8] {
let start = addr;
let end = addr + size;
&self.mem[start..end]
}

fn write_mem(&mut self, addr: usize, data: u8) {
self.mem[addr] = data;
}

fn write_mem_chunk(&mut self, addr: usize, size: usize, strobe: Option<&[bool]>, data: &[u8]) {
assert_eq!(
addr % size,
0,
"unaligned chunk write addr={addr:#x} size={size}B"
);

if let Some(masks) = strobe {
masks.iter().enumerate().for_each(|(i, mask)| {
if *mask {
self.mem[addr + i] = data[i];
}
})
} else {
let start = addr;
let end = addr + size;
self.mem[start..end].copy_from_slice(data);
}
}
}
1 change: 1 addition & 0 deletions difftest/dpi_t1rocket/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::path::PathBuf;

use dpi_common::plusarg::PlusArgMatcher;

mod bus;
pub mod dpi;
pub mod drive;

Expand Down

0 comments on commit bfa241a

Please sign in to comment.