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}