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