diff --git a/difftest/dpi_common/src/dpi_target.rs b/difftest/dpi_common/src/dpi_target.rs new file mode 100644 index 000000000..ac8d11c6d --- /dev/null +++ b/difftest/dpi_common/src/dpi_target.rs @@ -0,0 +1,42 @@ +use std::sync::Mutex; + +pub struct DpiTarget { + target: Mutex>, +} + +impl DpiTarget { + 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(&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(&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; + } +} diff --git a/difftest/dpi_common/src/lib.rs b/difftest/dpi_common/src/lib.rs index 7c269ff8c..279350ec2 100644 --- a/difftest/dpi_common/src/lib.rs +++ b/difftest/dpi_common/src/lib.rs @@ -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() { diff --git a/difftest/dpi_t1/src/dpi.rs b/difftest/dpi_t1/src/dpi.rs index 2073859e4..6cf7319a5 100644 --- a/difftest/dpi_t1/src/dpi.rs +++ b/difftest/dpi_t1/src/dpi.rs @@ -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; @@ -17,7 +17,7 @@ pub type SvBitVecVal = u32; // preparing data structures // -------------------------- -static DPI_TARGET: Mutex>> = Mutex::new(None); +static TARGET: DpiTarget = DpiTarget::new(); pub(crate) struct AxiReadPayload { pub(crate) data: Vec, @@ -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. @@ -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. @@ -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. @@ -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] @@ -226,13 +226,7 @@ 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, @@ -240,35 +234,36 @@ unsafe extern "C" fn t1_cosim_init() { #[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(); + }); } //--------------------------------