-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[difftest] add ShadowBus devices emulation
- Loading branch information
1 parent
725d01b
commit bfa241a
Showing
3 changed files
with
193 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ use std::path::PathBuf; | |
|
||
use dpi_common::plusarg::PlusArgMatcher; | ||
|
||
mod bus; | ||
pub mod dpi; | ||
pub mod drive; | ||
|
||
|