ab_riscv_primitives/instructions/rv64/zce/
zcb.rs1#[cfg(test)]
4mod tests;
5
6use crate::instructions::Instruction;
7use crate::instructions::rv64::c::zca::Rv64ZcaInstruction;
8use crate::instructions::utils::I24;
9use crate::registers::general_purpose::Register;
10use ab_riscv_macros::instruction;
11use core::fmt;
12
13#[instruction(
17 inherit = [Rv64ZcaInstruction, Rv64ZcbOnlyInstruction],
18)]
19#[derive(Debug, Clone, Copy)]
20#[derive_const(PartialEq, Eq)]
21pub enum Rv64ZcbInstruction<Reg> {}
22
23#[instruction]
24const impl<Reg> Instruction for Rv64ZcbInstruction<Reg>
25where
26 Reg: [const] Register<Type = u64>,
27{
28 type Reg = Reg;
29
30 #[inline(always)]
31 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
32 fn try_decode(instruction: u32) -> Option<Self> {
33 None
34 }
35
36 #[inline(always)]
37 fn alignment() -> u8 {
38 align_of::<u16>() as u8
39 }
40
41 #[inline(always)]
42 fn size(&self) -> u8 {
43 size_of::<u16>() as u8
44 }
45}
46
47#[instruction]
48impl<Reg> fmt::Display for Rv64ZcbInstruction<Reg>
49where
50 Reg: fmt::Display + Copy,
51{
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 match self {}
54 }
55}
56
57#[instruction]
59#[derive(Debug, Clone, Copy)]
60#[derive_const(PartialEq, Eq)]
61#[rustfmt::skip]
62#[doc(hidden)]
63pub enum Rv64ZcbOnlyInstruction<Reg> {
64 CLbu { rd: Reg, rs1: Reg, uimm: u8 },
67 CLh { rd: Reg, rs1: Reg, uimm: u8 },
69 CLhu { rd: Reg, rs1: Reg, uimm: u8 },
71 CSb { rs1: Reg, rs2: Reg, uimm: u8 },
73 CSh { rs1: Reg, rs2: Reg, uimm: u8 },
75
76 CZextB { rd: Reg },
79 #[instruction(if = [Rv64ZbbInstruction])]
81 CSextB { rd: Reg },
82 #[instruction(if = [Rv64ZbbInstruction])]
84 CZextH { rd: Reg },
85 #[instruction(if = [Rv64ZbbInstruction])]
87 CSextH { rd: Reg },
88 #[instruction(if = [Rv64ZbaInstruction])]
90 CZextW { rd: Reg },
91 CNot { rd: Reg },
93
94 #[instruction(
97 if = [Rv64MInstruction],
98 if = [Rv64ZmmulInstruction]
99 )]
100 CMul { rd: Reg, rs2: Reg },
101}
102
103#[instruction]
104const impl<Reg> Instruction for Rv64ZcbOnlyInstruction<Reg>
105where
106 Reg: [const] Register<Type = u64>,
107{
108 type Reg = Reg;
109
110 #[inline(always)]
111 #[cfg_attr(feature = "no-panic", no_panic_const::no_panic(const))]
112 fn try_decode(instruction: u32) -> Option<Self> {
113 #[inline(always)]
115 const fn prime_reg_bits(bits: u8) -> u8 {
116 bits + 8
117 }
118
119 let inst = instruction as u16;
120 let quadrant = inst & 0b11;
121 let funct3 = ((inst >> 13) & 0b111) as u8;
122
123 match quadrant {
124 0b00 if funct3 == 0b100 => {
126 let sub = ((inst >> 10) & 0b111) as u8;
127 let rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
128 let rd_rs2_bits = prime_reg_bits(((inst >> 2) & 0b111) as u8);
129
130 match sub {
131 0b000 => {
133 let uimm = ((((inst >> 5) & 1) << 1) | ((inst >> 6) & 1)) as u8;
134 let rs1 = Reg::from_bits(rs1_bits)?;
135 let rd = Reg::from_bits(rd_rs2_bits)?;
136 Some(Self::CLbu { rd, rs1, uimm })
137 }
138 0b001 => {
141 let funct1 = ((inst >> 6) & 1) as u8;
142 let uimm = (((inst >> 5) & 1) as u8) << 1;
143 let rs1 = Reg::from_bits(rs1_bits)?;
144 let rd = Reg::from_bits(rd_rs2_bits)?;
145 if funct1 == 0 {
146 Some(Self::CLhu { rd, rs1, uimm })
147 } else {
148 Some(Self::CLh { rd, rs1, uimm })
149 }
150 }
151 0b010 => {
153 let uimm = ((((inst >> 5) & 1) << 1) | ((inst >> 6) & 1)) as u8;
154 let rs1 = Reg::from_bits(rs1_bits)?;
155 let rs2 = Reg::from_bits(rd_rs2_bits)?;
156 Some(Self::CSb { rs1, rs2, uimm })
157 }
158 0b011 => {
160 if ((inst >> 6) & 1) != 0 {
161 None?;
162 }
163 let uimm = (((inst >> 5) & 1) as u8) << 1;
164 let rs1 = Reg::from_bits(rs1_bits)?;
165 let rs2 = Reg::from_bits(rd_rs2_bits)?;
166 Some(Self::CSh { rs1, rs2, uimm })
167 }
168 _ => None,
169 }
170 }
171
172 0b01 if funct3 == 0b100 => {
180 let funct2_11_10 = ((inst >> 10) & 0b11) as u8;
181 let bit12 = (inst >> 12) & 1;
182
183 if funct2_11_10 != 0b11 || bit12 == 0 {
184 None?;
185 }
186
187 let rd_rs1_bits = prime_reg_bits(((inst >> 7) & 0b111) as u8);
188 let funct2b = ((inst >> 5) & 0b11) as u8;
189 let rs2_sub = ((inst >> 2) & 0b111) as u8;
190
191 match funct2b {
192 0b11 => {
194 let rd = Reg::from_bits(rd_rs1_bits)?;
195 match rs2_sub {
196 0b000 => Some(Self::CZextB { rd }),
197 0b001 => Some(Self::CSextB { rd }),
198 0b010 => Some(Self::CZextH { rd }),
199 0b011 => Some(Self::CSextH { rd }),
200 0b100 => Some(Self::CZextW { rd }),
201 0b101 => Some(Self::CNot { rd }),
202 _ => None,
204 }
205 }
206 0b10 => {
208 let rd = Reg::from_bits(rd_rs1_bits)?;
209 let rs2 = Reg::from_bits(prime_reg_bits(rs2_sub))?;
210 Some(Self::CMul { rd, rs2 })
211 }
212 _ => None,
214 }
215 }
216
217 _ => None,
218 }
219 }
220
221 #[inline(always)]
222 fn alignment() -> u8 {
223 align_of::<u16>() as u8
224 }
225
226 #[inline(always)]
227 fn size(&self) -> u8 {
228 size_of::<u16>() as u8
229 }
230}
231
232#[instruction]
233impl<Reg> fmt::Display for Rv64ZcbOnlyInstruction<Reg>
234where
235 Reg: fmt::Display + Copy,
236{
237 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
238 match self {
239 Self::CLbu { rd, rs1, uimm } => write!(f, "c.lbu {rd}, {uimm}({rs1})"),
240 Self::CLh { rd, rs1, uimm } => write!(f, "c.lh {rd}, {uimm}({rs1})"),
241 Self::CLhu { rd, rs1, uimm } => write!(f, "c.lhu {rd}, {uimm}({rs1})"),
242 Self::CSb { rs1, rs2, uimm } => write!(f, "c.sb {rs2}, {uimm}({rs1})"),
243 Self::CSh { rs1, rs2, uimm } => write!(f, "c.sh {rs2}, {uimm}({rs1})"),
244 Self::CZextB { rd } => write!(f, "c.zext.b {rd}"),
245 Self::CSextB { rd } => write!(f, "c.sext.b {rd}"),
246 Self::CZextH { rd } => write!(f, "c.zext.h {rd}"),
247 Self::CSextH { rd } => write!(f, "c.sext.h {rd}"),
248 Self::CZextW { rd } => write!(f, "c.zext.w {rd}"),
249 Self::CNot { rd } => write!(f, "c.not {rd}"),
250 Self::CMul { rd, rs2 } => write!(f, "c.mul {rd}, {rs2}"),
251 }
252 }
253}