ab_riscv_primitives/instruction/
tuples.rs

1//! Composition tuples for instructions
2
3use crate::instruction::{BaseInstruction, Instruction};
4use core::fmt;
5
6/// Tuple instruction that allows composing a base instruction type with an extension.
7///
8/// NOTE: All instructions in a tuple must use the same associated register type or else the
9/// compiler will produce a lot of very confusing errors.
10#[derive(Debug, Copy, Clone)]
11pub enum Tuple2Instruction<A, Base>
12where
13    A: Instruction<Base = Base>,
14    Base: BaseInstruction,
15{
16    A(A),
17    Base(Base),
18}
19
20impl<A, Base> fmt::Display for Tuple2Instruction<A, Base>
21where
22    A: Instruction<Base = Base>,
23    Base: BaseInstruction,
24{
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        match self {
27            Tuple2Instruction::A(a) => fmt::Display::fmt(a, f),
28            Tuple2Instruction::Base(b) => fmt::Display::fmt(b, f),
29        }
30    }
31}
32
33impl<A, Base> const Instruction for Tuple2Instruction<A, Base>
34where
35    A: [const] Instruction<Base = Base>,
36    Base: [const] BaseInstruction,
37{
38    type Base = Base;
39
40    #[inline(always)]
41    fn try_decode(instruction: u32) -> Option<Self> {
42        if let Some(instruction) = A::try_decode(instruction) {
43            Some(Self::A(instruction))
44        } else {
45            Some(Self::Base(Base::try_decode(instruction)?))
46        }
47    }
48
49    #[inline(always)]
50    fn size(&self) -> u8 {
51        match self {
52            Tuple2Instruction::A(a) => a.size(),
53            Tuple2Instruction::Base(b) => b.size(),
54        }
55    }
56}
57
58impl<A, Base> const BaseInstruction for Tuple2Instruction<A, Base>
59where
60    A: [const] Instruction<Base = Base>,
61    Base: [const] BaseInstruction,
62{
63    type Reg = Base::Reg;
64
65    #[inline(always)]
66    fn from_base(base: Base) -> Self {
67        Self::Base(base)
68    }
69
70    #[inline]
71    fn decode(instruction: u32) -> Self {
72        if let Some(instruction) = A::try_decode(instruction) {
73            Self::A(instruction)
74        } else {
75            Self::Base(Base::decode(instruction))
76        }
77    }
78}
79
80/// Tuple instruction that allows composing a base instruction type with two extensions.
81///
82/// NOTE: All instructions in a tuple must use the same associated register type or else the
83/// compiler will produce a lot of very confusing errors.
84#[derive(Debug, Copy, Clone)]
85pub enum Tuple3Instruction<A, B, Base>
86where
87    A: Instruction<Base = Base>,
88    B: Instruction<Base = Base>,
89    Base: BaseInstruction,
90{
91    A(A),
92    B(B),
93    Base(Base),
94}
95
96impl<A, B, Base> fmt::Display for Tuple3Instruction<A, B, Base>
97where
98    A: Instruction<Base = Base>,
99    B: Instruction<Base = Base>,
100    Base: BaseInstruction,
101{
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        match self {
104            Tuple3Instruction::A(a) => fmt::Display::fmt(a, f),
105            Tuple3Instruction::B(b) => fmt::Display::fmt(b, f),
106            Tuple3Instruction::Base(b) => fmt::Display::fmt(b, f),
107        }
108    }
109}
110
111impl<A, B, Base> const Instruction for Tuple3Instruction<A, B, Base>
112where
113    A: [const] Instruction<Base = Base>,
114    B: [const] Instruction<Base = Base>,
115    Base: [const] BaseInstruction,
116{
117    type Base = Base;
118
119    #[inline(always)]
120    fn try_decode(instruction: u32) -> Option<Self> {
121        if let Some(instruction) = A::try_decode(instruction) {
122            Some(Self::A(instruction))
123        } else if let Some(instruction) = B::try_decode(instruction) {
124            Some(Self::B(instruction))
125        } else {
126            Some(Self::Base(Base::try_decode(instruction)?))
127        }
128    }
129
130    #[inline(always)]
131    fn size(&self) -> u8 {
132        match self {
133            Tuple3Instruction::A(a) => a.size(),
134            Tuple3Instruction::B(b) => b.size(),
135            Tuple3Instruction::Base(b) => b.size(),
136        }
137    }
138}
139
140impl<A, B, Base> const BaseInstruction for Tuple3Instruction<A, B, Base>
141where
142    A: [const] Instruction<Base = Base>,
143    B: [const] Instruction<Base = Base>,
144    Base: [const] BaseInstruction,
145{
146    type Reg = Base::Reg;
147
148    #[inline(always)]
149    fn from_base(base: Base) -> Self {
150        Self::Base(base)
151    }
152
153    #[inline]
154    fn decode(instruction: u32) -> Self {
155        if let Some(instruction) = A::try_decode(instruction) {
156            Self::A(instruction)
157        } else if let Some(instruction) = B::try_decode(instruction) {
158            Self::B(instruction)
159        } else {
160            Self::Base(Base::decode(instruction))
161        }
162    }
163}