Skip to main content

ab_riscv_primitives/instructions/rv32/
zabha.rs

1//! RV32 Zabha extension
2
3#[cfg(test)]
4mod tests;
5
6use crate::instructions::Instruction;
7use crate::instructions::rv32::a::zaamo::Rv32ZaamoInstruction;
8use crate::registers::general_purpose::Register;
9use ab_riscv_macros::instruction;
10use core::fmt;
11
12/// RISC-V RV32 Zabha instruction (Byte and Halfword Atomic Memory Operations)
13#[instruction(inherit = [Rv32ZaamoInstruction])]
14#[derive(Debug, Clone, Copy)]
15#[derive_const(PartialEq, Eq)]
16#[rustfmt::skip]
17pub enum Rv32ZabhaInstruction<Reg> {
18    AmoswapB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
19    AmoswapH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
20    AmoaddB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
21    AmoaddH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
22    AmoxorB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
23    AmoxorH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
24    AmoandB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
25    AmoandH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
26    AmoorB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
27    AmoorH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
28    AmominB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
29    AmominH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
30    AmomaxB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
31    AmomaxH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
32    AmominuB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
33    AmominuH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
34    AmomaxuB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
35    AmomaxuH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
36    /// Compare-and-swap byte. Only present when `Zacas` is also implemented.
37    #[instruction(if = [Rv32ZacasInstruction])]
38    AmocasB { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
39    /// Compare-and-swap halfword. Only present when `Zacas` is also implemented.
40    #[instruction(if = [Rv32ZacasInstruction])]
41    AmocasH { rd: Reg, rs1: Reg, rs2: Reg, aq: bool, rl: bool },
42}
43
44#[instruction]
45const impl<Reg> Instruction for Rv32ZabhaInstruction<Reg>
46where
47    Reg: [const] Register<Type = u32>,
48{
49    type Reg = Reg;
50
51    #[inline(always)]
52    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
53    fn try_decode(instruction: u32) -> Option<Self> {
54        let opcode = (instruction & 0b111_1111) as u8;
55        let rd_bits = ((instruction >> 7) & 0x1f) as u8;
56        let funct3 = ((instruction >> 12) & 0b111) as u8;
57        let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
58        let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
59        let funct7 = ((instruction >> 25) & 0b111_1111) as u8;
60
61        match (opcode, funct3) {
62            // AMO, byte- or halfword-sized
63            (0b010_1111, 0b000 | 0b001) => {
64                let rd = Reg::from_bits(rd_bits)?;
65                let rs1 = Reg::from_bits(rs1_bits)?;
66                let rs2 = Reg::from_bits(rs2_bits)?;
67                let funct5 = funct7 >> 2;
68                let aq = (funct7 & 0b10) != 0;
69                let rl = (funct7 & 0b01) != 0;
70
71                if funct3 == 0b000 {
72                    match funct5 {
73                        0b00001 => Some(Self::AmoswapB {
74                            rd,
75                            rs1,
76                            rs2,
77                            aq,
78                            rl,
79                        }),
80                        0b00000 => Some(Self::AmoaddB {
81                            rd,
82                            rs1,
83                            rs2,
84                            aq,
85                            rl,
86                        }),
87                        0b00100 => Some(Self::AmoxorB {
88                            rd,
89                            rs1,
90                            rs2,
91                            aq,
92                            rl,
93                        }),
94                        0b01100 => Some(Self::AmoandB {
95                            rd,
96                            rs1,
97                            rs2,
98                            aq,
99                            rl,
100                        }),
101                        0b01000 => Some(Self::AmoorB {
102                            rd,
103                            rs1,
104                            rs2,
105                            aq,
106                            rl,
107                        }),
108                        0b10000 => Some(Self::AmominB {
109                            rd,
110                            rs1,
111                            rs2,
112                            aq,
113                            rl,
114                        }),
115                        0b10100 => Some(Self::AmomaxB {
116                            rd,
117                            rs1,
118                            rs2,
119                            aq,
120                            rl,
121                        }),
122                        0b11000 => Some(Self::AmominuB {
123                            rd,
124                            rs1,
125                            rs2,
126                            aq,
127                            rl,
128                        }),
129                        0b11100 => Some(Self::AmomaxuB {
130                            rd,
131                            rs1,
132                            rs2,
133                            aq,
134                            rl,
135                        }),
136                        0b00101 => Some(Self::AmocasB {
137                            rd,
138                            rs1,
139                            rs2,
140                            aq,
141                            rl,
142                        }),
143                        _ => None,
144                    }
145                } else {
146                    match funct5 {
147                        0b00001 => Some(Self::AmoswapH {
148                            rd,
149                            rs1,
150                            rs2,
151                            aq,
152                            rl,
153                        }),
154                        0b00000 => Some(Self::AmoaddH {
155                            rd,
156                            rs1,
157                            rs2,
158                            aq,
159                            rl,
160                        }),
161                        0b00100 => Some(Self::AmoxorH {
162                            rd,
163                            rs1,
164                            rs2,
165                            aq,
166                            rl,
167                        }),
168                        0b01100 => Some(Self::AmoandH {
169                            rd,
170                            rs1,
171                            rs2,
172                            aq,
173                            rl,
174                        }),
175                        0b01000 => Some(Self::AmoorH {
176                            rd,
177                            rs1,
178                            rs2,
179                            aq,
180                            rl,
181                        }),
182                        0b10000 => Some(Self::AmominH {
183                            rd,
184                            rs1,
185                            rs2,
186                            aq,
187                            rl,
188                        }),
189                        0b10100 => Some(Self::AmomaxH {
190                            rd,
191                            rs1,
192                            rs2,
193                            aq,
194                            rl,
195                        }),
196                        0b11000 => Some(Self::AmominuH {
197                            rd,
198                            rs1,
199                            rs2,
200                            aq,
201                            rl,
202                        }),
203                        0b11100 => Some(Self::AmomaxuH {
204                            rd,
205                            rs1,
206                            rs2,
207                            aq,
208                            rl,
209                        }),
210                        0b00101 => Some(Self::AmocasH {
211                            rd,
212                            rs1,
213                            rs2,
214                            aq,
215                            rl,
216                        }),
217                        _ => None,
218                    }
219                }
220            }
221            _ => None,
222        }
223    }
224
225    #[inline(always)]
226    fn alignment() -> u8 {
227        align_of::<u32>() as u8
228    }
229
230    #[inline(always)]
231    fn size(&self) -> u8 {
232        size_of::<u32>() as u8
233    }
234}
235
236/// Format `aq`/`rl` suffix for display
237#[inline(always)]
238fn aq_rl_suffix(aq: &bool, rl: &bool) -> &'static str {
239    match (*aq, *rl) {
240        (false, false) => "",
241        (true, false) => ".aq",
242        (false, true) => ".rl",
243        (true, true) => ".aqrl",
244    }
245}
246
247#[instruction]
248impl<Reg> fmt::Display for Rv32ZabhaInstruction<Reg>
249where
250    Reg: fmt::Display + Copy,
251{
252    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253        #[rustfmt::skip]
254        match self {
255            Self::AmoswapB { rd, rs1, rs2, aq, rl } => write!(f, "amoswap.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
256            Self::AmoswapH { rd, rs1, rs2, aq, rl } => write!(f, "amoswap.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
257            Self::AmoaddB { rd, rs1, rs2, aq, rl } => write!(f, "amoadd.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
258            Self::AmoaddH { rd, rs1, rs2, aq, rl } => write!(f, "amoadd.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
259            Self::AmoxorB { rd, rs1, rs2, aq, rl } => write!(f, "amoxor.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
260            Self::AmoxorH { rd, rs1, rs2, aq, rl } => write!(f, "amoxor.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
261            Self::AmoandB { rd, rs1, rs2, aq, rl } => write!(f, "amoand.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
262            Self::AmoandH { rd, rs1, rs2, aq, rl } => write!(f, "amoand.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
263            Self::AmoorB { rd, rs1, rs2, aq, rl } => write!(f, "amoor.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
264            Self::AmoorH { rd, rs1, rs2, aq, rl } => write!(f, "amoor.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
265            Self::AmominB { rd, rs1, rs2, aq, rl } => write!(f, "amomin.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
266            Self::AmominH { rd, rs1, rs2, aq, rl } => write!(f, "amomin.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
267            Self::AmomaxB { rd, rs1, rs2, aq, rl } => write!(f, "amomax.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
268            Self::AmomaxH { rd, rs1, rs2, aq, rl } => write!(f, "amomax.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
269            Self::AmominuB { rd, rs1, rs2, aq, rl } => write!(f, "amominu.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
270            Self::AmominuH { rd, rs1, rs2, aq, rl } => write!(f, "amominu.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
271            Self::AmomaxuB { rd, rs1, rs2, aq, rl } => write!(f, "amomaxu.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
272            Self::AmomaxuH { rd, rs1, rs2, aq, rl } => write!(f, "amomaxu.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
273            Self::AmocasB { rd, rs1, rs2, aq, rl } => write!(f, "amocas.b{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
274            Self::AmocasH { rd, rs1, rs2, aq, rl } => write!(f, "amocas.h{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
275        }
276    }
277}