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