Skip to main content

rustdv_sim/handle/
logic.rs

1//! Logic reads, scheduled writes, and edge triggers.
2
3use rustdv_gpi as gpi;
4
5use crate::{
6    LogicArray, ValueError,
7    handle::{BigUint, HandleBase, HandleEvent},
8    phase,
9    triggers::{Edge, EdgeKind},
10};
11
12/// A value-bearing signal. Explicit `get()`/`set()` (mapping row 20 โ€”
13/// cocotb 2.x itself moved off the `.value` property).
14#[derive(Copy, Clone, PartialEq, Eq)]
15pub struct LogicHandle {
16    pub(super) raw: gpi::LogicHandle,
17}
18
19impl From<gpi::LogicHandle> for LogicHandle {
20    fn from(raw: gpi::LogicHandle) -> Self {
21        LogicHandle { raw }
22    }
23}
24
25impl HandleBase for LogicHandle {
26    fn name(&self) -> String {
27        self.raw.name()
28    }
29
30    fn full_name(&self) -> String {
31        self.raw.full_name()
32    }
33}
34
35impl std::fmt::Debug for LogicHandle {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        write!(f, "LogicHandle(\"{}\")", self.full_name())
38    }
39}
40
41impl LogicHandle {
42    pub fn size(&self) -> u32 {
43        self.raw.size()
44    }
45
46    // ----------------- Read: current value (mapping row 19) -----------------
47
48    /// Current boolean value, or `Err` if VPI does not supply it.
49    pub fn get_bool(&self) -> Result<bool, ValueError> {
50        self.raw.get_bool()
51    }
52
53    /// Current unsigned 8-bit value, or `Err` if VPI does not supply it.
54    pub fn get_u8(&self) -> Result<u8, ValueError> {
55        self.raw.get_u8()
56    }
57    /// Current unsigned 16-bit value, or `Err` if VPI does not supply it.
58    pub fn get_u16(&self) -> Result<u16, ValueError> {
59        self.raw.get_u16()
60    }
61
62    /// Current unsigned 32-bit value, or `Err` if VPI does not supply it.
63    pub fn get_u32(&self) -> Result<u32, ValueError> {
64        self.raw.get_u32()
65    }
66
67    /// Current unsigned 64-bit value, or `Err` if VPI does not supply it.
68    pub fn get_u64(&self) -> Result<u64, ValueError> {
69        self.raw.get_u64()
70    }
71
72    /// Current unsigned 128-bit value, or `Err` if VPI does not supply it.
73    pub fn get_u128(&self) -> Result<u128, ValueError> {
74        self.raw.get_u128()
75    }
76
77    /// Current arbitrary-width unsigned value, or `Err` if VPI does not supply it.
78    pub fn get_bigint(&self) -> Result<BigUint, ValueError> {
79        self.raw.get_bigint()
80    }
81
82    /// Current four-state value, or `Err` if VPI does not supply it.
83    pub fn get_logic(&self) -> Result<LogicArray, ValueError> {
84        self.raw.get_logic()
85    }
86
87    /// Current four-state value formatted as an MSB-first binary string.
88    pub fn get_binstr(&self) -> Result<String, ValueError> {
89        Ok(self.raw.get_logic()?.to_binstr())
90    }
91
92    /// Convenience for 1-bit signals: true iff the value is 1b1.
93    pub fn is_high(&self) -> bool {
94        self.raw.get_bool() == Ok(true)
95    }
96
97    /// Convenience for 1-bit signals: true iff the value is 1b0.
98    pub fn is_low(&self) -> bool {
99        self.raw.get_bool() == Ok(false)
100    }
101
102    // ------ Write: scheduled (applied at next ReadWrite phase, row 22) ------
103
104    /// Set the boolean value to be applied at the next ReadWrite phase. The
105    /// write is buffered and the last write wins, preserving order of distinct
106    /// signals.
107    pub fn set_bool(&self, v: bool) {
108        phase::schedule(self.raw, phase::WriteVal::Bool(v));
109    }
110
111    /// Set the unsigned 8-bit value to be applied at the next ReadWrite phase.
112    /// The write is buffered and the last write wins, preserving order of
113    /// distinct signals.
114    pub fn set_u8(&self, v: u8) {
115        phase::schedule(self.raw, phase::WriteVal::U8(v));
116    }
117
118    /// Set the unsigned 16-bit value to be applied at the next ReadWrite phase.
119    /// The write is buffered and the last write wins, preserving order of
120    /// distinct signals.
121    pub fn set_u16(&self, v: u16) {
122        phase::schedule(self.raw, phase::WriteVal::U16(v));
123    }
124
125    /// Set the unsigned 32-bit value to be applied at the next ReadWrite phase.
126    /// The write is buffered and the last write wins, preserving order of
127    /// distinct signals.
128    pub fn set_u32(&self, v: u32) {
129        phase::schedule(self.raw, phase::WriteVal::U32(v));
130    }
131
132    /// Set the unsigned 64-bit value to be applied at the next ReadWrite phase.
133    /// The write is buffered and the last write wins, preserving order of
134    /// distinct signals.
135    pub fn set_u64(&self, v: u64) {
136        phase::schedule(self.raw, phase::WriteVal::U64(v));
137    }
138
139    /// Set the unsigned 128-bit value to be applied at the next ReadWrite
140    /// phase. The write is buffered and the last write wins, preserving order
141    /// of distinct signals.
142    pub fn set_u128(&self, v: u128) {
143        phase::schedule(self.raw, phase::WriteVal::U128(v));
144    }
145
146    /// Set the arbitrary-width unsigned value to be applied at the next
147    /// ReadWrite phase. The write is buffered and the last write wins,
148    /// preserving order of distinct signals.
149    pub fn set_bigint(&self, v: &BigUint) {
150        phase::schedule(self.raw, phase::WriteVal::BigInt(v.clone()));
151    }
152
153    /// Set the four-state value to be applied at the next ReadWrite phase. The
154    /// write is buffered and the last write wins, preserving order of distinct
155    /// signals.
156    pub fn set_logic(&self, v: &LogicArray) {
157        phase::schedule(self.raw, phase::WriteVal::Logic(v.clone()));
158    }
159
160    // -------------- write: immediate (setimmediatevalue analog) --------------
161    //
162    // Immediate skips the write *scheduler*, not the phase *rule* (D108). The
163    // rule is the simulator's: writing during ReadOnly is illegal however the
164    // write gets there. Left unchecked, these two went straight to
165    // `vpi_put_value` and Icarus swallowed them with a printed diagnostic โ€”
166    // "attempted to put a value to variable 'x' during a read-only synch
167    // callback" โ€” after which the run continued on values that were never
168    // applied. That is the worst kind of wrong: it looks like a warning and it
169    // silently changes results.
170
171    /// Set the boolean value immediately, skipping the write scheduler. The
172    /// write is applied at once, but the ReadOnly rule is still enforced.
173    pub fn set_bool_now(&self, v: bool) {
174        phase::deny_write_in_read_only(self.raw);
175        self.raw.set_bool_now(v);
176    }
177
178    /// Set the unsigned 8-bit value immediately, skipping the write scheduler.
179    /// The write is applied at once, but the ReadOnly rule is still enforced.
180    pub fn set_u8_now(&self, v: u8) {
181        phase::deny_write_in_read_only(self.raw);
182        self.raw.set_u8_now(v);
183    }
184
185    /// Set the unsigned 16-bit value immediately, skipping the write scheduler.
186    /// The write is applied at once, but the ReadOnly rule is still enforced.
187    pub fn set_u16_now(&self, v: u16) {
188        phase::deny_write_in_read_only(self.raw);
189        self.raw.set_u16_now(v);
190    }
191
192    /// Set the unsigned 32-bit value immediately, skipping the write scheduler.
193    /// The write is applied at once, but the ReadOnly rule is still enforced.
194    pub fn set_u32_now(&self, v: u32) {
195        phase::deny_write_in_read_only(self.raw);
196        self.raw.set_u32_now(v);
197    }
198
199    /// Set the unsigned 64-bit value immediately, skipping the write scheduler.
200    /// The write is applied at once, but the ReadOnly rule is still enforced.
201    pub fn set_u64_now(&self, v: u64) {
202        phase::deny_write_in_read_only(self.raw);
203        self.raw.set_u64_now(v);
204    }
205
206    /// Set the unsigned 128-bit value immediately, skipping the write
207    /// scheduler. The write is applied at once, but the ReadOnly rule is still
208    /// enforced.
209    pub fn set_u128_now(&self, v: u128) {
210        phase::deny_write_in_read_only(self.raw);
211        self.raw.set_u128_now(v);
212    }
213
214    /// Set the arbitrary-width unsigned value immediately, skipping the write
215    /// scheduler. The write is applied at once, but the ReadOnly rule is still
216    /// enforced.
217    pub fn set_bigint_now(&self, v: &BigUint) {
218        phase::deny_write_in_read_only(self.raw);
219        self.raw.set_bigint_now(v);
220    }
221
222    /// Set the four-state value immediately, skipping the write scheduler. The
223    /// write is applied at once, but the ReadOnly rule is still enforced.
224    pub fn set_logic_now(&self, v: &LogicArray) {
225        phase::deny_write_in_read_only(self.raw);
226        self.raw.set_logic_now(v);
227    }
228}
229
230impl HandleEvent for LogicHandle {
231    /// Get the rising edge event for this handle
232    fn rising_edge(&self) -> Edge {
233        Edge::new(self.raw, EdgeKind::Rising)
234    }
235
236    /// Get the falling edge event for this handle
237    fn falling_edge(&self) -> Edge {
238        Edge::new(self.raw, EdgeKind::Falling)
239    }
240
241    /// Get the value change event for this handle
242    fn value_change(&self) -> Edge {
243        Edge::new(self.raw, EdgeKind::AnyChange)
244    }
245}