1#![no_std]
2#![allow(incomplete_features)]
3#![feature(generic_const_exprs)]
4#![warn(missing_docs)]
5
6extern crate alloc;
11
12#[doc(hidden)]
13pub mod __hidden__;
14use core::{ffi::CStr, ptr::NonNull};
15
16pub use vpi_user;
17mod bitvec;
18mod clk;
19mod handle;
20mod impls;
21mod vpi_iter;
22pub use bitvec::BitVector;
23pub use clk::Clk;
24pub use vpi_export_macro::{bitvec, vpi_module, vpi_task, vpi_top};
25pub use vpi_user::vpi_printf;
26use vpi_user::{vpiSimTime, vpi_get_time};
27
28mod __private {
29 pub trait Sealed {}
30}
31
32pub use handle::Handle;
33pub use vpi_iter::VpiIter;
34
35pub type RawHandle = NonNull<vpi_user::PLI_UINT32>;
37
38pub trait VpiTaskResult: __private::Sealed {
40 fn into_vpi_result(self) -> Result<()>;
42}
43
44#[derive(Debug)]
46#[non_exhaustive]
47pub enum VpiError {
48 Utf8Error(core::str::Utf8Error),
50 NoModule(&'static CStr),
52 BitVectorLengthMissMatch {
54 expected: usize,
56 actual: usize,
58 },
59 PeriodTooSmall,
61}
62
63pub type Result<T> = core::result::Result<T, VpiError>;
65
66pub trait FromVpiHandle: Sized {
68 unsafe fn from_vpi_handle(handle: RawHandle) -> Result<Self>;
73}
74
75pub trait StoreIntoVpiHandle: Sized {
77 unsafe fn store_into_vpi_handle(&self, handle: RawHandle) -> Result<()>;
82}
83
84unsafe extern "C" fn cb(data: *mut vpi_user::t_cb_data) -> i32 {
85 let data = unsafe { &mut *data };
86 let data = unsafe { &mut *(data.user_data as *mut CallbackData) };
87 let f = unsafe { &mut *data.callback };
88 f();
89 0
90}
91
92struct CallbackData {
93 raw_callback_pointer: *mut u8,
94 callback: *mut dyn FnMut(),
95 callback_layout: alloc::alloc::Layout,
96}
97
98pub struct VpiCallbackHandle(vpi_user::vpiHandle, *const CallbackData);
100
101pub fn on_value_change<E: FromVpiHandle, F: FnMut() + Sized + 'static>(
103 value: Handle<E>,
104 f: F,
105) -> VpiCallbackHandle {
106 use alloc::alloc::{alloc, handle_alloc_error, Layout};
107 let callback_layout = Layout::new::<F>();
108 let raw_callback_pointer = unsafe { alloc(callback_layout) };
109 let callback = raw_callback_pointer as *mut F;
110 if callback.is_null() {
111 handle_alloc_error(callback_layout);
112 }
113 unsafe {
114 callback.write(f);
115 }
116 let data_layout = Layout::new::<CallbackData>();
117 let data = unsafe { alloc(data_layout) } as *mut CallbackData;
118 unsafe {
119 data.write(CallbackData {
120 raw_callback_pointer,
121 callback,
122 callback_layout,
123 });
124 }
125 let mut cb_data = vpi_user::t_cb_data {
126 reason: vpi_user::cbValueChange as i32,
127 cb_rtn: Some(cb),
128 obj: value.handle.as_ptr(),
129 user_data: data as *mut vpi_user::PLI_BYTE8,
130 ..Default::default()
131 };
132 VpiCallbackHandle(unsafe { vpi_user::vpi_register_cb(&mut cb_data) }, data)
133}
134
135fn on_delay_internal<F: FnMut() + Sized + 'static>(delay: u64, f: F) -> VpiCallbackHandle {
136 use alloc::alloc::{alloc, handle_alloc_error, Layout};
137 let callback_layout = Layout::new::<F>();
138 let raw_callback_pointer = unsafe { alloc(callback_layout) };
139 let callback = raw_callback_pointer as *mut F;
140 if callback.is_null() {
141 handle_alloc_error(callback_layout);
142 }
143 unsafe {
144 callback.write(f);
145 }
146 let data_layout = Layout::new::<CallbackData>();
147 let data = unsafe { alloc(data_layout) } as *mut CallbackData;
148 unsafe {
149 data.write(CallbackData {
150 raw_callback_pointer,
151 callback,
152 callback_layout,
153 });
154 }
155
156 let mut cb_data = vpi_user::t_cb_data {
157 reason: vpi_user::cbAfterDelay as i32,
158 cb_rtn: Some(cb),
159 time: &mut vpi_user::t_vpi_time {
160 type_: vpiSimTime as i32,
161 high: (delay >> 32) as u32,
162 low: (delay & ((!0u64) >> 32)) as u32,
163 ..Default::default()
164 },
165 user_data: data as *mut vpi_user::PLI_BYTE8,
166 ..Default::default()
167 };
168 VpiCallbackHandle(unsafe { vpi_user::vpi_register_cb(&mut cb_data) }, data)
169}
170
171pub fn on_delay<F: FnOnce() + Sized + 'static>(delay: u64, f: F) -> VpiCallbackHandle {
173 let mut f = Some(f);
174 on_delay_internal(delay, move || {
175 if let Some(f) = core::mem::take(&mut f) {
176 f();
177 }
178 })
179}
180
181pub fn get_time() -> u64 {
183 let mut t = vpi_user::t_vpi_time {
184 type_: vpiSimTime as i32,
185 ..Default::default()
186 };
187 unsafe { vpi_get_time(core::ptr::null_mut(), &mut t) };
188 let mut result = t.high as u64;
189 result <<= 32;
190 result |= t.low as u64;
191 result
192}
193
194pub fn finish() {
196 unsafe {
197 vpi_user::vpi_control(vpi_user::vpiFinish as i32);
198 }
199}
200
201pub fn remove_cb(cb_handle: VpiCallbackHandle) {
203 let a = unsafe { &*cb_handle.1 };
206 let _ = a.callback_layout;
207 let _ = a.raw_callback_pointer;
208 unsafe { vpi_user::vpi_remove_cb(cb_handle.0) };
209}
210
211pub fn print(c: &core::ffi::CStr) {
213 unsafe {
214 vpi_user::vpi_printf(c.as_ptr() as *mut core::ffi::c_char);
215 }
216}
217
218pub fn println(c: &core::ffi::CStr) {
220 print(c);
221 print(c"\n");
222}