1use num_enum::TryFromPrimitive;
8#[cfg(test)]
9use proptest_derive::Arbitrary;
10use std::fmt::Formatter;
11use std::num::NonZeroU32;
12
13pub(crate) const HIERARCHY_NAME_MAX_SIZE: usize = 65536;
17pub(crate) const HIERARCHY_ATTRIBUTE_MAX_SIZE: usize = 65536 + 4096;
18
19#[derive(Debug, PartialEq)]
20#[cfg_attr(test, derive(Arbitrary))]
21pub struct FstSignalHandle(NonZeroU32);
22
23impl FstSignalHandle {
24 pub(crate) fn new(value: u32) -> Self {
25 FstSignalHandle(NonZeroU32::new(value).unwrap())
26 }
27 pub fn from_index(index: usize) -> Self {
28 FstSignalHandle(NonZeroU32::new((index as u32) + 1).unwrap())
29 }
30 pub fn get_index(&self) -> usize {
31 (self.0.get() - 1) as usize
32 }
33
34 #[cfg(test)]
35 pub(crate) fn get_raw(&self) -> u32 {
36 self.0.get()
37 }
38}
39
40impl std::fmt::Display for FstSignalHandle {
41 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
42 write!(f, "H{}", self.0)
43 }
44}
45
46#[derive(Debug, PartialEq, Clone, Copy)]
47pub(crate) enum FloatingPointEndian {
48 Little,
49 Big,
50}
51
52#[repr(u8)]
53#[derive(Debug, TryFromPrimitive, Clone, Copy, PartialEq)]
54#[cfg_attr(test, derive(Arbitrary))]
55pub enum FileType {
56 Verilog = 0,
57 Vhdl = 1,
58 VerilogVhdl = 2,
59}
60
61#[repr(u8)]
62#[derive(Debug, TryFromPrimitive, PartialEq)]
63pub enum BlockType {
64 Header = 0,
65 VcData = 1,
66 Blackout = 2,
67 Geometry = 3,
68 Hierarchy = 4,
69 VcDataDynamicAlias = 5,
70 HierarchyLZ4 = 6,
71 HierarchyLZ4Duo = 7,
72 VcDataDynamicAlias2 = 8,
73 GZipWrapper = 254,
74 Skip = 255,
75}
76
77#[repr(u8)]
78#[derive(Debug, TryFromPrimitive, Clone, Copy, PartialEq)]
79#[cfg_attr(test, derive(Arbitrary))]
80pub enum FstScopeType {
81 Module = 0,
83 Task = 1,
84 Function = 2,
85 Begin = 3,
86 Fork = 4,
87 Generate = 5,
88 Struct = 6,
89 Union = 7,
90 Class = 8,
91 Interface = 9,
92 Package = 10,
93 Program = 11,
94 VhdlArchitecture = 12,
96 VhdlProcedure = 13,
97 VhdlFunction = 14,
98 VhdlRecord = 15,
99 VhdlProcess = 16,
100 VhdlBlock = 17,
101 VhdlForGenerate = 18,
102 VhdlIfGenerate = 19,
103 VhdlGenerate = 20,
104 VhdlPackage = 21,
105 SvArray = 22,
107 AttributeBegin = 252,
109 AttributeEnd = 253,
110 VcdScope = 254,
112 VcdUpScope = 255,
113}
114
115#[repr(u8)]
116#[derive(Debug, TryFromPrimitive, PartialEq, Copy, Clone)]
117#[cfg_attr(test, derive(Arbitrary))]
118pub enum FstVarType {
119 Event = 0,
121 Integer = 1,
122 Parameter = 2,
123 Real = 3,
124 RealParameter = 4,
125 Reg = 5,
126 Supply0 = 6,
127 Supply1 = 7,
128 Time = 8,
129 Tri = 9,
130 TriAnd = 10,
131 TriOr = 11,
132 TriReg = 12,
133 Tri0 = 13,
134 Tri1 = 14,
135 Wand = 15, Wire = 16,
137 Wor = 17, Port = 18,
139 SparseArray = 19,
140 RealTime = 20,
141 GenericString = 21,
142 Bit = 22,
144 Logic = 23,
145 Int = 24,
146 ShortInt = 25,
147 LongInt = 26,
148 Byte = 27,
149 Enum = 28,
150 ShortReal = 29,
151}
152
153impl FstVarType {
154 pub fn is_real(&self) -> bool {
156 matches!(
157 self,
158 FstVarType::Real
159 | FstVarType::RealParameter
160 | FstVarType::RealTime
161 | FstVarType::ShortReal
162 )
163 }
164}
165
166#[repr(u8)]
167#[derive(Debug, TryFromPrimitive, Clone, Copy, PartialEq)]
168#[cfg_attr(test, derive(Arbitrary))]
169pub enum FstVarDirection {
170 Implicit = 0,
171 Input = 1,
172 Output = 2,
173 InOut = 3,
174 Buffer = 4,
175 Linkage = 5,
176}
177
178#[repr(u8)]
179#[derive(Debug, TryFromPrimitive, Clone, Copy, PartialEq)]
180#[cfg_attr(test, derive(Arbitrary))]
181pub enum FstVhdlVarType {
182 None = 0,
183 Signal = 1,
184 Variable = 2,
185 Constant = 3,
186 File = 4,
187 Memory = 5,
188}
189
190#[repr(u8)]
191#[derive(Debug, TryFromPrimitive, Clone, Copy, PartialEq)]
192#[cfg_attr(test, derive(Arbitrary))]
193pub enum FstVhdlDataType {
194 None = 0,
195 Boolean = 1,
196 Bit = 2,
197 Vector = 3,
198 ULogic = 4,
199 ULogicVector = 5,
200 Logic = 6,
201 LogicVector = 7,
202 Unsigned = 8,
203 Signed = 9,
204 Integer = 10,
205 Real = 11,
206 Natural = 12,
207 Positive = 13,
208 Time = 14,
209 Character = 15,
210 String = 16,
211}
212
213#[repr(u8)]
214#[derive(Debug, TryFromPrimitive, PartialEq)]
215pub enum AttributeType {
216 Misc = 0,
217 Array = 1,
218 Enum = 2,
219 Pack = 3,
220}
221
222#[repr(u8)]
223#[derive(Debug, TryFromPrimitive, PartialEq)]
224pub enum MiscType {
225 Comment = 0,
226 EnvVar = 1,
227 SupVar = 2,
228 PathName = 3,
229 SourceStem = 4,
230 SourceInstantiationStem = 5,
231 ValueList = 6,
232 EnumTable = 7,
233 Unknown = 8,
234}
235
236pub(crate) const DOUBLE_ENDIAN_TEST: f64 = std::f64::consts::E;
237
238#[derive(Debug, PartialEq)]
239#[cfg_attr(test, derive(Arbitrary))]
240#[allow(dead_code)]
241pub(crate) struct Header {
242 pub(crate) start_time: u64,
243 pub(crate) end_time: u64,
244 pub(crate) memory_used_by_writer: u64,
245 pub(crate) scope_count: u64,
246 pub(crate) var_count: u64,
247 pub(crate) max_var_id_code: u64, pub(crate) vc_section_count: u64,
249 pub(crate) timescale_exponent: i8,
250 pub(crate) version: String,
251 pub(crate) date: String,
252 pub(crate) file_type: FileType,
253 pub(crate) time_zero: u64,
254}
255
256#[derive(Debug, PartialEq)]
257#[cfg_attr(test, derive(Arbitrary))]
258pub(crate) enum SignalInfo {
259 BitVec(NonZeroU32),
260 Real,
261}
262
263impl SignalInfo {
264 pub(crate) fn from_file_format(value: u32) -> Self {
265 if value == 0 {
266 SignalInfo::Real
267 } else if value != u32::MAX {
268 SignalInfo::BitVec(NonZeroU32::new(value + 1).unwrap())
269 } else {
270 SignalInfo::BitVec(NonZeroU32::new(1).unwrap())
271 }
272 }
273
274 #[cfg(test)]
275 pub(crate) fn to_file_format(&self) -> u32 {
276 match self {
277 SignalInfo::BitVec(value) => match value.get() {
278 1 => u32::MAX,
279 other => other - 1,
280 },
281 SignalInfo::Real => 0,
282 }
283 }
284
285 #[inline]
286 pub(crate) fn len(&self) -> u32 {
287 match self {
288 SignalInfo::BitVec(value) => value.get() - 1,
289 SignalInfo::Real => 8,
290 }
291 }
292
293 #[inline]
294 pub(crate) fn is_real(&self) -> bool {
295 match self {
296 SignalInfo::BitVec(_) => false,
297 SignalInfo::Real => true,
298 }
299 }
300}
301
302#[derive(Debug, PartialEq)]
303#[cfg_attr(test, derive(Arbitrary))]
304pub(crate) struct BlackoutData {
305 pub(crate) time: u64,
306 pub(crate) contains_activity: bool,
307}
308
309#[derive(Debug, Clone)]
310pub(crate) struct DataSectionInfo {
311 pub(crate) file_offset: u64, pub(crate) start_time: u64,
313 pub(crate) end_time: u64,
314 pub(crate) kind: DataSectionKind,
315 #[allow(dead_code)]
317 pub(crate) mem_required_for_traversal: u64,
318}
319
320#[derive(Debug, PartialEq)]
321#[cfg_attr(test, derive(Arbitrary))]
322pub enum FstHierarchyEntry {
323 Scope {
324 tpe: FstScopeType,
325 name: String,
326 component: String,
327 },
328 UpScope,
329 Var {
330 tpe: FstVarType,
331 direction: FstVarDirection,
332 name: String,
333 length: u32,
334 handle: FstSignalHandle,
335 is_alias: bool,
336 },
337 PathName {
338 id: u64,
340 name: String,
341 },
342 SourceStem {
343 is_instantiation: bool,
344 path_id: u64,
345 line: u64,
346 },
347 Comment {
348 string: String,
349 },
350 EnumTable {
351 name: String,
352 handle: u64,
353 mapping: Vec<(String, String)>,
354 },
355 EnumTableRef {
356 handle: u64,
357 },
358 VhdlVarInfo {
359 type_name: String,
360 var_type: FstVhdlVarType,
361 data_type: FstVhdlDataType,
362 },
363 AttributeEnd,
364}
365
366#[derive(Debug, Copy, Clone)]
367#[cfg_attr(test, derive(Arbitrary))]
368pub(crate) enum HierarchyCompression {
369 Uncompressed,
370 ZLib,
371 Lz4,
372 Lz4Duo,
373}
374
375type BitMaskWord = u64;
376
377pub(crate) struct BitMask {
378 inner: Vec<BitMaskWord>,
379}
380
381impl BitMask {
382 pub(crate) fn repeat(value: bool, size: usize) -> Self {
383 let word = if value { BitMaskWord::MAX } else { 0 };
384 let word_count = size.div_ceil(BitMaskWord::BITS as usize);
385 Self {
386 inner: vec![word; word_count],
387 }
388 }
389
390 pub(crate) fn set(&mut self, index: usize, value: bool) {
391 let (word_idx, bit_idx) = Self::word_and_bit_index(index);
392 if value {
393 self.inner[word_idx] |= (1 as BitMaskWord) << bit_idx;
394 } else {
395 self.inner[word_idx] &= !((1 as BitMaskWord) << bit_idx);
396 }
397 }
398
399 fn word_and_bit_index(index: usize) -> (usize, usize) {
400 let word_idx = index / BitMaskWord::BITS as usize;
401 let bit_idx = index - word_idx * BitMaskWord::BITS as usize;
402 (word_idx, bit_idx)
403 }
404
405 pub(crate) fn is_set(&self, index: usize) -> bool {
406 let (word_idx, bit_idx) = Self::word_and_bit_index(index);
407 (self.inner[word_idx] >> bit_idx) & 1 == 1
408 }
409}
410
411pub(crate) struct DataFilter {
412 pub(crate) start: u64,
413 pub(crate) end: u64,
414 pub(crate) signals: BitMask,
415}
416
417#[derive(Debug, Clone, Copy, PartialEq)]
418pub(crate) enum DataSectionKind {
419 Standard,
420 DynamicAlias,
421 DynamicAlias2,
422}
423
424#[derive(Debug, Clone, Copy)]
425pub(crate) enum ValueChangePackType {
426 Lz4,
427 FastLz,
428 Zlib,
429}
430
431impl ValueChangePackType {
432 pub(crate) fn from_u8(value: u8) -> Self {
433 match value {
434 b'4' => ValueChangePackType::Lz4,
435 b'F' => ValueChangePackType::FastLz,
436 _ => ValueChangePackType::Zlib,
437 }
438 }
439}
440
441impl DataSectionKind {
442 pub(crate) fn from_block_type(tpe: &BlockType) -> Option<Self> {
443 match tpe {
444 BlockType::VcData => Some(DataSectionKind::Standard),
445 BlockType::VcDataDynamicAlias => Some(DataSectionKind::DynamicAlias),
446 BlockType::VcDataDynamicAlias2 => Some(DataSectionKind::DynamicAlias2),
447 _ => None,
448 }
449 }
450}
451
452#[cfg(test)]
453mod tests {
454 use super::*;
455
456 #[test]
457 fn test_sizes() {
458 assert_eq!(std::mem::size_of::<SignalInfo>(), 4);
460 }
461}