Skip to content

Commit

Permalink
[difftest] move DPI call logic to DpiTarget
Browse files Browse the repository at this point in the history
  • Loading branch information
FanShupei committed Aug 28, 2024
1 parent e66f8a8 commit aec68df
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 38 deletions.
42 changes: 42 additions & 0 deletions difftest/dpi_common/src/dpi_target.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use std::sync::Mutex;

pub struct DpiTarget<T> {
target: Mutex<Option<T>>,
}

impl<T> DpiTarget<T> {
pub const fn new() -> Self {
Self { target: Mutex::new(None) }
}

#[track_caller]
pub fn init(&self, init_fn: impl FnOnce() -> T) {
let mut target = self.target.lock().unwrap();
if target.is_some() {
panic!("DpiTarget is already initialized");
}
*target = Some(init_fn());
}

#[track_caller]
pub fn with<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
let mut target = self.target.lock().unwrap();
let target = target.as_mut().expect("DpiTarget is not initialized");
f(target)
}

#[track_caller]
pub fn with_optional<R>(&self, f: impl FnOnce(Option<&mut T>) -> R) -> R {
let mut target = self.target.lock().unwrap();
f(target.as_mut())
}

#[track_caller]
pub fn dispose(&self) {
let mut target = self.target.lock().unwrap();
if target.is_none() {
panic!("DpiTarget is not initialized");
}
*target = None;
}
}
3 changes: 3 additions & 0 deletions difftest/dpi_common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
pub mod dpi_target;
pub mod dump;
pub mod plusarg;

pub use dpi_target::DpiTarget;

use tracing_subscriber::{EnvFilter, FmtSubscriber};

pub fn setup_logger() {
Expand Down
71 changes: 33 additions & 38 deletions difftest/dpi_t1/src/dpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

use dpi_common::dump::DumpControl;
use dpi_common::plusarg::PlusArgMatcher;
use dpi_common::DpiTarget;
use std::ffi::{c_char, c_longlong};
use std::sync::Mutex;
use tracing::{debug, error};

use crate::drive::Driver;
Expand All @@ -17,7 +17,7 @@ pub type SvBitVecVal = u32;
// preparing data structures
// --------------------------

static DPI_TARGET: Mutex<Option<Box<Driver>>> = Mutex::new(None);
static TARGET: DpiTarget<Driver> = DpiTarget::new();

pub(crate) struct AxiReadPayload {
pub(crate) data: Vec<u8>,
Expand Down Expand Up @@ -126,10 +126,10 @@ unsafe extern "C" fn axi_write_highBandwidthPort(
awlen={awlen}, awsize={awsize}, awburst={awburst}, awlock={awlock}, awcache={awcache}, \
awprot={awprot}, awqos={awqos}, awregion={awregion})"
);
let mut driver = DPI_TARGET.lock().unwrap();
let driver = driver.as_mut().unwrap();
let (strobe, data) = load_from_payload(payload, driver.dlen);
driver.axi_write_high_bandwidth(awaddr as u32, awsize as u64, &strobe, data);
TARGET.with(|driver| {
let (strobe, data) = load_from_payload(payload, driver.dlen);
driver.axi_write_high_bandwidth(awaddr as u32, awsize as u64, &strobe, data);
});
}

/// evaluate at AR fire at corresponding channel_id.
Expand All @@ -154,10 +154,10 @@ unsafe extern "C" fn axi_read_highBandwidthPort(
arlen={arlen}, arsize={arsize}, arburst={arburst}, arlock={arlock}, arcache={arcache}, \
arprot={arprot}, arqos={arqos}, arregion={arregion})"
);
let mut driver = DPI_TARGET.lock().unwrap();
let driver = driver.as_mut().unwrap();
let response = driver.axi_read_high_bandwidth(araddr as u32, arsize as u64);
fill_axi_read_payload(payload, driver.dlen, &response);
TARGET.with(|driver| {
let response = driver.axi_read_high_bandwidth(araddr as u32, arsize as u64);
fill_axi_read_payload(payload, driver.dlen, &response);
});
}

