makai_waveform_db/
lib.rs

1// Coming from a VCD file there are two primary and slightly opposed ways to
2// represent the waveform in-memory.
3// 1. A compressed but complete format where the minimum amount of memory is
4//    used to store the waveforms. This format needs to be easily queried for
5//    the waveform value at arbitrary timestamps, as well as knowing if any
6//    transitions exist within a given timespan.
7// 2. A format that allows the waveform to be shown on the display for a given
8//    timespan. This format cannot simply be downsampled from the compressed
9//    format because that would miss brief transitions that still need to be
10//    shown in the waveform. This format has a finite resolution given to it
11//    before it is extracted from the compressed waveform.
12
13// Compressed Format:
14//    A critical part of the compressed format is that it can be easily searched
15//    like a binary tree for the desired timestamp index. This requires
16//    fixed-size blocks of data with headers. These fixed-size blocks start with
17//    a header containing the 64-bit timestamp offset of the first change/skip
18//    in the block. The header also contains another 64-bit mask representing
19//    whether each of the 64 locations in the block is a header or a skip count.
20//
21//    The block size is fixed at 512 bytes, where the first 16 bytes store the
22//    timestamp and then then bit-vector offset, and all following bytes either
23//    indicate transitions or timestamp skips.
24//
25//    By looking at the first byte in this list, it's MSB is a one if it
26//    represents a number of consecutive changes (from 1 to 128) in the value.
27//    If the MSB is a zero, then it and up to eight following bytes with an
28//    MSB of zero are a skip count (up to 64 bits excluding the MSBs). Skips at
29//    the end of a block are ignored since the next block is going to define a
30//    new starting timestamp.
31//
32//    The compressed data for each signal in the waveform references timestamp
33//    indices, not the timestamps themselves.
34
35pub mod bitvector;
36pub mod errors;
37pub mod history;
38pub mod real;
39pub mod vector;
40
41use std::cmp::Ordering;
42use std::collections::HashMap;
43
44use crate::bitvector::BitVector;
45use crate::errors::*;
46use crate::real::*;
47use crate::vector::*;
48
49#[derive(Clone, Debug, PartialEq, Eq)]
50pub enum WaveformSearchMode {
51    Before,
52    After,
53    Closest,
54    Exact,
55}
56
57pub enum WaveformSignalResult<'a> {
58    Vector(&'a WaveformSignalVector),
59    Real(&'a WaveformSignalReal),
60}
61
62#[derive(Clone, Debug, PartialEq)]
63pub enum WaveformValueResult {
64    Vector(BitVector, usize), // value, timestamp index
65    Real(f64, usize),         // value, timestamp index
66}
67
68impl WaveformValueResult {
69    pub fn is_unknown(&self) -> bool {
70        match self {
71            Self::Vector(bv, _) => bv.is_unknown(),
72            _ => false,
73        }
74    }
75
76    pub fn is_high_impedance(&self) -> bool {
77        match self {
78            Self::Vector(bv, _) => bv.is_high_impedance(),
79            _ => false,
80        }
81    }
82
83    pub fn get_timestamp_index(&self) -> usize {
84        match self {
85            Self::Vector(_, index) | Self::Real(_, index) => *index,
86        }
87    }
88}
89
90pub struct Waveform {
91    timestamps: Vec<u64>,
92    vector_signals: HashMap<usize, WaveformSignalVector>,
93    real_signals: HashMap<usize, WaveformSignalReal>,
94}
95
96impl Waveform {
97    pub fn new() -> Self {
98        Self {
99            timestamps: Vec::new(),
100            vector_signals: HashMap::default(),
101            real_signals: HashMap::default(),
102        }
103    }
104
105    pub fn shard(self, num_shards: usize) -> Vec<Self> {
106        let mut shards = Vec::new();
107        for _ in 0..num_shards {
108            let mut shard = Self::new();
109            shard.timestamps = self.timestamps.clone();
110            shards.push(shard);
111        }
112        for (id, signal) in self.vector_signals {
113            shards[id % num_shards].vector_signals.insert(id, signal);
114        }
115        for (id, signal) in self.real_signals {
116            shards[id % num_shards].real_signals.insert(id, signal);
117        }
118        shards
119    }
120
121    pub fn unshard(shards: Vec<Self>) -> WaveformResult<Self> {
122        let timestamps = if let Some(shard) = shards.first() {
123            shard.timestamps.clone()
124        } else {
125            Vec::new()
126        };
127        for shard in &shards {
128            if shard.timestamps != timestamps {
129                return Err(WaveformError::MismatchedTimestamps);
130            }
131        }
132        let mut merged = Self::new();
133        merged.timestamps = timestamps;
134        for shard in shards {
135            merged.vector_signals.extend(shard.vector_signals);
136            merged.real_signals.extend(shard.real_signals);
137        }
138        Ok(merged)
139    }
140
141    pub fn initialize_vector(&mut self, id: usize, width: usize) {
142        self.vector_signals
143            .insert(id, WaveformSignalVector::new(width));
144    }
145
146    pub fn initialize_real(&mut self, id: usize) {
147        self.real_signals.insert(id, WaveformSignalReal::new());
148    }
149
150    pub fn get_vector_signal(&self, id: usize) -> Option<&WaveformSignalVector> {
151        self.vector_signals.get(&id)
152    }
153
154    pub fn get_real_signal(&self, id: usize) -> Option<&WaveformSignalReal> {
155        self.real_signals.get(&id)
156    }
157
158    pub fn get_signal(&self, id: usize) -> Option<WaveformSignalResult<'_>> {
159        if let Some(signal) = self.vector_signals.get(&id) {
160            Some(WaveformSignalResult::Vector(signal))
161        } else {
162            self.real_signals.get(&id).map(WaveformSignalResult::Real)
163        }
164    }
165
166    pub fn get_timestamps(&self) -> &Vec<u64> {
167        &self.timestamps
168    }
169
170    pub fn insert_timestamp(&mut self, timestamp: u64) -> WaveformResult<()> {
171        let Some(last) = self.timestamps.last() else {
172            self.timestamps.push(timestamp);
173            return Ok(());
174        };
175        match timestamp.cmp(last) {
176            Ordering::Less => return Err(WaveformError::DecreasingTimestamp { timestamp }),
177            Ordering::Greater => self.timestamps.push(timestamp),
178            Ordering::Equal => {}
179        }
180        Ok(())
181    }
182
183    pub fn update_vector(&mut self, id: usize, value: BitVector) -> WaveformResult<()> {
184        let signal = if let Some(signal) = self.vector_signals.get_mut(&id) {
185            signal
186        } else {
187            return Err(WaveformError::InvalidId { id });
188        };
189        if signal.get_width() < value.get_bit_width() {
190            return Err(WaveformError::InvalidWidth {
191                id,
192                expected: signal.get_width(),
193                actual: value.get_bit_width(),
194            });
195        }
196        signal.update(self.timestamps.len() - 1, value);
197        Ok(())
198    }
199
200    pub fn update_real(&mut self, id: usize, value: f64) -> WaveformResult<()> {
201        let signal = if let Some(signal) = self.real_signals.get_mut(&id) {
202            signal
203        } else {
204            return Err(WaveformError::InvalidId { id });
205        };
206        signal.update(self.timestamps.len() - 1, value);
207        Ok(())
208    }
209
210    pub fn timestamps_count(&self) -> usize {
211        self.timestamps.len()
212    }
213
214    pub fn get_block_size(&self) -> usize {
215        let mut size = 0;
216        for signal in self.vector_signals.values() {
217            size += signal.get_history().get_block_size();
218        }
219        for signal in self.real_signals.values() {
220            size += signal.get_history().get_block_size();
221        }
222        size
223    }
224
225    pub fn get_vector_size(&self) -> usize {
226        let mut size = 0;
227        for signal in self.vector_signals.values() {
228            size += signal.get_vector_size();
229        }
230        for signal in self.real_signals.values() {
231            size += signal.get_vector_size();
232        }
233        size
234    }
235
236    pub fn count_empty(&self) -> usize {
237        let mut empty = 0;
238        for signal in self.vector_signals.values() {
239            if signal.is_empty() {
240                empty += 1;
241            }
242        }
243        for signal in self.real_signals.values() {
244            if signal.is_empty() {
245                empty += 1;
246            }
247        }
248        empty
249    }
250
251    pub fn count_one(&self) -> usize {
252        let mut empty = 0;
253        for signal in self.vector_signals.values() {
254            if signal.len() == 1 {
255                empty += 1;
256            }
257        }
258        for signal in self.real_signals.values() {
259            if signal.len() == 1 {
260                empty += 1;
261            }
262        }
263        empty
264    }
265
266    /// Returns the first and last timestamps (both inclusive) that are present
267    /// in this waveform
268    pub fn get_timestamp_range(&self) -> std::ops::Range<u64> {
269        match (self.get_timestamps().first(), self.get_timestamps().last()) {
270            (Some(start), Some(end)) => *start..*end,
271            _ => 0..0,
272        }
273    }
274
275    /// Binary search for the index of the requested timestamp, if the exact
276    /// timestamp exists. Otherwise, the search mode is used to determine where
277    /// else to look to look for a timestamp, either closest of any timestamp,
278    /// closest timestamp before, or closest timestamp after. If a timestamp
279    /// is found, this function returns a tuple (timestamp, timestamp index)
280    pub fn search_timestamp(
281        &self,
282        timestamp: u64,
283        search_mode: WaveformSearchMode,
284    ) -> Option<usize> {
285        // https://stackoverflow.com/questions/30245166/find-the-nearest-closest-value-in-a-sorted-list
286        let (mut start, mut end) = (0, self.timestamps.len() - 1);
287        // If the search timestamp is outside of the range of timestamps
288        if timestamp < self.timestamps[start] {
289            return match search_mode {
290                WaveformSearchMode::Exact | WaveformSearchMode::Before => None,
291                WaveformSearchMode::After | WaveformSearchMode::Closest => Some(start),
292            };
293        } else if self.timestamps[end] < timestamp {
294            return match search_mode {
295                WaveformSearchMode::Exact | WaveformSearchMode::After => None,
296                WaveformSearchMode::Before | WaveformSearchMode::Closest => Some(end),
297            };
298        }
299        // Iterate through until start == end + 1
300        while start <= end {
301            let mid = (start + end) / 2;
302            let mid_value = self.timestamps[mid];
303            match timestamp.cmp(&mid_value) {
304                Ordering::Less => end = mid - 1,
305                Ordering::Greater => start = mid + 1,
306                Ordering::Equal => return Some(mid),
307            }
308        }
309        // Select result based on search mode
310        match search_mode {
311            WaveformSearchMode::Exact => None,
312            WaveformSearchMode::Before => Some(end),
313            WaveformSearchMode::After => Some(start),
314            WaveformSearchMode::Closest => {
315                if (self.timestamps[start] - timestamp) < (timestamp - self.timestamps[end]) {
316                    Some(start)
317                } else {
318                    Some(end)
319                }
320            }
321        }
322    }
323
324    pub fn search_value_bit_index(
325        &self,
326        idcode: usize,
327        timestamp_index: usize,
328        search_mode: WaveformSearchMode,
329        bit_index: Option<usize>,
330    ) -> Option<WaveformValueResult> {
331        if let Some(signal) = self.vector_signals.get(&idcode) {
332            let Some(index) = signal.get_history().search_timestamp_index(timestamp_index, search_mode) else {
333                return None
334            };
335            let bv = signal.get_bitvector(index.get_value_index());
336            let bv = if let Some(index) = bit_index {
337                BitVector::from(bv.get_bit(index))
338            } else {
339                bv
340            };
341            Some(WaveformValueResult::Vector(bv, index.get_timestamp_index()))
342        } else if let Some(signal) = self.real_signals.get(&idcode) {
343            let Some(index) = signal.get_history().search_timestamp_index(timestamp_index, search_mode) else {
344                return None
345            };
346            let r = signal.get_real(index.get_value_index());
347            Some(WaveformValueResult::Real(r, index.get_timestamp_index()))
348        } else {
349            None
350        }
351    }
352
353    pub fn search_value(
354        &self,
355        idcode: usize,
356        timestamp_index: usize,
357        search_mode: WaveformSearchMode,
358    ) -> Option<WaveformValueResult> {
359        self.search_value_bit_index(idcode, timestamp_index, search_mode, None)
360    }
361}
362
363impl Default for Waveform {
364    fn default() -> Self {
365        Self::new()
366    }
367}