wavefst/block/
header.rs

1use std::convert::TryFrom;
2use std::io::{Read, Seek};
3
4use crate::error::{Error, Result};
5use crate::types::BlockType;
6use crate::util::{read_cstring, read_f64_be, read_u64_be, validate_endian};
7
8/// Fixed sizes of textual header fields, as defined by the FST specification.
9pub const VERSION_FIELD_LEN: usize = 128;
10/// Length (in bytes) reserved for the ASCII date field in the header.
11pub const DATE_FIELD_LEN: usize = 119;
12
13/// In-memory representation of the FST header block.
14#[derive(Debug, Clone)]
15pub struct Header {
16    /// Length of the header section (should remain 329 bytes for compatibility).
17    pub section_length: u64,
18    /// Earliest simulation timestamp recorded in the trace.
19    pub start_time: u64,
20    /// Latest simulation timestamp recorded in the trace.
21    pub end_time: u64,
22    /// Writer memory usage hint captured during dump generation.
23    pub memory_used: u64,
24    /// Number of scopes written by the producer.
25    pub scope_count: u64,
26    /// Number of variables written by the producer.
27    pub var_count: u64,
28    /// Highest variable handle emitted (1-based index).
29    pub max_handle: u64,
30    /// Number of value-change sections present in the file.
31    pub vc_section_count: u64,
32    /// Base-10 exponent describing the simulation time unit (10^exponent seconds).
33    pub timescale_exponent: i8,
34    /// Producer version string (null terminated within the 128-byte buffer).
35    pub version: String,
36    /// Producer supplied date string (null terminated within the 119-byte buffer).
37    pub date: String,
38    /// File type marker (e.g. Verilog, VHDL, mixed).
39    pub file_type: u8,
40    /// Simulation time zero offset stored in the header.
41    pub time_zero: u64,
42}
43
44impl Default for Header {
45    fn default() -> Self {
46        Self {
47            section_length: 329,
48            start_time: 0,
49            end_time: 0,
50            memory_used: 0,
51            scope_count: 0,
52            var_count: 0,
53            max_handle: 0,
54            vc_section_count: 0,
55            timescale_exponent: -9,
56            version: String::from("fst-format"),
57            date: String::from(""),
58            file_type: 0,
59            time_zero: 0,
60        }
61    }
62}
63
64impl Header {
65    /// Reads and parses the header block from the provided reader.
66    pub fn read<R: Read + Seek>(reader: &mut R) -> Result<Self> {
67        let mut block_type = [0u8; 1];
68        reader.read_exact(&mut block_type)?;
69        let block_type = BlockType::try_from(block_type[0]).map_err(|_| {
70            Error::invalid(format!("unexpected first block type {:02x}", block_type[0]))
71        })?;
72
73        if block_type != BlockType::Header {
74            return Err(Error::invalid(format!(
75                "expected header block (0), found {block_type:?}"
76            )));
77        }
78
79        let section_length = read_u64_be(reader)?;
80        let start_time = read_u64_be(reader)?;
81        let end_time = read_u64_be(reader)?;
82        let endian_test = read_f64_be(reader)?;
83        validate_endian(endian_test)?;
84        let memory_used = read_u64_be(reader)?;
85        let scope_count = read_u64_be(reader)?;
86        let var_count = read_u64_be(reader)?;
87        let max_handle = read_u64_be(reader)?;
88        let vc_section_count = read_u64_be(reader)?;
89
90        let mut timescale_buf = [0u8; 1];
91        reader.read_exact(&mut timescale_buf)?;
92        let timescale_exponent = timescale_buf[0] as i8;
93
94        let version = read_cstring(reader, VERSION_FIELD_LEN)?;
95        let date = read_cstring(reader, DATE_FIELD_LEN)?;
96
97        let mut file_type_buf = [0u8; 1];
98        reader.read_exact(&mut file_type_buf)?;
99        let file_type = file_type_buf[0];
100        let time_zero = read_u64_be(reader)?;
101
102        Ok(Self {
103            section_length,
104            start_time,
105            end_time,
106            memory_used,
107            scope_count,
108            var_count,
109            max_handle,
110            vc_section_count,
111            timescale_exponent,
112            version,
113            date,
114            file_type,
115            time_zero,
116        })
117    }
118
119    /// Returns the timescale as 10^exponent seconds.
120    pub fn timescale_factor(&self) -> f64 {
121        10f64.powi(self.timescale_exponent as i32)
122    }
123}