Skip to main content

ab_riscv_primitives/instructions/rv32/
zabha.rs

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