/// evaluate at AR fire at corresponding channel_id.
Expand All @@ -182,10 +182,10 @@ unsafe extern "C" fn axi_read_indexedAccessPort(
arlen={arlen}, arsize={arsize}, arburst={arburst}, arlock={arlock}, arcache={arcache}, \
arprot={arprot}, arqos={arqos}, arregion={arregion})"
);
let mut driver = DPI_TARGET.lock().unwrap();
let driver = driver.as_mut().unwrap();
let response = driver.axi_read_indexed(araddr as u32, arsize as u64);
fill_axi_read_payload(payload, driver.dlen, &response);
TARGET.with(|driver| {
let response = driver.axi_read_indexed(araddr as u32, arsize as u64);
fill_axi_read_payload(payload, driver.dlen, &response);
});
}

/// evaluate after AW and W is finished at corresponding channel_id.
Expand All @@ -210,10 +210,10 @@ unsafe extern "C" fn axi_write_indexedAccessPort(
awlen={awlen}, awsize={awsize}, awburst={awburst}, awlock={awlock}, awcache={awcache}, \
awprot={awprot}, awqos={awqos}, awregion={awregion})"
);
let mut driver = DPI_TARGET.lock().unwrap();
let driver = driver.as_mut().unwrap();
let (strobe, data) = load_from_payload(payload, 32);
driver.axi_write_indexed_access_port(awaddr as u32, awsize as u64, &strobe, data);
TARGET.with(|driver| {
driver.axi_write_indexed_access_port(awaddr as u32, awsize as u64, &strobe, data);
});
}

#[no_mangle]
Expand All @@ -226,49 +226,44 @@ unsafe extern "C" fn t1_cosim_init() {
let scope = SvScope::get_current().expect("failed to get scope in t1_cosim_init");
let dump_control = DumpControl::from_plusargs(scope, &plusargs);

let driver = Box::new(Driver::new(scope, dump_control, &args));
let mut dpi_target = DPI_TARGET.lock().unwrap();
assert!(
dpi_target.is_none(),
"t1_cosim_init should be called only once"
);
*dpi_target = Some(driver);
TARGET.init(|| Driver::new(scope, dump_control, &args));
}

/// evaluate at every 1024 cycles, return reason = 0 to continue simulation,
/// other value is used as error code.
#[no_mangle]
unsafe extern "C" fn cosim_watchdog(reason: *mut c_char) {
// watchdog dpi call would be called before initialization, guard on null target
let mut driver = DPI_TARGET.lock().unwrap();
if let Some(driver) = driver.as_mut() {
*reason = driver.watchdog() as c_char
}
TARGET.with_optional(|driver| {
if let Some(driver) = driver {
*reason = driver.watchdog() as c_char
}
});
}

/// evaluate at instruction queue is not empty
/// arg issue will be type cast from a struct to svBitVecVal*(uint32_t*)
#[no_mangle]
unsafe extern "C" fn issue_vector_instruction(issue_dst: *mut SvBitVecVal) {
let mut driver = DPI_TARGET.lock().unwrap();
let driver = driver.as_mut().unwrap();
let issue = driver.issue_instruction();
*(issue_dst as *mut IssueData) = issue;
TARGET.with(|driver| {
let issue = driver.issue_instruction();
*(issue_dst as *mut IssueData) = issue;
});
}

#[no_mangle]
unsafe extern "C" fn retire_vector_instruction(retire_src: *const SvBitVecVal) {
let mut driver = DPI_TARGET.lock().unwrap();
let driver = driver.as_mut().unwrap();
let retire = &*(retire_src as *const Retire);
driver.retire_instruction(retire)
TARGET.with(|driver| {
driver.retire_instruction(retire);
});
}

#[no_mangle]
unsafe extern "C" fn retire_vector_mem(dummy: *const SvBitVecVal) {
let mut driver = DPI_TARGET.lock().unwrap();
let driver = driver.as_mut().unwrap();
driver.retire_memory();
TARGET.with(|driver| {
driver.retire_memory();
});
}

//--------------------------------
Expand Down

0 comments on commit aec68df

Please sign in to comment.