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