fst_reader/
types.rs

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