cameleon_genapi/
masked_int_reg.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use super::{
6    elem_type::{BitMask, Endianness, IntegerRepresentation, Sign},
7    interface::{IInteger, INode, IRegister, ISelector, IncrementMode},
8    node_base::{NodeAttributeBase, NodeBase},
9    register_base::RegisterBase,
10    store::{CacheStore, NodeId, NodeStore, ValueStore},
11    utils, Device, GenApiError, GenApiResult, ValueCtxt,
12};
13
14#[derive(Debug, Clone)]
15pub struct MaskedIntRegNode {
16    pub(crate) attr_base: NodeAttributeBase,
17    pub(crate) register_base: RegisterBase,
18
19    pub(crate) bit_mask: BitMask,
20    pub(crate) sign: Sign,
21    pub(crate) endianness: Endianness,
22    pub(crate) unit: Option<String>,
23    pub(crate) representation: IntegerRepresentation,
24    pub(crate) p_selected: Vec<NodeId>,
25}
26
27impl MaskedIntRegNode {
28    #[must_use]
29    pub fn register_base(&self) -> &RegisterBase {
30        &self.register_base
31    }
32
33    #[must_use]
34    pub fn bit_mask(&self) -> BitMask {
35        self.bit_mask
36    }
37
38    #[must_use]
39    pub fn sign(&self) -> Sign {
40        self.sign
41    }
42
43    #[must_use]
44    pub fn endianness(&self) -> Endianness {
45        self.endianness
46    }
47
48    #[must_use]
49    pub fn unit_elem(&self) -> Option<&str> {
50        self.unit.as_deref()
51    }
52
53    #[must_use]
54    pub fn representation_elem(&self) -> IntegerRepresentation {
55        self.representation
56    }
57
58    #[must_use]
59    pub fn p_selected(&self) -> &[NodeId] {
60        &self.p_selected
61    }
62}
63
64impl INode for MaskedIntRegNode {
65    fn node_base(&self) -> NodeBase {
66        let elem_base = &self.register_base.elem_base;
67        NodeBase::new(&self.attr_base, elem_base)
68    }
69
70    fn streamable(&self) -> bool {
71        self.register_base().streamable()
72    }
73}
74
75impl IInteger for MaskedIntRegNode {
76    #[tracing::instrument(skip(self, device, store, cx),
77                          level = "trace",
78                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
79    fn value<T: ValueStore, U: CacheStore>(
80        &self,
81        device: &mut impl Device,
82        store: &impl NodeStore,
83        cx: &mut ValueCtxt<T, U>,
84    ) -> GenApiResult<i64> {
85        let nid = self.node_base().id();
86        let reg = self.register_base();
87
88        // Get register value.
89        let reg_value = reg.with_cache_or_read(nid, device, store, cx, |data| {
90            utils::int_from_slice(data, self.endianness, self.sign)
91        })?;
92
93        // Apply mask.
94        let len = reg.length(device, store, cx)? as usize;
95        let res = self
96            .bit_mask
97            .apply_mask(reg_value, len, self.endianness, self.sign);
98
99        Ok(res)
100    }
101
102    #[tracing::instrument(skip(self, device, store, cx),
103                          level = "trace",
104                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
105    fn set_value<T: ValueStore, U: CacheStore>(
106        &self,
107        value: i64,
108        device: &mut impl Device,
109        store: &impl NodeStore,
110        cx: &mut ValueCtxt<T, U>,
111    ) -> GenApiResult<()> {
112        let nid = self.node_base().id();
113        cx.invalidate_cache_by(nid);
114
115        let reg = self.register_base();
116        let old_reg_value = reg.with_cache_or_read(nid, device, store, cx, |data| {
117            utils::int_from_slice(data, self.endianness, self.sign)
118        })?;
119
120        let length = reg.length(device, store, cx)? as usize;
121        let new_reg_value =
122            self.bit_mask
123                .masked_value(old_reg_value, value, length, self.endianness, self.sign)?;
124        let mut buf = vec![0; length];
125        utils::bytes_from_int(new_reg_value, &mut buf, self.endianness, self.sign)?;
126        reg.write_and_cache(nid, &buf, device, store, cx)?;
127
128        Ok(())
129    }
130
131    #[tracing::instrument(skip(self, device, store, cx),
132                          level = "trace",
133                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
134    fn min<T: ValueStore, U: CacheStore>(
135        &self,
136        device: &mut impl Device,
137        store: &impl NodeStore,
138        cx: &mut ValueCtxt<T, U>,
139    ) -> GenApiResult<i64> {
140        let len = self.register_base().length(device, store, cx)? as usize;
141        Ok(self.bit_mask.min(len, self.endianness, self.sign))
142    }
143
144    #[tracing::instrument(skip(self, device, store, cx),
145                          level = "trace",
146                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
147    fn max<T: ValueStore, U: CacheStore>(
148        &self,
149        device: &mut impl Device,
150        store: &impl NodeStore,
151        cx: &mut ValueCtxt<T, U>,
152    ) -> GenApiResult<i64> {
153        let len = self.register_base().length(device, store, cx)? as usize;
154        Ok(self.bit_mask.max(len, self.endianness, self.sign))
155    }
156
157    fn inc_mode(&self, _: &impl NodeStore) -> Option<IncrementMode> {
158        None
159    }
160
161    fn inc<T: ValueStore, U: CacheStore>(
162        &self,
163        _: &mut impl Device,
164        _: &impl NodeStore,
165        _: &mut ValueCtxt<T, U>,
166    ) -> GenApiResult<Option<i64>> {
167        Ok(None)
168    }
169
170    fn valid_value_set(&self, _: &impl NodeStore) -> &[i64] {
171        &[]
172    }
173
174    fn representation(&self, _: &impl NodeStore) -> IntegerRepresentation {
175        self.representation_elem()
176    }
177
178    fn unit(&self, _: &impl NodeStore) -> Option<&str> {
179        self.unit_elem()
180    }
181
182    #[tracing::instrument(skip(self, store),
183                          level = "trace",
184                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
185    fn set_min<T: ValueStore, U: CacheStore>(
186        &self,
187        _: i64,
188        _: &mut impl Device,
189        store: &impl NodeStore,
190        _: &mut ValueCtxt<T, U>,
191    ) -> GenApiResult<()> {
192        Err(GenApiError::not_writable())
193    }
194
195    #[tracing::instrument(skip(self, store),
196                          level = "trace",
197                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
198    fn set_max<T: ValueStore, U: CacheStore>(
199        &self,
200        _: i64,
201        _: &mut impl Device,
202        store: &impl NodeStore,
203        _: &mut ValueCtxt<T, U>,
204    ) -> GenApiResult<()> {
205        Err(GenApiError::not_writable())
206    }
207
208    #[tracing::instrument(skip(self, device, store, cx),
209                          level = "trace",
210                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
211    fn is_readable<T: ValueStore, U: CacheStore>(
212        &self,
213        device: &mut impl Device,
214        store: &impl NodeStore,
215        cx: &mut ValueCtxt<T, U>,
216    ) -> GenApiResult<bool> {
217        self.register_base().is_readable(device, store, cx)
218    }
219
220    #[tracing::instrument(skip(self, device, store, cx),
221                          level = "trace",
222                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
223    fn is_writable<T: ValueStore, U: CacheStore>(
224        &self,
225        device: &mut impl Device,
226        store: &impl NodeStore,
227        cx: &mut ValueCtxt<T, U>,
228    ) -> GenApiResult<bool> {
229        self.register_base().is_writable(device, store, cx)
230    }
231}
232
233impl IRegister for MaskedIntRegNode {
234    #[tracing::instrument(skip(self, device, store, cx),
235                          level = "trace",
236                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
237    fn read<T: ValueStore, U: CacheStore>(
238        &self,
239        buf: &mut [u8],
240        device: &mut impl Device,
241        store: &impl NodeStore,
242        cx: &mut ValueCtxt<T, U>,
243    ) -> GenApiResult<()> {
244        let address = self.address(device, store, cx)?;
245        let length = self.length(device, store, cx)?;
246        self.register_base().read_and_cache(
247            self.node_base().id(),
248            address,
249            length,
250            buf,
251            device,
252            store,
253            cx,
254        )
255    }
256
257    #[tracing::instrument(skip(self, device, store, cx),
258                          level = "trace",
259                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
260    fn write<T: ValueStore, U: CacheStore>(
261        &self,
262        buf: &[u8],
263        device: &mut impl Device,
264        store: &impl NodeStore,
265        cx: &mut ValueCtxt<T, U>,
266    ) -> GenApiResult<()> {
267        self.register_base()
268            .write_and_cache(self.node_base().id(), buf, device, store, cx)
269    }
270
271    #[tracing::instrument(skip(self, device, store, cx),
272                          level = "trace",
273                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
274    fn address<T: ValueStore, U: CacheStore>(
275        &self,
276        device: &mut impl Device,
277        store: &impl NodeStore,
278        cx: &mut ValueCtxt<T, U>,
279    ) -> GenApiResult<i64> {
280        self.register_base().address(device, store, cx)
281    }
282
283    #[tracing::instrument(skip(self, device, store, cx),
284                          level = "trace",
285                          fields(node = store.name_by_id(self.node_base().id()).unwrap()))]
286    fn length<T: ValueStore, U: CacheStore>(
287        &self,
288        device: &mut impl Device,
289        store: &impl NodeStore,
290        cx: &mut ValueCtxt<T, U>,
291    ) -> GenApiResult<i64> {
292        self.register_base().length(device, store, cx)
293    }
294}
295
296impl ISelector for MaskedIntRegNode {
297    fn selecting_nodes(&self, _: &impl NodeStore) -> GenApiResult<&[NodeId]> {
298        Ok(self.p_selected())
299    }
300}
301
302impl BitMask {
303    fn apply_mask(
304        &self,
305        reg_value: i64,
306        reg_byte_len: usize,
307        endianness: Endianness,
308        sign: Sign,
309    ) -> i64 {
310        let mask = self.mask(reg_byte_len, endianness);
311        let (lsb, msb) = (
312            self.lsb(reg_byte_len, endianness),
313            self.msb(reg_byte_len, endianness),
314        );
315        let res = (reg_value & mask) >> lsb;
316
317        match sign {
318            Sign::Signed if res >> (msb - lsb) == 1 => {
319                // Do sign extension.
320                res | ((-1) ^ (mask >> lsb))
321            }
322            _ => res,
323        }
324    }
325
326    fn masked_value(
327        &self,
328        old_reg_value: i64,
329        value: i64,
330        reg_byte_len: usize,
331        endianness: Endianness,
332        sign: Sign,
333    ) -> GenApiResult<i64> {
334        if value > self.max(reg_byte_len, endianness, sign)
335            || value < self.min(reg_byte_len, endianness, sign)
336        {
337            return Err(GenApiError::invalid_data(
338                "given value doesn't fit into the bit range".into(),
339            ));
340        }
341
342        let mask = self.mask(reg_byte_len, endianness);
343        let lsb = self.lsb(reg_byte_len, endianness);
344        Ok((old_reg_value & !mask) | ((value << lsb) & mask))
345    }
346
347    fn lsb(self, reg_byte_len: usize, endianness: Endianness) -> usize {
348        let lsb = match self {
349            Self::SingleBit(lsb) | Self::Range { lsb, .. } => lsb as usize,
350        };
351
352        // Normalize the value.
353        let bits_len = reg_byte_len * 8;
354        match endianness {
355            Endianness::LE => lsb,
356            Endianness::BE => bits_len - lsb - 1,
357        }
358    }
359
360    fn msb(self, reg_byte_len: usize, endianness: Endianness) -> usize {
361        let msb = match self {
362            Self::SingleBit(msb) | Self::Range { msb, .. } => msb as usize,
363        };
364
365        // Normalize the value.
366        let bits_len = reg_byte_len * 8;
367        match endianness {
368            Endianness::LE => msb,
369            Endianness::BE => bits_len - msb - 1,
370        }
371    }
372
373    fn min(&self, reg_byte_len: usize, endianness: Endianness, sign: Sign) -> i64 {
374        let (lsb, msb) = (
375            self.lsb(reg_byte_len, endianness),
376            self.msb(reg_byte_len, endianness),
377        );
378        match sign {
379            Sign::Signed => {
380                if msb - lsb == 63 {
381                    i64::MIN
382                } else {
383                    let value = 1 << (msb - lsb) as i64;
384                    -value
385                }
386            }
387            Sign::Unsigned => 0,
388        }
389    }
390
391    fn max(&self, reg_byte_len: usize, endianness: Endianness, sign: Sign) -> i64 {
392        let (lsb, msb) = (
393            self.lsb(reg_byte_len, endianness),
394            self.msb(reg_byte_len, endianness),
395        );
396        if msb - lsb == 63 {
397            return i64::MAX;
398        }
399        match sign {
400            Sign::Signed => (1 << (msb - lsb)) - 1,
401            Sign::Unsigned => {
402                if msb - lsb == 63 {
403                    i64::MAX
404                } else {
405                    (1 << (msb - lsb + 1)) - 1
406                }
407            }
408        }
409    }
410
411    fn mask(&self, reg_byte_len: usize, endianness: Endianness) -> i64 {
412        let (lsb, msb) = (
413            self.lsb(reg_byte_len, endianness),
414            self.msb(reg_byte_len, endianness),
415        );
416        if msb - lsb == 63 {
417            -1
418        } else {
419            ((1 << (msb - lsb + 1)) - 1) << lsb
420        }
421    }
422}
423
424#[cfg(test)]
425mod tests {
426    use super::*;
427
428    #[test]
429    fn test_bit_mask_8bit_single_bit() {
430        let reg_len = 1;
431        let reg_value = 0b1100_1011;
432        let endianness = Endianness::LE;
433        let mask = BitMask::SingleBit(3);
434
435        let sign = Sign::Unsigned;
436        assert_eq!(mask.min(reg_len, endianness, sign), 0);
437        assert_eq!(mask.max(reg_len, endianness, sign), 1);
438        let value = mask.apply_mask(reg_value, reg_len, endianness, sign);
439        assert_eq!(value, 1);
440        let new_value = mask
441            .masked_value(reg_value, 0, reg_len, endianness, sign)
442            .unwrap();
443        assert_eq!(new_value, 0b1100_0011);
444
445        let sign = Sign::Signed;
446        assert_eq!(mask.min(reg_len, endianness, sign), -1);
447        assert_eq!(mask.max(reg_len, endianness, sign), 0);
448        let value = mask.apply_mask(reg_value, reg_len, endianness, sign);
449        assert_eq!(value, -1);
450        let new_value = mask
451            .masked_value(reg_value, 0, reg_len, endianness, sign)
452            .unwrap();
453        assert_eq!(new_value, 0b1100_0011);
454    }
455
456    #[test]
457    fn test_bit_mask_8bit_le() {
458        let reg_len = 1;
459        let reg_value = 0b1100_1011;
460        let endianness = Endianness::LE;
461        let mask = BitMask::Range { lsb: 1, msb: 4 };
462
463        let sign = Sign::Unsigned;
464        assert_eq!(mask.min(reg_len, endianness, sign), 0);
465        assert_eq!(mask.max(reg_len, endianness, sign), 15);
466        let value = mask.apply_mask(reg_value, reg_len, endianness, sign);
467        assert_eq!(value, 0b0101);
468        let new_value = mask
469            .masked_value(reg_value, 0b0110, reg_len, endianness, sign)
470            .unwrap();
471        assert_eq!(new_value, 0b1100_1101);
472
473        let sign = Sign::Signed;
474        let value = mask.apply_mask(reg_value, reg_len, endianness, sign);
475        assert_eq!(mask.min(reg_len, endianness, sign), -8);
476        assert_eq!(mask.max(reg_len, endianness, sign), 7);
477        assert_eq!(value, 5);
478        let new_value = mask
479            .masked_value(reg_value, -1, reg_len, endianness, sign)
480            .unwrap();
481        assert_eq!(new_value, 0b1101_1111);
482    }
483
484    #[test]
485    fn test_bit_mask_8bit_be() {
486        let reg_len = 1;
487        let reg_value = 0b1100_1011;
488        let endianness = Endianness::BE;
489        let mask = BitMask::Range { lsb: 6, msb: 3 };
490
491        let sign = Sign::Unsigned;
492        let value = mask.apply_mask(reg_value, reg_len, endianness, sign);
493        assert_eq!(value, 0b0101);
494        let new_value = mask
495            .masked_value(reg_value, 0b0110, reg_len, endianness, sign)
496            .unwrap();
497        assert_eq!(new_value, 0b1100_1101);
498
499        let sign = Sign::Signed;
500        let value = mask.apply_mask(reg_value, reg_len, endianness, sign);
501        assert_eq!(value, 5);
502        let new_value = mask
503            .masked_value(reg_value, -1, reg_len, endianness, sign)
504            .unwrap();
505        assert_eq!(new_value, 0b1101_1111);
506
507        let new_value = mask.masked_value(reg_value, 256, reg_len, endianness, sign);
508        assert!(new_value.is_err());
509    }
510
511    #[test]
512    fn test_bit_mask_64bit() {
513        let reg_len = 1;
514        let reg_value = i64::MAX;
515        let endianness = Endianness::LE;
516        let mask = BitMask::Range { lsb: 0, msb: 63 };
517
518        let sign = Sign::Unsigned;
519        assert_eq!(mask.min(reg_len, endianness, sign), 0);
520        assert_eq!(mask.max(reg_len, endianness, sign), i64::MAX);
521        let value = mask.apply_mask(reg_value, reg_len, endianness, sign);
522        assert_eq!(value, i64::MAX);
523        let new_value = mask
524            .masked_value(reg_value, 0, reg_len, endianness, sign)
525            .unwrap();
526        assert_eq!(new_value, 0);
527
528        let sign = Sign::Signed;
529        assert_eq!(mask.min(reg_len, endianness, sign), i64::MIN);
530        assert_eq!(mask.max(reg_len, endianness, sign), i64::MAX);
531        let value = mask.apply_mask(reg_value, reg_len, endianness, sign);
532        assert_eq!(value, i64::MAX);
533        let new_value = mask
534            .masked_value(reg_value, i64::MIN, reg_len, endianness, sign)
535            .unwrap();
536        assert_eq!(new_value, i64::MIN);
537    }
538}