#![no_std]
#![allow(incomplete_features)]
#![feature(generic_const_exprs)]
#![warn(missing_docs)]
extern crate alloc;
#[doc(hidden)]
pub mod __hidden__;
use core::{ffi::CStr, ptr::NonNull};
pub use vpi_user;
mod bitvec;
mod clk;
mod handle;
mod impls;
mod vpi_iter;
pub use bitvec::BitVector;
pub use clk::Clk;
pub use vpi_export_macro::{bitvec, vpi_module, vpi_task, vpi_top};
pub use vpi_user::vpi_printf;
use vpi_user::{vpiSimTime, vpi_get_time};
mod __private {
pub trait Sealed {}
}
pub use handle::Handle;
pub use vpi_iter::VpiIter;
pub type RawHandle = NonNull<vpi_user::PLI_UINT32>;
pub trait VpiTaskResult: __private::Sealed {
fn into_vpi_result(self) -> Result<()>;
}
#[derive(Debug)]
#[non_exhaustive]
pub enum VpiError {
Utf8Error(core::str::Utf8Error),
NoModule(&'static CStr),
BitVectorLengthMissMatch {
expected: usize,
actual: usize,
},
PeriodTooSmall,
}
pub type Result<T> = core::result::Result<T, VpiError>;
pub trait FromVpiHandle: Sized {
unsafe fn from_vpi_handle(handle: RawHandle) -> Result<Self>;
}
pub trait StoreIntoVpiHandle: Sized {
unsafe fn store_into_vpi_handle(&self, handle: RawHandle) -> Result<()>;
}
unsafe extern "C" fn cb(data: *mut vpi_user::t_cb_data) -> i32 {
let data = unsafe { &mut *data };
let data = unsafe { &mut *(data.user_data as *mut CallbackData) };
let f = unsafe { &mut *data.callback };
f();
0
}
struct CallbackData {
raw_callback_pointer: *mut u8,
callback: *mut dyn FnMut(),
callback_layout: alloc::alloc::Layout,
}
pub struct VpiCallbackHandle(vpi_user::vpiHandle, *const CallbackData);
pub fn on_value_change<E: FromVpiHandle, F: FnMut() + Sized + 'static>(
value: Handle<E>,
f: F,
) -> VpiCallbackHandle {
use alloc::alloc::{alloc, handle_alloc_error, Layout};
let callback_layout = Layout::new::<F>();
let raw_callback_pointer = unsafe { alloc(callback_layout) };
let callback = raw_callback_pointer as *mut F;
if callback.is_null() {
handle_alloc_error(callback_layout);
}
unsafe {
callback.write(f);
}
let data_layout = Layout::new::<CallbackData>();
let data = unsafe { alloc(data_layout) } as *mut CallbackData;
unsafe {
data.write(CallbackData {
raw_callback_pointer,
callback,
callback_layout,
});
}
let mut cb_data = vpi_user::t_cb_data {
reason: vpi_user::cbValueChange as i32,
cb_rtn: Some(cb),
obj: value.handle.as_ptr(),
user_data: data as *mut vpi_user::PLI_BYTE8,
..Default::default()
};
VpiCallbackHandle(unsafe { vpi_user::vpi_register_cb(&mut cb_data) }, data)
}
fn on_delay_internal<F: FnMut() + Sized + 'static>(delay: u64, f: F) -> VpiCallbackHandle {
use alloc::alloc::{alloc, handle_alloc_error, Layout};
let callback_layout = Layout::new::<F>();
let raw_callback_pointer = unsafe { alloc(callback_layout) };
let callback = raw_callback_pointer as *mut F;
if callback.is_null() {
handle_alloc_error(callback_layout);
}
unsafe {
callback.write(f);
}
let data_layout = Layout::new::<CallbackData>();
let data = unsafe { alloc(data_layout) } as *mut CallbackData;
unsafe {
data.write(CallbackData {
raw_callback_pointer,
callback,
callback_layout,
});
}
let mut cb_data = vpi_user::t_cb_data {
reason: vpi_user::cbAfterDelay as i32,
cb_rtn: Some(cb),
time: &mut vpi_user::t_vpi_time {
type_: vpiSimTime as i32,
high: (delay >> 32) as u32,
low: (delay & ((!0u64) >> 32)) as u32,
..Default::default()
},
user_data: data as *mut vpi_user::PLI_BYTE8,
..Default::default()
};
VpiCallbackHandle(unsafe { vpi_user::vpi_register_cb(&mut cb_data) }, data)
}
pub fn on_delay<F: FnOnce() + Sized + 'static>(delay: u64, f: F) -> VpiCallbackHandle {
let mut f = Some(f);
on_delay_internal(delay, move || {
if let Some(f) = core::mem::take(&mut f) {
f();
}
})
}
pub fn get_time() -> u64 {
let mut t = vpi_user::t_vpi_time {
type_: vpiSimTime as i32,
..Default::default()
};
unsafe { vpi_get_time(core::ptr::null_mut(), &mut t) };
let mut result = t.high as u64;
result <<= 32;
result |= t.low as u64;
result
}
pub fn finish() {
unsafe {
vpi_user::vpi_control(vpi_user::vpiFinish as i32);
}
}
pub fn remove_cb(cb_handle: VpiCallbackHandle) {
let a = unsafe { &*cb_handle.1 };
let _ = a.callback_layout;
let _ = a.raw_callback_pointer;
unsafe { vpi_user::vpi_remove_cb(cb_handle.0) };
}
pub fn print(c: &core::ffi::CStr) {
unsafe {
vpi_user::vpi_printf(c.as_ptr() as *mut core::ffi::c_char);
}
}
pub fn println(c: &core::ffi::CStr) {
print(c);
print(c"\n");
}