Skip to main content

ab_riscv_primitives/instructions/rv64/a/
zaamo.rs

1//! RV64 Zaamo extension
2
3#[cfg(test)]
4mod tests;
5
6use crate::hart::HartConfig;
7use crate::instructions::{ImplementedExtension, Instruction, IsaExtension};
8use crate::registers::general_purpose::Register;
9use ab_riscv_macros::instruction;
10use core::fmt;
11
12/// RISC-V RV64 Zaamo instruction (Atomic memory operations)
13#[instruction]
14#[derive(Debug, Clone, Copy)]
15#[derive_const(PartialEq, Eq)]
16#[rustfmt::skip]
17pub enum Rv64ZaamoInstruction<Hart>
18where
19    Hart: HartConfig,
20{
21    Amoswap { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
22    Amoadd { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
23    Amoxor { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
24    Amoand { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
25    Amoor { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
26    Amomin { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
27    Amomax { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
28    Amominu { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
29    Amomaxu { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
30
31    AmoswapD { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
32    AmoaddD { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
33    AmoxorD { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
34    AmoandD { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
35    AmoorD { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
36    AmominD { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
37    AmomaxD { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
38    AmominuD { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
39    AmomaxuD { rd: Hart::Reg, rs1: Hart::Reg, rs2: Hart::Reg, aq: bool, rl: bool },
40}
41
42#[instruction]
43const impl<Reg, Hart> Instruction for Rv64ZaamoInstruction<Hart>
44where
45    Reg: [const] Register<Type = u64>,
46    Hart: [const] HartConfig<Reg = Reg>,
47{
48    const OWN_ISA_EXTENSIONS: &'static [IsaExtension] = &[IsaExtension::new("zaamo", 1, 0)];
49
50    const ALIGNMENT: u8 = align_of::<u32>() as u8;
51
52    type Hart = Hart;
53
54    #[inline(always)]
55    #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
56    fn try_decode(instruction: u32) -> Option<Self> {
57        let opcode = (instruction & 0b111_1111) as u8;
58        let rd_bits = ((instruction >> 7) & 0x1f) as u8;
59        let funct3 = ((instruction >> 12) & 0b111) as u8;
60        let rs1_bits = ((instruction >> 15) & 0x1f) as u8;
61        let rs2_bits = ((instruction >> 20) & 0x1f) as u8;
62        let funct7 = ((instruction >> 25) & 0b111_1111) as u8;
63
64        match (opcode, funct3) {
65            // AMO, word- or doubleword-sized (the only sizes that exist in RV64)
66            (0b010_1111, 0b010 | 0b011) => {
67                let rd = Reg::from_bits(rd_bits)?;
68                let rs1 = Reg::from_bits(rs1_bits)?;
69                let rs2 = Reg::from_bits(rs2_bits)?;
70                let funct5 = funct7 >> 2;
71                let aq = (funct7 & 0b10) != 0;
72                let rl = (funct7 & 0b01) != 0;
73
74                if funct3 == 0b010 {
75                    match funct5 {
76                        0b00001 => Some(Self::Amoswap {
77                            rd,
78                            rs1,
79                            rs2,
80                            aq,
81                            rl,
82                        }),
83                        0b00000 => Some(Self::Amoadd {
84                            rd,
85                            rs1,
86                            rs2,
87                            aq,
88                            rl,
89                        }),
90                        0b00100 => Some(Self::Amoxor {
91                            rd,
92                            rs1,
93                            rs2,
94                            aq,
95                            rl,
96                        }),
97                        0b01100 => Some(Self::Amoand {
98                            rd,
99                            rs1,
100                            rs2,
101                            aq,
102                            rl,
103                        }),
104                        0b01000 => Some(Self::Amoor {
105                            rd,
106                            rs1,
107                            rs2,
108                            aq,
109                            rl,
110                        }),
111                        0b10000 => Some(Self::Amomin {
112                            rd,
113                            rs1,
114                            rs2,
115                            aq,
116                            rl,
117                        }),
118                        0b10100 => Some(Self::Amomax {
119                            rd,
120                            rs1,
121                            rs2,
122                            aq,
123                            rl,
124                        }),
125                        0b11000 => Some(Self::Amominu {
126                            rd,
127                            rs1,
128                            rs2,
129                            aq,
130                            rl,
131                        }),
132                        0b11100 => Some(Self::Amomaxu {
133                            rd,
134                            rs1,
135                            rs2,
136                            aq,
137                            rl,
138                        }),
139                        _ => None,
140                    }
141                } else {
142                    match funct5 {
143                        0b00001 => Some(Self::AmoswapD {
144                            rd,
145                            rs1,
146                            rs2,
147                            aq,
148                            rl,
149                        }),
150                        0b00000 => Some(Self::AmoaddD {
151                            rd,
152                            rs1,
153                            rs2,
154                            aq,
155                            rl,
156                        }),
157                        0b00100 => Some(Self::AmoxorD {
158                            rd,
159                            rs1,
160                            rs2,
161                            aq,
162                            rl,
163                        }),
164                        0b01100 => Some(Self::AmoandD {
165                            rd,
166                            rs1,
167                            rs2,
168                            aq,
169                            rl,
170                        }),
171                        0b01000 => Some(Self::AmoorD {
172                            rd,
173                            rs1,
174                            rs2,
175                            aq,
176                            rl,
177                        }),
178                        0b10000 => Some(Self::AmominD {
179                            rd,
180                            rs1,
181                            rs2,
182                            aq,
183                            rl,
184                        }),
185                        0b10100 => Some(Self::AmomaxD {
186                            rd,
187                            rs1,
188                            rs2,
189                            aq,
190                            rl,
191                        }),
192                        0b11000 => Some(Self::AmominuD {
193                            rd,
194                            rs1,
195                            rs2,
196                            aq,
197                            rl,
198                        }),
199                        0b11100 => Some(Self::AmomaxuD {
200                            rd,
201                            rs1,
202                            rs2,
203                            aq,
204                            rl,
205                        }),
206                        _ => None,
207                    }
208                }
209            }
210            _ => None,
211        }
212    }
213
214    #[inline(always)]
215    fn size(&self) -> u8 {
216        size_of::<u32>() as u8
217    }
218}
219
220/// Format `aq`/`rl` suffix for display
221#[inline(always)]
222fn aq_rl_suffix(aq: &bool, rl: &bool) -> &'static str {
223    match (*aq, *rl) {
224        (false, false) => "",
225        (true, false) => ".aq",
226        (false, true) => ".rl",
227        (true, true) => ".aqrl",
228    }
229}
230
231#[instruction]
232impl<Reg, Hart> fmt::Display for Rv64ZaamoInstruction<Hart>
233where
234    Reg: fmt::Display,
235    Hart: HartConfig<Reg = Reg>,
236{
237    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
238        #[rustfmt::skip]
239        match self {
240            Self::Amoswap { rd, rs1, rs2, aq, rl } => write!(f, "amoswap.w{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
241            Self::Amoadd { rd, rs1, rs2, aq, rl } => write!(f, "amoadd.w{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
242            Self::Amoxor { rd, rs1, rs2, aq, rl } => write!(f, "amoxor.w{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
243            Self::Amoand { rd, rs1, rs2, aq, rl } => write!(f, "amoand.w{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
244            Self::Amoor { rd, rs1, rs2, aq, rl } => write!(f, "amoor.w{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
245            Self::Amomin { rd, rs1, rs2, aq, rl } => write!(f, "amomin.w{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
246            Self::Amomax { rd, rs1, rs2, aq, rl } => write!(f, "amomax.w{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
247            Self::Amominu { rd, rs1, rs2, aq, rl } => write!(f, "amominu.w{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
248            Self::Amomaxu { rd, rs1, rs2, aq, rl } => write!(f, "amomaxu.w{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
249
250            Self::AmoswapD { rd, rs1, rs2, aq, rl } => write!(f, "amoswap.d{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
251            Self::AmoaddD { rd, rs1, rs2, aq, rl } => write!(f, "amoadd.d{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
252            Self::AmoxorD { rd, rs1, rs2, aq, rl } => write!(f, "amoxor.d{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
253            Self::AmoandD { rd, rs1, rs2, aq, rl } => write!(f, "amoand.d{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
254            Self::AmoorD { rd, rs1, rs2, aq, rl } => write!(f, "amoor.d{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
255            Self::AmominD { rd, rs1, rs2, aq, rl } => write!(f, "amomin.d{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
256            Self::AmomaxD { rd, rs1, rs2, aq, rl } => write!(f, "amomax.d{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
257            Self::AmominuD { rd, rs1, rs2, aq, rl } => write!(f, "amominu.d{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
258            Self::AmomaxuD { rd, rs1, rs2, aq, rl } => write!(f, "amomaxu.d{} {rd}, {rs2}, ({rs1})", aq_rl_suffix(aq, rl)),
259        }
260    }
261}