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