sv_api/callbacks.rs
1/*
2 * File: callbacks.rs
3 * Brief: TODO
4 *
5 * Copyright (C) 2023 John Jekel
6 * See the LICENSE file at the root of the project for licensing info.
7 *
8 * TODO longer description
9 *
10*/
11
12/*!
13 * TODO rustdoc for this file here
14*/
15
16/* ------------------------------------------------------------------------------------------------
17 * Submodules
18 * --------------------------------------------------------------------------------------------- */
19
20//TODO (includes "mod ..." and "pub mod ...")
21
22/* ------------------------------------------------------------------------------------------------
23 * Uses
24 * --------------------------------------------------------------------------------------------- */
25
26//TODO (includes "use ..." and "extern crate ...")
27
28/* ------------------------------------------------------------------------------------------------
29 * Macros
30 * --------------------------------------------------------------------------------------------- */
31
32//TODO (also pub(crate) use the_macro statements here too)
33
34/* ------------------------------------------------------------------------------------------------
35 * Constants
36 * --------------------------------------------------------------------------------------------- */
37
38//TODO
39
40/* ------------------------------------------------------------------------------------------------
41 * Static Variables
42 * --------------------------------------------------------------------------------------------- */
43
44//TODO
45//TESTING
46static mut START_OF_SIM_CALLBACK_DATA: sv_bindings::t_cb_data = sv_bindings::t_cb_data {
47 reason: sv_bindings::cbAtStartOfSimTime as i32,
48 cb_rtn: None,//Some(start_of_sim_callback),
49 obj: std::ptr::null_mut(),
50 time: std::ptr::null_mut(),
51 //time: unsafe { &mut VPI_TIME },//Doesn't work :(
52 value: std::ptr::null_mut(),
53 index: 0,
54 user_data: std::ptr::null_mut()
55};
56
57/* ------------------------------------------------------------------------------------------------
58 * Types
59 * --------------------------------------------------------------------------------------------- */
60
61pub struct CallbackBuilder {
62 func: Option<Box<dyn FnMut()>>
63}
64
65#[derive(Clone, Copy, Debug)]
66pub enum Time {
67 ScaledRealTime(f64),
68 SimTime{high: u32, low: u32},
69 SuppressTime
70}
71
72#[derive(Clone, Copy, Debug)]
73#[repr(i32)]
74pub enum TimeType {
75 ScaledRealTime = sv_bindings::vpiScaledRealTime,
76 SimTime = sv_bindings::vpiSimTime,
77 SuppressTime = sv_bindings::vpiSuppressTime,
78}
79
80#[derive(Clone, Copy, Debug)]
81#[repr(i32)]
82pub enum CallbackReason {
83 Todo
84 //TODO
85}
86
87struct CallbackDataWrapper {//Self referential
88 raw_cb_data: sv_bindings::t_cb_data,
89 func: Option<Box<dyn FnMut()>>
90}
91
92/* ------------------------------------------------------------------------------------------------
93 * Associated Functions and Methods
94 * --------------------------------------------------------------------------------------------- */
95
96impl CallbackDataWrapper {
97 fn make_self_referential(&mut self) {//Only call this when the wrapper has been pinned in memory
98 let self_ptr: *mut CallbackDataWrapper = self;
99 self.raw_cb_data.user_data = self_ptr.cast();
100 }
101}
102
103impl CallbackBuilder {
104 pub fn new() -> CallbackBuilder {
105 CallbackBuilder {
106 func: None
107 }
108 }
109
110 pub fn call(mut self, func: impl FnMut() + 'static) -> CallbackBuilder {
111 self.func = Some(Box::new(func));
112 self
113 }
114
115 extern "C" fn closure_wrapper(cb_data: *mut sv_bindings::t_cb_data) -> i32 {
116 //TODO justify safety
117 unsafe {
118 //https://users.rust-lang.org/t/why-cant-a-convert-a-mut-c-void-into-mut-dyn-std-read/95780/7
119 //TODO try to make this more efficient in the future
120 let thin_ptr: *mut *mut dyn FnMut() = (*cb_data).user_data.cast();
121 let fat_ptr: *mut dyn FnMut() = *thin_ptr;
122 (*fat_ptr)();//TODO pass the closure extra info about what happened
123 //No need to re-box things since the closure may be re-called multiple times and we
124 //don't want to drop it
125 //FIXME how should we clean this up at the end?
126 //FIXME what if this is called from multiple threads?
127 };
128
129 0
130 }
131
132 pub fn register(mut self) {
133 //TESTING
134 unsafe {
135 START_OF_SIM_CALLBACK_DATA.cb_rtn = Some(CallbackBuilder::closure_wrapper);//Some(self.func.unwrap());
136 let time = Time::SimTime{high: 1, low: 2};
137 let ctime: sv_bindings::t_vpi_time = time.into();
138 let ctimebox = Box::new(ctime);
139 START_OF_SIM_CALLBACK_DATA.time = Box::into_raw(ctimebox);
140
141 assert!(self.func.is_some());
142 let boxed_closure = self.func.take().unwrap();
143 //https://users.rust-lang.org/t/why-cant-a-convert-a-mut-c-void-into-mut-dyn-std-read/95780/7
144 //TODO try to make this more efficient in the future
145 let fat_ptr: *mut dyn FnMut() = Box::into_raw(boxed_closure);
146 let boxed_fat_ptr = Box::new(fat_ptr);
147 let thin_ptr: *mut *mut dyn FnMut() = Box::into_raw(boxed_fat_ptr);
148 START_OF_SIM_CALLBACK_DATA.user_data = thin_ptr.cast();
149
150 //TODO in the wrapper around the registration callback panic if SupressTime or Time is NULL
151 sv_bindings::vpi_register_cb(
152 &mut START_OF_SIM_CALLBACK_DATA
153 );
154
155 }
156 }
157}
158
159/* ------------------------------------------------------------------------------------------------
160 * Traits And Default Implementations
161 * --------------------------------------------------------------------------------------------- */
162
163//TODO
164
165/* ------------------------------------------------------------------------------------------------
166 * Trait Implementations
167 * --------------------------------------------------------------------------------------------- */
168
169impl From<Time> for sv_bindings::t_vpi_time {
170 fn from(time: Time) -> sv_bindings::t_vpi_time {
171 match time {
172 Time::ScaledRealTime(real) => sv_bindings::t_vpi_time {
173 type_: TimeType::ScaledRealTime as i32,
174 low: 0,
175 high: 0,
176 real: real
177 },
178 Time::SimTime{high, low} => sv_bindings::t_vpi_time {
179 type_: TimeType::SimTime as i32,
180 low: low,
181 high: high,
182 real: 0.0
183 },
184 Time::SuppressTime => sv_bindings::t_vpi_time {
185 type_: TimeType::SuppressTime as i32,
186 low: 0,
187 high: 0,
188 real: 0.0
189 }
190 }
191 }
192}
193
194/* ------------------------------------------------------------------------------------------------
195 * Functions
196 * --------------------------------------------------------------------------------------------- */
197
198//TODO
199
200/* ------------------------------------------------------------------------------------------------
201 * Tests
202 * --------------------------------------------------------------------------------------------- */
203
204//TODO
205
206/* ------------------------------------------------------------------------------------------------
207 * Benchmarks
208 * --------------------------------------------------------------------------------------------- */
209
210//TODO