mister_fpga/
types.rs

1use bitvec::prelude::*;
2use serde::ser::SerializeSeq;
3use serde::{Serialize, Serializer};
4use std::fmt::{Debug, Display, Formatter, Write};
5
6pub mod units;
7
8/// A 128-bit status bit map, used by MiSTer cores to communicate options and triggers.
9#[derive(Clone, Copy, PartialEq, Eq)]
10pub struct StatusBitMap(BitArray<[u16; 8], Lsb0>);
11
12impl Serialize for StatusBitMap {
13    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
14    where
15        S: Serializer,
16    {
17        // If the format is human-readable, use bits as a string instead.
18        if serializer.is_human_readable() {
19            return serializer.serialize_str(&self.to_string());
20        }
21
22        // Either serialize the first 4 words or the whole array.
23        let r = self.as_raw_slice();
24        let short = r.iter().skip(4).all(|x| *x == 0);
25
26        let mut seq = serializer.serialize_seq(Some(if short { 4 } else { 8 }))?;
27        seq.serialize_element(&r[0])?;
28        seq.serialize_element(&r[1])?;
29        seq.serialize_element(&r[2])?;
30        seq.serialize_element(&r[3])?;
31
32        if !short {
33            seq.serialize_element(&r[4])?;
34            seq.serialize_element(&r[5])?;
35            seq.serialize_element(&r[6])?;
36            seq.serialize_element(&r[7])?;
37        }
38        seq.end()
39    }
40}
41
42impl Debug for StatusBitMap {
43    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
44        let mut str = String::with_capacity(128 + 4);
45        let arr = self.0.as_raw_slice();
46
47        for byte in 0..arr.len() {
48            str += &format!("{:032b} ", arr[byte]);
49            if arr[byte..].iter().all(|x| *x == 0) {
50                break;
51            }
52        }
53
54        f.debug_tuple("StatusBitMap")
55            .field(&str.trim_end())
56            .finish()
57    }
58}
59
60impl Default for StatusBitMap {
61    fn default() -> Self {
62        Self(BitArray::new([0; 8]))
63    }
64}
65
66impl StatusBitMap {
67    pub fn new() -> Self {
68        Self::default()
69    }
70
71    pub fn as_raw_slice(&self) -> &[u16] {
72        self.0.as_raw_slice()
73    }
74    pub fn as_mut_raw_slice(&mut self) -> &mut [u16] {
75        self.0.as_raw_mut_slice()
76    }
77
78    pub fn has_extra(&self) -> bool {
79        self.0.as_raw_slice()[4..].iter().any(|x| *x != 0)
80    }
81
82    pub fn set(&mut self, idx: usize, value: bool) {
83        self.0.set(idx, value);
84    }
85
86    pub fn get(&self, idx: usize) -> bool {
87        self.0[idx]
88    }
89
90    pub fn len(&self) -> usize {
91        self.0.len()
92    }
93
94    pub fn is_empty(&self) -> bool {
95        self.0.is_empty()
96    }
97
98    pub fn get_range(&self, range: impl IntoIterator<Item = u8>) -> u32 {
99        let mut result = 0;
100        let mut iter = range.into_iter().peekable();
101        let start = *iter.peek().unwrap_or(&0);
102        for i in iter {
103            result |= (self.get(i as usize) as u32) << (i - start) as usize;
104        }
105        result
106    }
107
108    /// Set a range of bits to a value. This cannot do more than 32 bits at a time.
109    /// On error, this may panic.
110    pub fn set_range(&mut self, range: impl IntoIterator<Item = u8>, mut value: u32) {
111        for i in range.into_iter() {
112            self.set(i as usize, value & 1 != 0);
113            value >>= 1;
114        }
115    }
116
117    pub fn debug_header() -> String {
118        "              Upper                          Lower\n\
119        0         1         2         3          4         5         6\n\
120        01234567890123456789012345678901 23456789012345678901234567890123\n\
121        0123456789ABCDEFGHIJKLMNOPQRSTUV 0123456789ABCDEFGHIJKLMNOPQRSTUV\n\
122        "
123        .to_string()
124    }
125
126    pub fn debug_string(&self, header: bool) -> String {
127        let mut result = String::new();
128        if header {
129            result += &Self::debug_header();
130        }
131
132        fn output_u64(mut word64: u64) -> String {
133            let mut word_str = String::new();
134            while word64 != 0 {
135                word_str.push(if word64 & 1 != 0 { 'X' } else { ' ' });
136                word64 >>= 1;
137            }
138            if word_str.len() > 32 {
139                word_str.insert(32, ' ');
140            }
141            word_str
142        }
143
144        let raw = self.0.as_raw_slice();
145        result.push_str(&output_u64(
146            (raw[0] as u64)
147                | ((raw[1] as u64) << 16)
148                | ((raw[2] as u64) << 32)
149                | ((raw[3] as u64) << 48),
150        ));
151
152        if raw[4] != 0 || raw[5] != 0 || raw[6] != 0 || raw[7] != 0 {
153            if header {
154                result += "\n\
155                    0     0         0         0          1         1         1       \n\
156                    6     7         8         9          0         1         2       \n\
157                    45678901234567890123456789012345 67890123456789012345678901234567\n\
158                    ";
159            }
160            result.push_str(&output_u64(
161                ((raw[0] as u64) << 48)
162                    | ((raw[1] as u64) << 32)
163                    | ((raw[2] as u64) << 16)
164                    | (raw[3] as u64),
165            ));
166        }
167
168        result.push('\n');
169        result
170    }
171
172    pub fn iter(&self) -> impl Iterator<Item = bool> + '_ {
173        self.0.iter().by_vals()
174    }
175}
176
177impl Display for StatusBitMap {
178    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
179        for i in 0..(if self.has_extra() { 128 } else { 64 }) {
180            f.write_char(if self.get(i) { '1' } else { '0' })?;
181        }
182        Ok(())
183    }
184}
185
186#[test]
187fn status_bits() {
188    let mut status_bits = StatusBitMap::new();
189    status_bits.set(0, true);
190    status_bits.set(2, true);
191    status_bits.set_range(4..8, 0b0101);
192
193    status_bits.set_range(32..34, 3);
194    status_bits.set_range(64..67, 3);
195    status_bits.set_range(96..120, 8);
196
197    assert_eq!(
198        status_bits.to_string(),
199        concat!(
200            "10101010000000000000000000000000",
201            "11000000000000000000000000000000",
202            "11000000000000000000000000000000",
203            "00010000000000000000000000000000"
204        )
205    );
206
207    assert_eq!(status_bits.get_range(32..34), 3);
208    assert_eq!(status_bits.get_range(64..67), 3);
209}