Skip to content

Commit

Permalink
[difftest] t1rocketemu: reimplement EXIT_POS by mmio device
Browse files Browse the repository at this point in the history
  • Loading branch information
FanShupei committed Nov 26, 2024
1 parent 3d7a153 commit dc4c637
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 26 deletions.
15 changes: 3 additions & 12 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_longlong;
use svdpi::SvScope;
use tracing::{debug, info};
use tracing::debug;

use crate::drive::Driver;
use crate::OnlineArgs;
Expand Down Expand Up @@ -233,16 +233,6 @@ unsafe extern "C" fn axi_write_loadStoreAXI(
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;
}
}
});
}

Expand Down Expand Up @@ -341,7 +331,8 @@ unsafe extern "C" fn t1_cosim_init() {
#[no_mangle]
unsafe extern "C" fn t1_cosim_final() {
TARGET.with(|driver| {
dpi_common::util::write_perf_json(crate::get_t(), driver.success);
let success = driver.exit_flag.is_finish();
dpi_common::util::write_perf_json(crate::get_t(), success);
});
}

Expand Down
11 changes: 5 additions & 6 deletions difftest/dpi_t1rocketemu/src/drive.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::get_t;
use crate::interconnect::simctrl::ExitFlagRef;
use crate::interconnect::{create_emu_addrspace, AddressSpace};
use crate::OnlineArgs;
use svdpi::SvScope;
Expand Down Expand Up @@ -37,13 +38,12 @@ pub(crate) struct Driver {

addr_space: AddressSpace,

pub(crate) quit: bool,
pub(crate) success: bool,
pub(crate) exit_flag: ExitFlagRef,
}

impl Driver {
pub(crate) fn new(scope: SvScope, args: &OnlineArgs) -> Self {
let mut addr_space = create_emu_addrspace();
let (mut addr_space, exit_flag) = create_emu_addrspace();
// pass e_entry to rocket
let (e_entry, _fn_sym_tab) =
Self::load_elf(&args.elf_file, &mut addr_space).expect("fail creating simulator");
Expand All @@ -59,8 +59,7 @@ impl Driver {

addr_space,

quit: false,
success: false,
exit_flag,
}
}

Expand Down Expand Up @@ -198,7 +197,7 @@ impl Driver {

let tick = get_t();

if self.quit {
if self.exit_flag.is_finish() {
trace!("[{tick}] watchdog quit");
return WATCHDOG_QUIT;
}
Expand Down
61 changes: 57 additions & 4 deletions difftest/dpi_t1rocketemu/src/interconnect.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use std::any::Any;

use framebuffer::FrameBuffer;
use simctrl::{ExitFlagRef, SimCtrl};

pub mod framebuffer;
pub mod simctrl;

#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct AddrInfo {
Expand All @@ -23,8 +25,8 @@ impl AddrInfo {
// However, since the functions are safe,
// even if contracts violate, implementions must not break memory safety,
pub trait Device: Any + Send + Sync {
// It's OK to side have effect for mmio device
// Panic for bus error
/// It's OK to side have effect for mmio device
/// Panic for bus error
fn mem_read(&mut self, addr: AddrInfo, data: &mut [u8]);

// Behave as if `mem_write_masked` with full mask,
Expand All @@ -48,6 +50,50 @@ pub trait DeviceExt: Device + Sized {
}
}

// Represents a MMIO devices consists of 4-byte 'registers'.
// Support only 4-byte aligned read/write, not support write mask
// `offset` is offset in bytes from base address, guaranteed to be multiple of 4.
// I choose offset in byte since it's usaully better aligned with document
pub trait RegDevice {
// Panic for bus error
fn reg_read(&mut self, offset: u32) -> u32;

// Panic for bus error
fn reg_write(&mut self, offset: u32, value: u32);
}

impl<T: RegDevice + Send + Sync + 'static> Device for T {
fn mem_read(&mut self, addr: AddrInfo, data: &mut [u8]) {
// allows only 4-byte aligned access
assert_eq!(4, addr.len);
assert!(addr.offset % 4 == 0);

let data: &mut [u8; 4] = data.try_into().unwrap();
let value = self.reg_read(addr.offset);
*data = u32::to_le_bytes(value);
}

fn mem_write(&mut self, addr: AddrInfo, data: &[u8]) {
// allows only 4-byte aligned access
assert_eq!(4, addr.len);
assert!(addr.offset % 4 == 0);

let value = u32::from_le_bytes(data.try_into().unwrap());
self.reg_write(addr.offset, value);
}

fn mem_write_masked(&mut self, addr: AddrInfo, data: &[u8], mask: &[bool]) {
// allows only 4-byte aligned access
assert_eq!(4, addr.len);
assert!(addr.offset % 4 == 0);
assert!(mask.iter().all(|&x| x));

let data: &[u8; 4] = data.try_into().unwrap();
let value = u32::from_le_bytes(*data);
self.reg_write(addr.offset, value);
}
}

pub struct RegularMemory {
data: Vec<u8>,
}
Expand Down Expand Up @@ -148,21 +194,28 @@ impl AddressSpace {

/// Memory map:
/// - 0x0400_0000 - 0x0600_0000 : framebuffer
/// - 0x4000_0000 - 0x4000_1000 : simctrl
/// - 0x2000_0000 - 0xc000_0000 : ddr
/// - 0xc000_0000 - 0xc040_0000 : sram
pub fn create_emu_addrspace() -> AddressSpace {
/// TODO: simctrl is inside ddr, move it elsewhere
pub fn create_emu_addrspace() -> (AddressSpace, ExitFlagRef) {
const DDR_BASE: u32 = 0x2000_0000;
const DDR_SIZE: u32 = 0xa000_0000;
const SRAM_BASE: u32 = 0xc000_0000;
const SRAM_SIZE: u32 = 0x0040_0000;

const SIMCTRL_BASE: u32 = 0x4000_0000;
const SIMCTRL_SIZE: u32 = 0x0000_1000; // one page
const DISPLAY_BASE: u32 = 0x0400_0000;
const DISPLAY_SIZE: u32 = 0x0200_0000;

let exit_flag = ExitFlagRef::new();

let devices = vec![
SimCtrl::new(exit_flag.clone()).with_addr(SIMCTRL_BASE, SIMCTRL_SIZE),
RegularMemory::with_size(DDR_SIZE).with_addr(DDR_BASE, DDR_SIZE),
RegularMemory::with_size(SRAM_SIZE).with_addr(SRAM_BASE, SRAM_SIZE),
FrameBuffer::new().with_addr(DISPLAY_BASE, DISPLAY_SIZE),
];
AddressSpace { devices }
(AddressSpace { devices }, exit_flag)
}
60 changes: 60 additions & 0 deletions difftest/dpi_t1rocketemu/src/interconnect/simctrl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use std::sync::{
atomic::{AtomicU32, Ordering},
Arc,
};

use tracing::{info, warn};

use super::RegDevice;

#[derive(Default, Debug, Clone)]
pub struct ExitFlagRef(Arc<AtomicU32>);

impl ExitFlagRef {
pub fn new() -> Self {
Self::default()
}

pub fn is_finish(&self) -> bool {
self.0.load(Ordering::Acquire) != 0
}

pub fn mark_finish(&self) {
self.0.store(1, Ordering::Release);
}
}

pub const EXIT_CODE: u32 = 0xdead_beef;

/// Reg map:
/// - 0x0000 : WO, write EXIT_CODE to mark simulation finish
pub struct SimCtrl {
exit_flag: ExitFlagRef,
}

impl SimCtrl {
pub fn new(exit_flag: ExitFlagRef) -> Self {
SimCtrl { exit_flag }
}
}

impl RegDevice for SimCtrl {
fn reg_read(&mut self, offset: u32) -> u32 {
let _ = offset;
unimplemented!()
}

fn reg_write(&mut self, reg_offset: u32, value: u32) {
match reg_offset {
0 => {
if value == EXIT_CODE {
self.exit_flag.mark_finish();
info!("simctrl: write EXIT_POS with EXIT_CODE, ready to quit");
} else {
warn!("simctrl: write EXIT_POS with value 0x{value:08x}, ignored");
}
}
_ => panic!(),
}
}
}
4 changes: 0 additions & 4 deletions difftest/dpi_t1rocketemu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,6 @@ impl OnlineArgs {
}
}

// quit signal
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
pub const CYCLE_PERIOD: u64 = 20000;
Expand Down

0 comments on commit dc4c637

Please sign in to comment.