1 //! Riscv64 ISA definitions: instruction arguments. 2 3 use super::*; 4 use crate::ir::condcodes::CondCode; 5 6 use crate::isa::riscv64::lower::isle::generated_code::{ 7 COpcodeSpace, CaOp, CbOp, CiOp, CiwOp, ClOp, CrOp, CsOp, CssOp, CsznOp, FpuOPWidth, ZcbMemOp, 8 }; 9 use crate::machinst::isle::WritableReg; 10 11 use core::fmt::Result; 12 13 /// A macro for defining a newtype of `Reg` that enforces some invariant about 14 /// the wrapped `Reg` (such as that it is of a particular register class). 15 macro_rules! newtype_of_reg { 16 ( 17 $newtype_reg:ident, 18 $newtype_writable_reg:ident, 19 |$check_reg:ident| $check:expr 20 ) => { 21 /// A newtype wrapper around `Reg`. 22 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 23 pub struct $newtype_reg(Reg); 24 25 impl PartialEq<Reg> for $newtype_reg { 26 fn eq(&self, other: &Reg) -> bool { 27 self.0 == *other 28 } 29 } 30 31 impl From<$newtype_reg> for Reg { 32 fn from(r: $newtype_reg) -> Self { 33 r.0 34 } 35 } 36 37 impl $newtype_reg { 38 /// Create this newtype from the given register, or return `None` if the register 39 /// is not a valid instance of this newtype. 40 pub fn new($check_reg: Reg) -> Option<Self> { 41 if $check { Some(Self($check_reg)) } else { None } 42 } 43 44 /// Get this newtype's underlying `Reg`. 45 pub fn to_reg(self) -> Reg { 46 self.0 47 } 48 } 49 50 // Convenience impl so that people working with this newtype can use it 51 // "just like" a plain `Reg`. 52 // 53 // NB: We cannot implement `DerefMut` because that would let people do 54 // nasty stuff like `*my_xreg.deref_mut() = some_freg`, breaking the 55 // invariants that `XReg` provides. 56 impl core::ops::Deref for $newtype_reg { 57 type Target = Reg; 58 59 fn deref(&self) -> &Reg { 60 &self.0 61 } 62 } 63 64 /// Writable Reg. 65 pub type $newtype_writable_reg = Writable<$newtype_reg>; 66 }; 67 } 68 69 // Newtypes for registers classes. 70 newtype_of_reg!(XReg, WritableXReg, |reg| reg.class() == RegClass::Int); 71 newtype_of_reg!(FReg, WritableFReg, |reg| reg.class() == RegClass::Float); 72 newtype_of_reg!(VReg, WritableVReg, |reg| reg.class() == RegClass::Vector); 73 74 /// An addressing mode specified for a load/store operation. 75 #[derive(Clone, Debug, Copy)] 76 pub enum AMode { 77 /// Arbitrary offset from a register. Converted to generation of large 78 /// offsets with multiple instructions as necessary during code emission. 79 RegOffset(Reg, i64), 80 /// Offset from the stack pointer. 81 SPOffset(i64), 82 83 /// Offset from the frame pointer. 84 FPOffset(i64), 85 86 /// Offset into the slot area of the stack, which lies just above the 87 /// outgoing argument area that's setup by the function prologue. 88 /// At emission time, this is converted to `SPOffset` with a fixup added to 89 /// the offset constant. The fixup is a running value that is tracked as 90 /// emission iterates through instructions in linear order, and can be 91 /// adjusted up and down with [Inst::VirtualSPOffsetAdj]. 92 /// 93 /// The standard ABI is in charge of handling this (by emitting the 94 /// adjustment meta-instructions). See the diagram in the documentation 95 /// for [crate::isa::aarch64::abi](the ABI module) for more details. 96 SlotOffset(i64), 97 98 /// Offset into the argument area. 99 IncomingArg(i64), 100 101 /// A reference to a constant which is placed outside of the function's 102 /// body, typically at the end. 103 Const(VCodeConstant), 104 105 /// A reference to a label. 106 Label(MachLabel), 107 } 108 109 impl AMode { 110 /// Add the registers referenced by this AMode to `collector`. get_operands(&mut self, collector: &mut impl OperandVisitor)111 pub(crate) fn get_operands(&mut self, collector: &mut impl OperandVisitor) { 112 match self { 113 AMode::RegOffset(reg, ..) => collector.reg_use(reg), 114 // Registers used in these modes aren't allocatable. 115 AMode::SPOffset(..) 116 | AMode::FPOffset(..) 117 | AMode::SlotOffset(..) 118 | AMode::IncomingArg(..) 119 | AMode::Const(..) 120 | AMode::Label(..) => {} 121 } 122 } 123 get_base_register(&self) -> Option<Reg>124 pub(crate) fn get_base_register(&self) -> Option<Reg> { 125 match self { 126 &AMode::RegOffset(reg, ..) => Some(reg), 127 &AMode::SPOffset(..) => Some(stack_reg()), 128 &AMode::FPOffset(..) => Some(fp_reg()), 129 &AMode::SlotOffset(..) => Some(stack_reg()), 130 &AMode::IncomingArg(..) => Some(stack_reg()), 131 &AMode::Const(..) | AMode::Label(..) => None, 132 } 133 } 134 get_offset_with_state(&self, state: &EmitState) -> i64135 pub(crate) fn get_offset_with_state(&self, state: &EmitState) -> i64 { 136 match self { 137 &AMode::SlotOffset(offset) => { 138 offset + i64::from(state.frame_layout().outgoing_args_size) 139 } 140 141 // Compute the offset into the incoming argument area relative to SP 142 &AMode::IncomingArg(offset) => { 143 let frame_layout = state.frame_layout(); 144 let sp_offset = frame_layout.tail_args_size 145 + frame_layout.setup_area_size 146 + frame_layout.clobber_size 147 + frame_layout.fixed_frame_storage_size 148 + frame_layout.outgoing_args_size; 149 i64::from(sp_offset) - offset 150 } 151 152 &AMode::RegOffset(_, offset) => offset, 153 &AMode::SPOffset(offset) => offset, 154 &AMode::FPOffset(offset) => offset, 155 &AMode::Const(_) | &AMode::Label(_) => 0, 156 } 157 } 158 159 /// Retrieve a MachLabel that corresponds to this addressing mode, if it exists. get_label_with_sink(&self, sink: &mut MachBuffer<Inst>) -> Option<MachLabel>160 pub(crate) fn get_label_with_sink(&self, sink: &mut MachBuffer<Inst>) -> Option<MachLabel> { 161 match self { 162 &AMode::Const(addr) => Some(sink.get_label_for_constant(addr)), 163 &AMode::Label(label) => Some(label), 164 &AMode::RegOffset(..) 165 | &AMode::SPOffset(..) 166 | &AMode::FPOffset(..) 167 | &AMode::IncomingArg(..) 168 | &AMode::SlotOffset(..) => None, 169 } 170 } 171 } 172 173 impl Display for AMode { fmt(&self, f: &mut Formatter<'_>) -> Result174 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 175 match self { 176 &AMode::RegOffset(r, offset, ..) => { 177 write!(f, "{}({})", offset, reg_name(r)) 178 } 179 &AMode::SPOffset(offset, ..) => { 180 write!(f, "{offset}(sp)") 181 } 182 &AMode::SlotOffset(offset, ..) => { 183 write!(f, "{offset}(slot)") 184 } 185 &AMode::IncomingArg(offset) => { 186 write!(f, "-{offset}(incoming_arg)") 187 } 188 &AMode::FPOffset(offset, ..) => { 189 write!(f, "{offset}(fp)") 190 } 191 &AMode::Const(addr, ..) => { 192 write!(f, "[const({})]", addr.as_u32()) 193 } 194 &AMode::Label(label) => { 195 write!(f, "[label{}]", label.as_u32()) 196 } 197 } 198 } 199 } 200 201 impl From<StackAMode> for AMode { from(stack: StackAMode) -> AMode202 fn from(stack: StackAMode) -> AMode { 203 match stack { 204 StackAMode::IncomingArg(offset, stack_args_size) => { 205 AMode::IncomingArg(i64::from(stack_args_size) - offset) 206 } 207 StackAMode::OutgoingArg(offset) => AMode::SPOffset(offset), 208 StackAMode::Slot(offset) => AMode::SlotOffset(offset), 209 } 210 } 211 } 212 213 /// risc-v always take two register to compare 214 #[derive(Clone, Copy, Debug)] 215 pub struct IntegerCompare { 216 pub(crate) kind: IntCC, 217 pub(crate) rs1: Reg, 218 pub(crate) rs2: Reg, 219 } 220 221 pub(crate) enum BranchFunct3 { 222 // == 223 Eq, 224 // != 225 Ne, 226 // signed < 227 Lt, 228 // signed >= 229 Ge, 230 // unsigned < 231 Ltu, 232 // unsigned >= 233 Geu, 234 } 235 236 impl BranchFunct3 { funct3(self) -> u32237 pub(crate) fn funct3(self) -> u32 { 238 match self { 239 BranchFunct3::Eq => 0b000, 240 BranchFunct3::Ne => 0b001, 241 BranchFunct3::Lt => 0b100, 242 BranchFunct3::Ge => 0b101, 243 BranchFunct3::Ltu => 0b110, 244 BranchFunct3::Geu => 0b111, 245 } 246 } 247 } 248 249 impl IntegerCompare { op_code(self) -> u32250 pub(crate) fn op_code(self) -> u32 { 251 0b1100011 252 } 253 254 // funct3 and if need inverse the register funct3(&self) -> (BranchFunct3, bool)255 pub(crate) fn funct3(&self) -> (BranchFunct3, bool) { 256 match self.kind { 257 IntCC::Equal => (BranchFunct3::Eq, false), 258 IntCC::NotEqual => (BranchFunct3::Ne, false), 259 IntCC::SignedLessThan => (BranchFunct3::Lt, false), 260 IntCC::SignedGreaterThanOrEqual => (BranchFunct3::Ge, false), 261 262 IntCC::SignedGreaterThan => (BranchFunct3::Lt, true), 263 IntCC::SignedLessThanOrEqual => (BranchFunct3::Ge, true), 264 265 IntCC::UnsignedLessThan => (BranchFunct3::Ltu, false), 266 IntCC::UnsignedGreaterThanOrEqual => (BranchFunct3::Geu, false), 267 268 IntCC::UnsignedGreaterThan => (BranchFunct3::Ltu, true), 269 IntCC::UnsignedLessThanOrEqual => (BranchFunct3::Geu, true), 270 } 271 } 272 273 #[inline] op_name(&self) -> &'static str274 pub(crate) fn op_name(&self) -> &'static str { 275 match self.kind { 276 IntCC::Equal => "beq", 277 IntCC::NotEqual => "bne", 278 IntCC::SignedLessThan => "blt", 279 IntCC::SignedGreaterThanOrEqual => "bge", 280 IntCC::SignedGreaterThan => "bgt", 281 IntCC::SignedLessThanOrEqual => "ble", 282 IntCC::UnsignedLessThan => "bltu", 283 IntCC::UnsignedGreaterThanOrEqual => "bgeu", 284 IntCC::UnsignedGreaterThan => "bgtu", 285 IntCC::UnsignedLessThanOrEqual => "bleu", 286 } 287 } 288 emit(self) -> u32289 pub(crate) fn emit(self) -> u32 { 290 let (funct3, reverse) = self.funct3(); 291 let (rs1, rs2) = if reverse { 292 (self.rs2, self.rs1) 293 } else { 294 (self.rs1, self.rs2) 295 }; 296 297 self.op_code() 298 | funct3.funct3() << 12 299 | reg_to_gpr_num(rs1) << 15 300 | reg_to_gpr_num(rs2) << 20 301 } 302 inverse(self) -> Self303 pub(crate) fn inverse(self) -> Self { 304 Self { 305 kind: self.kind.complement(), 306 ..self 307 } 308 } 309 regs(&self) -> [Reg; 2]310 pub(crate) fn regs(&self) -> [Reg; 2] { 311 [self.rs1, self.rs2] 312 } 313 } 314 315 #[derive(Debug, Clone, Copy, PartialEq)] 316 pub struct FliConstant(u8); 317 318 impl FliConstant { new(value: u8) -> Self319 pub(crate) fn new(value: u8) -> Self { 320 debug_assert!(value <= 31, "Invalid FliConstant: {value}"); 321 Self(value) 322 } 323 maybe_from_u64(ty: Type, imm: u64) -> Option<Self>324 pub(crate) fn maybe_from_u64(ty: Type, imm: u64) -> Option<Self> { 325 // Convert the value into an F64, this allows us to represent 326 // values from both f32 and f64 in the same value. 327 let value = match ty { 328 F16 => { 329 // FIXME(#8312): Use `f16` once it has been stabilised. 330 // Handle special/non-normal values first. 331 match imm { 332 // `f16::MIN_POSITIVE` 333 0x0400 => return Some(Self::new(1)), 334 // 2 pow -16 335 0x0100 => return Some(Self::new(2)), 336 // 2 pow -15 337 0x0200 => return Some(Self::new(3)), 338 // `f16::INFINITY` 339 0x7c00 => return Some(Self::new(30)), 340 // Canonical NaN 341 0x7e00 => return Some(Self::new(31)), 342 _ => { 343 let exponent_bits = imm & 0x7c00; 344 if exponent_bits == 0 || exponent_bits == 0x7c00 { 345 // All non-normal values are handled above. 346 return None; 347 } 348 let sign = (imm & 0x8000) << 48; 349 // Adjust the exponent for the difference between the `f16` exponent bias 350 // and the `f64` exponent bias. 351 let exponent = (exponent_bits + ((1023 - 15) << 10)) << 42; 352 let significand = (imm & 0x3ff) << 42; 353 f64::from_bits(sign | exponent | significand) 354 } 355 } 356 } 357 F32 => f32::from_bits(imm as u32) as f64, 358 F64 => f64::from_bits(imm), 359 _ => unimplemented!(), 360 }; 361 362 Some(match (ty, value) { 363 (_, f) if f == -1.0 => Self::new(0), 364 365 // Since f64 can represent all f32 values, f32::min_positive won't be 366 // the same as f64::min_positive, so we need to check for both indepenendtly 367 (F32, f) if f == (f32::MIN_POSITIVE as f64) => Self::new(1), 368 (F64, f) if f == f64::MIN_POSITIVE => Self::new(1), 369 370 (_, f) if f == 2.0f64.powi(-16) => Self::new(2), 371 (_, f) if f == 2.0f64.powi(-15) => Self::new(3), 372 (_, f) if f == 2.0f64.powi(-8) => Self::new(4), 373 (_, f) if f == 2.0f64.powi(-7) => Self::new(5), 374 (_, f) if f == 0.0625 => Self::new(6), 375 (_, f) if f == 0.125 => Self::new(7), 376 (_, f) if f == 0.25 => Self::new(8), 377 (_, f) if f == 0.3125 => Self::new(9), 378 (_, f) if f == 0.375 => Self::new(10), 379 (_, f) if f == 0.4375 => Self::new(11), 380 (_, f) if f == 0.5 => Self::new(12), 381 (_, f) if f == 0.625 => Self::new(13), 382 (_, f) if f == 0.75 => Self::new(14), 383 (_, f) if f == 0.875 => Self::new(15), 384 (_, f) if f == 1.0 => Self::new(16), 385 (_, f) if f == 1.25 => Self::new(17), 386 (_, f) if f == 1.5 => Self::new(18), 387 (_, f) if f == 1.75 => Self::new(19), 388 (_, f) if f == 2.0 => Self::new(20), 389 (_, f) if f == 2.5 => Self::new(21), 390 (_, f) if f == 3.0 => Self::new(22), 391 (_, f) if f == 4.0 => Self::new(23), 392 (_, f) if f == 8.0 => Self::new(24), 393 (_, f) if f == 16.0 => Self::new(25), 394 (_, f) if f == 128.0 => Self::new(26), 395 (_, f) if f == 256.0 => Self::new(27), 396 (_, f) if f == 32768.0 => Self::new(28), 397 (_, f) if f == 65536.0 => Self::new(29), 398 (_, f) if f == f64::INFINITY => Self::new(30), 399 400 // NaN's are not guaranteed to preserve the sign / payload bits, so we need to check 401 // the original bits directly. 402 (F32, f) if f.is_nan() && imm == 0x7fc0_0000 => Self::new(31), // Canonical NaN 403 (F64, f) if f.is_nan() && imm == 0x7ff8_0000_0000_0000 => Self::new(31), // Canonical NaN 404 _ => return None, 405 }) 406 } 407 format(self) -> &'static str408 pub(crate) fn format(self) -> &'static str { 409 // The preferred assembly syntax for entries 1, 30, and 31 is min, inf, and nan, respectively. 410 // For entries 0 through 29 (including entry 1), the assembler will accept decimal constants 411 // in C-like syntax. 412 match self.0 { 413 0 => "-1.0", 414 1 => "min", 415 2 => "2^-16", 416 3 => "2^-15", 417 4 => "2^-8", 418 5 => "2^-7", 419 6 => "0.0625", 420 7 => "0.125", 421 8 => "0.25", 422 9 => "0.3125", 423 10 => "0.375", 424 11 => "0.4375", 425 12 => "0.5", 426 13 => "0.625", 427 14 => "0.75", 428 15 => "0.875", 429 16 => "1.0", 430 17 => "1.25", 431 18 => "1.5", 432 19 => "1.75", 433 20 => "2.0", 434 21 => "2.5", 435 22 => "3.0", 436 23 => "4.0", 437 24 => "8.0", 438 25 => "16.0", 439 26 => "128.0", 440 27 => "256.0", 441 28 => "32768.0", 442 29 => "65536.0", 443 30 => "inf", 444 31 => "nan", 445 _ => panic!("Invalid FliConstant"), 446 } 447 } 448 bits(self) -> u8449 pub(crate) fn bits(self) -> u8 { 450 self.0 451 } 452 } 453 454 impl FpuOPRRRR { op_name(self, width: FpuOPWidth) -> String455 pub(crate) fn op_name(self, width: FpuOPWidth) -> String { 456 match self { 457 Self::Fmadd => format!("fmadd.{width}"), 458 Self::Fmsub => format!("fmsub.{width}"), 459 Self::Fnmsub => format!("fnmsub.{width}"), 460 Self::Fnmadd => format!("fnmadd.{width}"), 461 } 462 } 463 opcode(self) -> u32464 pub(crate) fn opcode(self) -> u32 { 465 match self { 466 Self::Fmadd => 0b1000011, 467 Self::Fmsub => 0b1000111, 468 Self::Fnmsub => 0b1001011, 469 Self::Fnmadd => 0b1001111, 470 } 471 } 472 } 473 474 impl FpuOPRR { op_name(self, width: FpuOPWidth) -> String475 pub(crate) fn op_name(self, width: FpuOPWidth) -> String { 476 let fmv_width = match width { 477 FpuOPWidth::H => "h", 478 FpuOPWidth::S => "w", 479 FpuOPWidth::D => "d", 480 FpuOPWidth::Q => "q", 481 }; 482 match self { 483 Self::Fsqrt => format!("fsqrt.{width}"), 484 Self::Fround => format!("fround.{width}"), 485 Self::Fclass => format!("fclass.{width}"), 486 Self::FcvtWFmt => format!("fcvt.w.{width}"), 487 Self::FcvtWuFmt => format!("fcvt.wu.{width}"), 488 Self::FcvtLFmt => format!("fcvt.l.{width}"), 489 Self::FcvtLuFmt => format!("fcvt.lu.{width}"), 490 Self::FcvtFmtW => format!("fcvt.{width}.w"), 491 Self::FcvtFmtWu => format!("fcvt.{width}.wu"), 492 Self::FcvtFmtL => format!("fcvt.{width}.l"), 493 Self::FcvtFmtLu => format!("fcvt.{width}.lu"), 494 495 // fmv instructions deviate from the normal encoding and instead 496 // encode the width as "w" instead of "s". The ISA manual gives this rationale: 497 // 498 // Instructions FMV.S.X and FMV.X.S were renamed to FMV.W.X and FMV.X.W respectively 499 // to be more consistent with their semantics, which did not change. The old names will continue 500 // to be supported in the tools. 501 Self::FmvXFmt => format!("fmv.x.{fmv_width}"), 502 Self::FmvFmtX => format!("fmv.{fmv_width}.x"), 503 504 Self::FcvtSD => "fcvt.s.d".to_string(), 505 Self::FcvtDS => "fcvt.d.s".to_string(), 506 } 507 } 508 is_convert_to_int(self) -> bool509 pub(crate) fn is_convert_to_int(self) -> bool { 510 match self { 511 Self::FcvtWFmt | Self::FcvtWuFmt | Self::FcvtLFmt | Self::FcvtLuFmt => true, 512 _ => false, 513 } 514 } 515 has_frm(self) -> bool516 pub(crate) fn has_frm(self) -> bool { 517 match self { 518 FpuOPRR::FmvXFmt | FpuOPRR::FmvFmtX | FpuOPRR::Fclass => false, 519 _ => true, 520 } 521 } 522 opcode(self) -> u32523 pub(crate) fn opcode(self) -> u32 { 524 // OP-FP Major opcode 525 0b1010011 526 } 527 rs2(self) -> u32528 pub(crate) fn rs2(self) -> u32 { 529 match self { 530 Self::Fsqrt => 0b00000, 531 Self::Fround => 0b00100, 532 Self::Fclass => 0b00000, 533 Self::FcvtWFmt => 0b00000, 534 Self::FcvtWuFmt => 0b00001, 535 Self::FcvtLFmt => 0b00010, 536 Self::FcvtLuFmt => 0b00011, 537 Self::FcvtFmtW => 0b00000, 538 Self::FcvtFmtWu => 0b00001, 539 Self::FcvtFmtL => 0b00010, 540 Self::FcvtFmtLu => 0b00011, 541 Self::FmvXFmt => 0b00000, 542 Self::FmvFmtX => 0b00000, 543 Self::FcvtSD => 0b00001, 544 Self::FcvtDS => 0b00000, 545 } 546 } 547 funct5(self) -> u32548 pub(crate) fn funct5(self) -> u32 { 549 match self { 550 Self::Fsqrt => 0b01011, 551 Self::Fround => 0b01000, 552 Self::Fclass => 0b11100, 553 Self::FcvtWFmt => 0b11000, 554 Self::FcvtWuFmt => 0b11000, 555 Self::FcvtLFmt => 0b11000, 556 Self::FcvtLuFmt => 0b11000, 557 Self::FcvtFmtW => 0b11010, 558 Self::FcvtFmtWu => 0b11010, 559 Self::FcvtFmtL => 0b11010, 560 Self::FcvtFmtLu => 0b11010, 561 Self::FmvXFmt => 0b11100, 562 Self::FmvFmtX => 0b11110, 563 Self::FcvtSD => 0b01000, 564 Self::FcvtDS => 0b01000, 565 } 566 } 567 funct7(self, width: FpuOPWidth) -> u32568 pub(crate) fn funct7(self, width: FpuOPWidth) -> u32 { 569 (self.funct5() << 2) | width.as_u32() 570 } 571 } 572 573 impl FpuOPRRR { op_name(self, width: FpuOPWidth) -> String574 pub(crate) fn op_name(self, width: FpuOPWidth) -> String { 575 match self { 576 Self::Fadd => format!("fadd.{width}"), 577 Self::Fsub => format!("fsub.{width}"), 578 Self::Fmul => format!("fmul.{width}"), 579 Self::Fdiv => format!("fdiv.{width}"), 580 Self::Fsgnj => format!("fsgnj.{width}"), 581 Self::Fsgnjn => format!("fsgnjn.{width}"), 582 Self::Fsgnjx => format!("fsgnjx.{width}"), 583 Self::Fmin => format!("fmin.{width}"), 584 Self::Fmax => format!("fmax.{width}"), 585 Self::Feq => format!("feq.{width}"), 586 Self::Flt => format!("flt.{width}"), 587 Self::Fle => format!("fle.{width}"), 588 Self::Fminm => format!("fminm.{width}"), 589 Self::Fmaxm => format!("fmaxm.{width}"), 590 } 591 } 592 opcode(self) -> u32593 pub(crate) fn opcode(self) -> u32 { 594 // OP-FP Major opcode 595 0b1010011 596 } 597 funct5(self) -> u32598 pub(crate) const fn funct5(self) -> u32 { 599 match self { 600 Self::Fadd => 0b00000, 601 Self::Fsub => 0b00001, 602 Self::Fmul => 0b00010, 603 Self::Fdiv => 0b00011, 604 Self::Fsgnj => 0b00100, 605 Self::Fsgnjn => 0b00100, 606 Self::Fsgnjx => 0b00100, 607 Self::Fmin => 0b00101, 608 Self::Fmax => 0b00101, 609 Self::Feq => 0b10100, 610 Self::Flt => 0b10100, 611 Self::Fle => 0b10100, 612 Self::Fminm => 0b00101, 613 Self::Fmaxm => 0b00101, 614 } 615 } 616 funct7(self, width: FpuOPWidth) -> u32617 pub(crate) fn funct7(self, width: FpuOPWidth) -> u32 { 618 (self.funct5() << 2) | width.as_u32() 619 } 620 has_frm(self) -> bool621 pub(crate) fn has_frm(self) -> bool { 622 match self { 623 FpuOPRRR::Fsgnj 624 | FpuOPRRR::Fsgnjn 625 | FpuOPRRR::Fsgnjx 626 | FpuOPRRR::Fmin 627 | FpuOPRRR::Fmax 628 | FpuOPRRR::Feq 629 | FpuOPRRR::Flt 630 | FpuOPRRR::Fle => false, 631 _ => true, 632 } 633 } 634 } 635 636 impl Display for FpuOPWidth { fmt(&self, f: &mut Formatter<'_>) -> Result637 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 638 write!( 639 f, 640 "{}", 641 match self { 642 FpuOPWidth::H => "h", 643 FpuOPWidth::S => "s", 644 FpuOPWidth::D => "d", 645 FpuOPWidth::Q => "q", 646 } 647 ) 648 } 649 } 650 651 impl TryFrom<Type> for FpuOPWidth { 652 type Error = &'static str; 653 try_from(value: Type) -> core::result::Result<Self, Self::Error>654 fn try_from(value: Type) -> core::result::Result<Self, Self::Error> { 655 match value { 656 F16 => Ok(FpuOPWidth::H), 657 F32 => Ok(FpuOPWidth::S), 658 F64 => Ok(FpuOPWidth::D), 659 F128 => Ok(FpuOPWidth::Q), 660 _ => Err("Invalid type for FpuOPWidth"), 661 } 662 } 663 } 664 665 impl FpuOPWidth { as_u32(&self) -> u32666 pub(crate) fn as_u32(&self) -> u32 { 667 match self { 668 FpuOPWidth::S => 0b00, 669 FpuOPWidth::D => 0b01, 670 FpuOPWidth::H => 0b10, 671 FpuOPWidth::Q => 0b11, 672 } 673 } 674 } 675 676 impl AluOPRRR { op_name(self) -> &'static str677 pub(crate) const fn op_name(self) -> &'static str { 678 match self { 679 Self::Add => "add", 680 Self::Sub => "sub", 681 Self::Sll => "sll", 682 Self::Slt => "slt", 683 Self::Sgt => "sgt", 684 Self::SltU => "sltu", 685 Self::Sgtu => "sgtu", 686 Self::Xor => "xor", 687 Self::Srl => "srl", 688 Self::Sra => "sra", 689 Self::Or => "or", 690 Self::And => "and", 691 Self::Addw => "addw", 692 Self::Subw => "subw", 693 Self::Sllw => "sllw", 694 Self::Srlw => "srlw", 695 Self::Sraw => "sraw", 696 Self::Mul => "mul", 697 Self::Mulh => "mulh", 698 Self::Mulhsu => "mulhsu", 699 Self::Mulhu => "mulhu", 700 Self::Div => "div", 701 Self::DivU => "divu", 702 Self::Rem => "rem", 703 Self::RemU => "remu", 704 Self::Mulw => "mulw", 705 Self::Divw => "divw", 706 Self::Divuw => "divuw", 707 Self::Remw => "remw", 708 Self::Remuw => "remuw", 709 Self::Adduw => "add.uw", 710 Self::Andn => "andn", 711 Self::Bclr => "bclr", 712 Self::Bext => "bext", 713 Self::Binv => "binv", 714 Self::Bset => "bset", 715 Self::Clmul => "clmul", 716 Self::Clmulh => "clmulh", 717 Self::Clmulr => "clmulr", 718 Self::Max => "max", 719 Self::Maxu => "maxu", 720 Self::Min => "min", 721 Self::Minu => "minu", 722 Self::Orn => "orn", 723 Self::Rol => "rol", 724 Self::Rolw => "rolw", 725 Self::Ror => "ror", 726 Self::Rorw => "rorw", 727 Self::Sh1add => "sh1add", 728 Self::Sh1adduw => "sh1add.uw", 729 Self::Sh2add => "sh2add", 730 Self::Sh2adduw => "sh2add.uw", 731 Self::Sh3add => "sh3add", 732 Self::Sh3adduw => "sh3add.uw", 733 Self::Xnor => "xnor", 734 Self::Pack => "pack", 735 Self::Packw => "packw", 736 Self::Packh => "packh", 737 Self::CzeroEqz => "czero.eqz", 738 Self::CzeroNez => "czero.nez", 739 } 740 } 741 funct3(self) -> u32742 pub fn funct3(self) -> u32 { 743 match self { 744 AluOPRRR::Add => 0b000, 745 AluOPRRR::Sll => 0b001, 746 AluOPRRR::Slt => 0b010, 747 AluOPRRR::Sgt => 0b010, 748 AluOPRRR::SltU => 0b011, 749 AluOPRRR::Sgtu => 0b011, 750 AluOPRRR::Xor => 0b100, 751 AluOPRRR::Srl => 0b101, 752 AluOPRRR::Sra => 0b101, 753 AluOPRRR::Or => 0b110, 754 AluOPRRR::And => 0b111, 755 AluOPRRR::Sub => 0b000, 756 757 AluOPRRR::Addw => 0b000, 758 AluOPRRR::Subw => 0b000, 759 AluOPRRR::Sllw => 0b001, 760 AluOPRRR::Srlw => 0b101, 761 AluOPRRR::Sraw => 0b101, 762 763 AluOPRRR::Mul => 0b000, 764 AluOPRRR::Mulh => 0b001, 765 AluOPRRR::Mulhsu => 0b010, 766 AluOPRRR::Mulhu => 0b011, 767 AluOPRRR::Div => 0b100, 768 AluOPRRR::DivU => 0b101, 769 AluOPRRR::Rem => 0b110, 770 AluOPRRR::RemU => 0b111, 771 772 AluOPRRR::Mulw => 0b000, 773 AluOPRRR::Divw => 0b100, 774 AluOPRRR::Divuw => 0b101, 775 AluOPRRR::Remw => 0b110, 776 AluOPRRR::Remuw => 0b111, 777 778 // Zbb 779 AluOPRRR::Adduw => 0b000, 780 AluOPRRR::Andn => 0b111, 781 AluOPRRR::Bclr => 0b001, 782 AluOPRRR::Bext => 0b101, 783 AluOPRRR::Binv => 0b001, 784 AluOPRRR::Bset => 0b001, 785 AluOPRRR::Clmul => 0b001, 786 AluOPRRR::Clmulh => 0b011, 787 AluOPRRR::Clmulr => 0b010, 788 AluOPRRR::Max => 0b110, 789 AluOPRRR::Maxu => 0b111, 790 AluOPRRR::Min => 0b100, 791 AluOPRRR::Minu => 0b101, 792 AluOPRRR::Orn => 0b110, 793 AluOPRRR::Rol => 0b001, 794 AluOPRRR::Rolw => 0b001, 795 AluOPRRR::Ror => 0b101, 796 AluOPRRR::Rorw => 0b101, 797 AluOPRRR::Sh1add => 0b010, 798 AluOPRRR::Sh1adduw => 0b010, 799 AluOPRRR::Sh2add => 0b100, 800 AluOPRRR::Sh2adduw => 0b100, 801 AluOPRRR::Sh3add => 0b110, 802 AluOPRRR::Sh3adduw => 0b110, 803 AluOPRRR::Xnor => 0b100, 804 805 // Zbkb 806 AluOPRRR::Pack => 0b100, 807 AluOPRRR::Packw => 0b100, 808 AluOPRRR::Packh => 0b111, 809 810 // ZiCond 811 AluOPRRR::CzeroEqz => 0b101, 812 AluOPRRR::CzeroNez => 0b111, 813 } 814 } 815 op_code(self) -> u32816 pub fn op_code(self) -> u32 { 817 match self { 818 AluOPRRR::Add 819 | AluOPRRR::Sub 820 | AluOPRRR::Sll 821 | AluOPRRR::Slt 822 | AluOPRRR::Sgt 823 | AluOPRRR::SltU 824 | AluOPRRR::Sgtu 825 | AluOPRRR::Xor 826 | AluOPRRR::Srl 827 | AluOPRRR::Sra 828 | AluOPRRR::Or 829 | AluOPRRR::And 830 | AluOPRRR::Pack 831 | AluOPRRR::Packh => 0b0110011, 832 833 AluOPRRR::Addw 834 | AluOPRRR::Subw 835 | AluOPRRR::Sllw 836 | AluOPRRR::Srlw 837 | AluOPRRR::Sraw 838 | AluOPRRR::Packw => 0b0111011, 839 840 AluOPRRR::Mul 841 | AluOPRRR::Mulh 842 | AluOPRRR::Mulhsu 843 | AluOPRRR::Mulhu 844 | AluOPRRR::Div 845 | AluOPRRR::DivU 846 | AluOPRRR::Rem 847 | AluOPRRR::RemU => 0b0110011, 848 849 AluOPRRR::Mulw 850 | AluOPRRR::Divw 851 | AluOPRRR::Divuw 852 | AluOPRRR::Remw 853 | AluOPRRR::Remuw => 0b0111011, 854 855 AluOPRRR::Adduw => 0b0111011, 856 AluOPRRR::Andn 857 | AluOPRRR::Bclr 858 | AluOPRRR::Bext 859 | AluOPRRR::Binv 860 | AluOPRRR::Bset 861 | AluOPRRR::Clmul 862 | AluOPRRR::Clmulh 863 | AluOPRRR::Clmulr 864 | AluOPRRR::Max 865 | AluOPRRR::Maxu 866 | AluOPRRR::Min 867 | AluOPRRR::Minu 868 | AluOPRRR::Orn 869 | AluOPRRR::Rol 870 | AluOPRRR::Ror 871 | AluOPRRR::Sh1add 872 | AluOPRRR::Sh2add 873 | AluOPRRR::Sh3add 874 | AluOPRRR::Xnor 875 | AluOPRRR::CzeroEqz 876 | AluOPRRR::CzeroNez => 0b0110011, 877 878 AluOPRRR::Rolw 879 | AluOPRRR::Rorw 880 | AluOPRRR::Sh2adduw 881 | AluOPRRR::Sh3adduw 882 | AluOPRRR::Sh1adduw => 0b0111011, 883 } 884 } 885 funct7(self) -> u32886 pub const fn funct7(self) -> u32 { 887 match self { 888 AluOPRRR::Add => 0b0000000, 889 AluOPRRR::Sub => 0b0100000, 890 AluOPRRR::Sll => 0b0000000, 891 AluOPRRR::Slt => 0b0000000, 892 AluOPRRR::Sgt => 0b0000000, 893 AluOPRRR::SltU => 0b0000000, 894 AluOPRRR::Sgtu => 0b0000000, 895 896 AluOPRRR::Xor => 0b0000000, 897 AluOPRRR::Srl => 0b0000000, 898 AluOPRRR::Sra => 0b0100000, 899 AluOPRRR::Or => 0b0000000, 900 AluOPRRR::And => 0b0000000, 901 902 AluOPRRR::Addw => 0b0000000, 903 AluOPRRR::Subw => 0b0100000, 904 AluOPRRR::Sllw => 0b0000000, 905 AluOPRRR::Srlw => 0b0000000, 906 AluOPRRR::Sraw => 0b0100000, 907 908 AluOPRRR::Mul => 0b0000001, 909 AluOPRRR::Mulh => 0b0000001, 910 AluOPRRR::Mulhsu => 0b0000001, 911 AluOPRRR::Mulhu => 0b0000001, 912 AluOPRRR::Div => 0b0000001, 913 AluOPRRR::DivU => 0b0000001, 914 AluOPRRR::Rem => 0b0000001, 915 AluOPRRR::RemU => 0b0000001, 916 917 AluOPRRR::Mulw => 0b0000001, 918 AluOPRRR::Divw => 0b0000001, 919 AluOPRRR::Divuw => 0b0000001, 920 AluOPRRR::Remw => 0b0000001, 921 AluOPRRR::Remuw => 0b0000001, 922 AluOPRRR::Adduw => 0b0000100, 923 AluOPRRR::Andn => 0b0100000, 924 AluOPRRR::Bclr => 0b0100100, 925 AluOPRRR::Bext => 0b0100100, 926 AluOPRRR::Binv => 0b0110100, 927 AluOPRRR::Bset => 0b0010100, 928 AluOPRRR::Clmul => 0b0000101, 929 AluOPRRR::Clmulh => 0b0000101, 930 AluOPRRR::Clmulr => 0b0000101, 931 AluOPRRR::Max => 0b0000101, 932 AluOPRRR::Maxu => 0b0000101, 933 AluOPRRR::Min => 0b0000101, 934 AluOPRRR::Minu => 0b0000101, 935 AluOPRRR::Orn => 0b0100000, 936 AluOPRRR::Rol => 0b0110000, 937 AluOPRRR::Rolw => 0b0110000, 938 AluOPRRR::Ror => 0b0110000, 939 AluOPRRR::Rorw => 0b0110000, 940 AluOPRRR::Sh1add => 0b0010000, 941 AluOPRRR::Sh1adduw => 0b0010000, 942 AluOPRRR::Sh2add => 0b0010000, 943 AluOPRRR::Sh2adduw => 0b0010000, 944 AluOPRRR::Sh3add => 0b0010000, 945 AluOPRRR::Sh3adduw => 0b0010000, 946 AluOPRRR::Xnor => 0b0100000, 947 948 // Zbkb 949 AluOPRRR::Pack => 0b0000100, 950 AluOPRRR::Packw => 0b0000100, 951 AluOPRRR::Packh => 0b0000100, 952 953 // ZiCond 954 AluOPRRR::CzeroEqz => 0b0000111, 955 AluOPRRR::CzeroNez => 0b0000111, 956 } 957 } 958 reverse_rs(self) -> bool959 pub(crate) fn reverse_rs(self) -> bool { 960 // special case. 961 // sgt and sgtu is not defined in isa. 962 // emit should reverse rs1 and rs2. 963 self == AluOPRRR::Sgt || self == AluOPRRR::Sgtu 964 } 965 } 966 967 impl AluOPRRI { option_funct6(self) -> Option<u32>968 pub(crate) fn option_funct6(self) -> Option<u32> { 969 let x: Option<u32> = match self { 970 Self::Slli => Some(0b00_0000), 971 Self::Srli => Some(0b00_0000), 972 Self::Srai => Some(0b01_0000), 973 Self::Bclri => Some(0b010010), 974 Self::Bexti => Some(0b010010), 975 Self::Binvi => Some(0b011010), 976 Self::Bseti => Some(0b001010), 977 Self::Rori => Some(0b011000), 978 Self::SlliUw => Some(0b000010), 979 _ => None, 980 }; 981 x 982 } 983 option_funct7(self) -> Option<u32>984 pub(crate) fn option_funct7(self) -> Option<u32> { 985 let x = match self { 986 Self::Slliw => Some(0b000_0000), 987 Self::SrliW => Some(0b000_0000), 988 Self::Sraiw => Some(0b010_0000), 989 Self::Roriw => Some(0b0110000), 990 _ => None, 991 }; 992 x 993 } 994 imm12(self, imm12: Imm12) -> u32995 pub(crate) fn imm12(self, imm12: Imm12) -> u32 { 996 let x = imm12.bits(); 997 if let Some(func) = self.option_funct6() { 998 func << 6 | (x & 0b11_1111) 999 } else if let Some(func) = self.option_funct7() { 1000 func << 5 | (x & 0b1_1111) 1001 } else if let Some(func) = self.option_funct12() { 1002 func 1003 } else { 1004 x 1005 } 1006 } 1007 option_funct12(self) -> Option<u32>1008 pub(crate) fn option_funct12(self) -> Option<u32> { 1009 match self { 1010 Self::Clz => Some(0b011000000000), 1011 Self::Clzw => Some(0b011000000000), 1012 Self::Cpop => Some(0b011000000010), 1013 Self::Cpopw => Some(0b011000000010), 1014 Self::Ctz => Some(0b011000000001), 1015 Self::Ctzw => Some(0b011000000001), 1016 Self::Rev8 => Some(0b011010111000), 1017 Self::Sextb => Some(0b011000000100), 1018 Self::Sexth => Some(0b011000000101), 1019 Self::Zexth => Some(0b000010000000), 1020 Self::Orcb => Some(0b001010000111), 1021 Self::Brev8 => Some(0b0110_1000_0111), 1022 _ => None, 1023 } 1024 } 1025 op_name(self) -> &'static str1026 pub(crate) fn op_name(self) -> &'static str { 1027 match self { 1028 Self::Addi => "addi", 1029 Self::Slti => "slti", 1030 Self::SltiU => "sltiu", 1031 Self::Xori => "xori", 1032 Self::Ori => "ori", 1033 Self::Andi => "andi", 1034 Self::Slli => "slli", 1035 Self::Srli => "srli", 1036 Self::Srai => "srai", 1037 Self::Addiw => "addiw", 1038 Self::Slliw => "slliw", 1039 Self::SrliW => "srliw", 1040 Self::Sraiw => "sraiw", 1041 Self::Bclri => "bclri", 1042 Self::Bexti => "bexti", 1043 Self::Binvi => "binvi", 1044 Self::Bseti => "bseti", 1045 Self::Rori => "rori", 1046 Self::Roriw => "roriw", 1047 Self::SlliUw => "slli.uw", 1048 Self::Clz => "clz", 1049 Self::Clzw => "clzw", 1050 Self::Cpop => "cpop", 1051 Self::Cpopw => "cpopw", 1052 Self::Ctz => "ctz", 1053 Self::Ctzw => "ctzw", 1054 Self::Rev8 => "rev8", 1055 Self::Sextb => "sext.b", 1056 Self::Sexth => "sext.h", 1057 Self::Zexth => "zext.h", 1058 Self::Orcb => "orc.b", 1059 Self::Brev8 => "brev8", 1060 } 1061 } 1062 funct3(self) -> u321063 pub fn funct3(self) -> u32 { 1064 match self { 1065 AluOPRRI::Addi => 0b000, 1066 AluOPRRI::Slti => 0b010, 1067 AluOPRRI::SltiU => 0b011, 1068 AluOPRRI::Xori => 0b100, 1069 AluOPRRI::Ori => 0b110, 1070 AluOPRRI::Andi => 0b111, 1071 AluOPRRI::Slli => 0b001, 1072 AluOPRRI::Srli => 0b101, 1073 AluOPRRI::Srai => 0b101, 1074 AluOPRRI::Addiw => 0b000, 1075 AluOPRRI::Slliw => 0b001, 1076 AluOPRRI::SrliW => 0b101, 1077 AluOPRRI::Sraiw => 0b101, 1078 AluOPRRI::Bclri => 0b001, 1079 AluOPRRI::Bexti => 0b101, 1080 AluOPRRI::Binvi => 0b001, 1081 AluOPRRI::Bseti => 0b001, 1082 AluOPRRI::Rori => 0b101, 1083 AluOPRRI::Roriw => 0b101, 1084 AluOPRRI::SlliUw => 0b001, 1085 AluOPRRI::Clz => 0b001, 1086 AluOPRRI::Clzw => 0b001, 1087 AluOPRRI::Cpop => 0b001, 1088 AluOPRRI::Cpopw => 0b001, 1089 AluOPRRI::Ctz => 0b001, 1090 AluOPRRI::Ctzw => 0b001, 1091 AluOPRRI::Rev8 => 0b101, 1092 AluOPRRI::Sextb => 0b001, 1093 AluOPRRI::Sexth => 0b001, 1094 AluOPRRI::Zexth => 0b100, 1095 AluOPRRI::Orcb => 0b101, 1096 AluOPRRI::Brev8 => 0b101, 1097 } 1098 } 1099 op_code(self) -> u321100 pub fn op_code(self) -> u32 { 1101 match self { 1102 AluOPRRI::Addi 1103 | AluOPRRI::Slti 1104 | AluOPRRI::SltiU 1105 | AluOPRRI::Xori 1106 | AluOPRRI::Ori 1107 | AluOPRRI::Andi 1108 | AluOPRRI::Slli 1109 | AluOPRRI::Srli 1110 | AluOPRRI::Srai 1111 | AluOPRRI::Bclri 1112 | AluOPRRI::Bexti 1113 | AluOPRRI::Binvi 1114 | AluOPRRI::Bseti 1115 | AluOPRRI::Rori 1116 | AluOPRRI::Clz 1117 | AluOPRRI::Cpop 1118 | AluOPRRI::Ctz 1119 | AluOPRRI::Rev8 1120 | AluOPRRI::Sextb 1121 | AluOPRRI::Sexth 1122 | AluOPRRI::Orcb 1123 | AluOPRRI::Brev8 => 0b0010011, 1124 1125 AluOPRRI::Addiw 1126 | AluOPRRI::Slliw 1127 | AluOPRRI::SrliW 1128 | AluOPRRI::Sraiw 1129 | AluOPRRI::Roriw 1130 | AluOPRRI::SlliUw 1131 | AluOPRRI::Clzw 1132 | AluOPRRI::Cpopw 1133 | AluOPRRI::Ctzw => 0b0011011, 1134 AluOPRRI::Zexth => 0b0111011, 1135 } 1136 } 1137 } 1138 1139 impl Default for FRM { default() -> Self1140 fn default() -> Self { 1141 Self::Fcsr 1142 } 1143 } 1144 1145 /// float rounding mode. 1146 impl FRM { to_static_str(self) -> &'static str1147 pub(crate) fn to_static_str(self) -> &'static str { 1148 match self { 1149 FRM::RNE => "rne", 1150 FRM::RTZ => "rtz", 1151 FRM::RDN => "rdn", 1152 FRM::RUP => "rup", 1153 FRM::RMM => "rmm", 1154 FRM::Fcsr => "fcsr", 1155 } 1156 } 1157 1158 #[inline] bits(self) -> u81159 pub(crate) fn bits(self) -> u8 { 1160 match self { 1161 FRM::RNE => 0b000, 1162 FRM::RTZ => 0b001, 1163 FRM::RDN => 0b010, 1164 FRM::RUP => 0b011, 1165 FRM::RMM => 0b100, 1166 FRM::Fcsr => 0b111, 1167 } 1168 } as_u32(self) -> u321169 pub(crate) fn as_u32(self) -> u32 { 1170 self.bits() as u32 1171 } 1172 } 1173 1174 impl FFlagsException { 1175 #[inline] 1176 #[expect(dead_code, reason = "here for future use")] mask(self) -> u321177 pub(crate) fn mask(self) -> u32 { 1178 match self { 1179 FFlagsException::NV => 1 << 4, 1180 FFlagsException::DZ => 1 << 3, 1181 FFlagsException::OF => 1 << 2, 1182 FFlagsException::UF => 1 << 1, 1183 FFlagsException::NX => 1 << 0, 1184 } 1185 } 1186 } 1187 1188 impl LoadOP { op_name(self) -> &'static str1189 pub(crate) fn op_name(self) -> &'static str { 1190 match self { 1191 Self::Lb => "lb", 1192 Self::Lh => "lh", 1193 Self::Lw => "lw", 1194 Self::Lbu => "lbu", 1195 Self::Lhu => "lhu", 1196 Self::Lwu => "lwu", 1197 Self::Ld => "ld", 1198 Self::Flh => "flh", 1199 Self::Flw => "flw", 1200 Self::Fld => "fld", 1201 } 1202 } 1203 from_type(ty: Type) -> Self1204 pub(crate) fn from_type(ty: Type) -> Self { 1205 match ty { 1206 F16 => Self::Flh, 1207 F32 => Self::Flw, 1208 F64 => Self::Fld, 1209 I8 => Self::Lb, 1210 I16 => Self::Lh, 1211 I32 => Self::Lw, 1212 I64 => Self::Ld, 1213 _ => unreachable!(), 1214 } 1215 } 1216 size(&self) -> i641217 pub(crate) fn size(&self) -> i64 { 1218 match self { 1219 Self::Lb | Self::Lbu => 1, 1220 Self::Lh | Self::Lhu | Self::Flh => 2, 1221 Self::Lw | Self::Lwu | Self::Flw => 4, 1222 Self::Ld | Self::Fld => 8, 1223 } 1224 } 1225 op_code(self) -> u321226 pub(crate) fn op_code(self) -> u32 { 1227 match self { 1228 Self::Lb | Self::Lh | Self::Lw | Self::Lbu | Self::Lhu | Self::Lwu | Self::Ld => { 1229 0b0000011 1230 } 1231 Self::Flh | Self::Flw | Self::Fld => 0b0000111, 1232 } 1233 } funct3(self) -> u321234 pub(crate) fn funct3(self) -> u32 { 1235 match self { 1236 Self::Lb => 0b000, 1237 Self::Lh => 0b001, 1238 Self::Lw => 0b010, 1239 Self::Lwu => 0b110, 1240 Self::Lbu => 0b100, 1241 Self::Lhu => 0b101, 1242 Self::Ld => 0b011, 1243 Self::Flh => 0b001, 1244 Self::Flw => 0b010, 1245 Self::Fld => 0b011, 1246 } 1247 } 1248 } 1249 1250 impl StoreOP { op_name(self) -> &'static str1251 pub(crate) fn op_name(self) -> &'static str { 1252 match self { 1253 Self::Sb => "sb", 1254 Self::Sh => "sh", 1255 Self::Sw => "sw", 1256 Self::Sd => "sd", 1257 Self::Fsh => "fsh", 1258 Self::Fsw => "fsw", 1259 Self::Fsd => "fsd", 1260 } 1261 } from_type(ty: Type) -> Self1262 pub(crate) fn from_type(ty: Type) -> Self { 1263 match ty { 1264 F16 => Self::Fsh, 1265 F32 => Self::Fsw, 1266 F64 => Self::Fsd, 1267 I8 => Self::Sb, 1268 I16 => Self::Sh, 1269 I32 => Self::Sw, 1270 I64 => Self::Sd, 1271 _ => unreachable!(), 1272 } 1273 } 1274 size(&self) -> i641275 pub(crate) fn size(&self) -> i64 { 1276 match self { 1277 Self::Sb => 1, 1278 Self::Sh | Self::Fsh => 2, 1279 Self::Sw | Self::Fsw => 4, 1280 Self::Sd | Self::Fsd => 8, 1281 } 1282 } 1283 op_code(self) -> u321284 pub(crate) fn op_code(self) -> u32 { 1285 match self { 1286 Self::Sb | Self::Sh | Self::Sw | Self::Sd => 0b0100011, 1287 Self::Fsh | Self::Fsw | Self::Fsd => 0b0100111, 1288 } 1289 } funct3(self) -> u321290 pub(crate) fn funct3(self) -> u32 { 1291 match self { 1292 Self::Sb => 0b000, 1293 Self::Sh => 0b001, 1294 Self::Sw => 0b010, 1295 Self::Sd => 0b011, 1296 Self::Fsh => 0b001, 1297 Self::Fsw => 0b010, 1298 Self::Fsd => 0b011, 1299 } 1300 } 1301 } 1302 1303 impl FClassResult { bit(self) -> u321304 pub(crate) const fn bit(self) -> u32 { 1305 match self { 1306 FClassResult::NegInfinite => 1 << 0, 1307 FClassResult::NegNormal => 1 << 1, 1308 FClassResult::NegSubNormal => 1 << 2, 1309 FClassResult::NegZero => 1 << 3, 1310 FClassResult::PosZero => 1 << 4, 1311 FClassResult::PosSubNormal => 1 << 5, 1312 FClassResult::PosNormal => 1 << 6, 1313 FClassResult::PosInfinite => 1 << 7, 1314 FClassResult::SNaN => 1 << 8, 1315 FClassResult::QNaN => 1 << 9, 1316 } 1317 } 1318 1319 #[inline] 1320 #[expect(dead_code, reason = "here for future use")] is_nan_bits() -> u321321 pub(crate) const fn is_nan_bits() -> u32 { 1322 Self::SNaN.bit() | Self::QNaN.bit() 1323 } 1324 #[inline] 1325 #[expect(dead_code, reason = "here for future use")] is_zero_bits() -> u321326 pub(crate) fn is_zero_bits() -> u32 { 1327 Self::NegZero.bit() | Self::PosZero.bit() 1328 } 1329 1330 #[inline] 1331 #[expect(dead_code, reason = "here for future use")] is_infinite_bits() -> u321332 pub(crate) fn is_infinite_bits() -> u32 { 1333 Self::PosInfinite.bit() | Self::NegInfinite.bit() 1334 } 1335 } 1336 1337 impl AtomicOP { 1338 #[inline] is_load(self) -> bool1339 pub(crate) fn is_load(self) -> bool { 1340 match self { 1341 Self::LrW | Self::LrD => true, 1342 _ => false, 1343 } 1344 } 1345 1346 #[inline] op_name(self, amo: AMO) -> String1347 pub(crate) fn op_name(self, amo: AMO) -> String { 1348 let s = match self { 1349 Self::LrW => "lr.w", 1350 Self::ScW => "sc.w", 1351 1352 Self::AmoswapW => "amoswap.w", 1353 Self::AmoaddW => "amoadd.w", 1354 Self::AmoxorW => "amoxor.w", 1355 Self::AmoandW => "amoand.w", 1356 Self::AmoorW => "amoor.w", 1357 Self::AmominW => "amomin.w", 1358 Self::AmomaxW => "amomax.w", 1359 Self::AmominuW => "amominu.w", 1360 Self::AmomaxuW => "amomaxu.w", 1361 Self::LrD => "lr.d", 1362 Self::ScD => "sc.d", 1363 Self::AmoswapD => "amoswap.d", 1364 Self::AmoaddD => "amoadd.d", 1365 Self::AmoxorD => "amoxor.d", 1366 Self::AmoandD => "amoand.d", 1367 Self::AmoorD => "amoor.d", 1368 Self::AmominD => "amomin.d", 1369 Self::AmomaxD => "amomax.d", 1370 Self::AmominuD => "amominu.d", 1371 Self::AmomaxuD => "amomaxu.d", 1372 }; 1373 format!("{}{}", s, amo.to_static_str()) 1374 } 1375 #[inline] op_code(self) -> u321376 pub(crate) fn op_code(self) -> u32 { 1377 0b0101111 1378 } 1379 1380 #[inline] funct7(self, amo: AMO) -> u321381 pub(crate) fn funct7(self, amo: AMO) -> u32 { 1382 self.funct5() << 2 | amo.as_u32() & 0b11 1383 } 1384 funct3(self) -> u321385 pub(crate) fn funct3(self) -> u32 { 1386 match self { 1387 AtomicOP::LrW 1388 | AtomicOP::ScW 1389 | AtomicOP::AmoswapW 1390 | AtomicOP::AmoaddW 1391 | AtomicOP::AmoxorW 1392 | AtomicOP::AmoandW 1393 | AtomicOP::AmoorW 1394 | AtomicOP::AmominW 1395 | AtomicOP::AmomaxW 1396 | AtomicOP::AmominuW 1397 | AtomicOP::AmomaxuW => 0b010, 1398 AtomicOP::LrD 1399 | AtomicOP::ScD 1400 | AtomicOP::AmoswapD 1401 | AtomicOP::AmoaddD 1402 | AtomicOP::AmoxorD 1403 | AtomicOP::AmoandD 1404 | AtomicOP::AmoorD 1405 | AtomicOP::AmominD 1406 | AtomicOP::AmomaxD 1407 | AtomicOP::AmominuD 1408 | AtomicOP::AmomaxuD => 0b011, 1409 } 1410 } funct5(self) -> u321411 pub(crate) fn funct5(self) -> u32 { 1412 match self { 1413 AtomicOP::LrW => 0b00010, 1414 AtomicOP::ScW => 0b00011, 1415 AtomicOP::AmoswapW => 0b00001, 1416 AtomicOP::AmoaddW => 0b00000, 1417 AtomicOP::AmoxorW => 0b00100, 1418 AtomicOP::AmoandW => 0b01100, 1419 AtomicOP::AmoorW => 0b01000, 1420 AtomicOP::AmominW => 0b10000, 1421 AtomicOP::AmomaxW => 0b10100, 1422 AtomicOP::AmominuW => 0b11000, 1423 AtomicOP::AmomaxuW => 0b11100, 1424 AtomicOP::LrD => 0b00010, 1425 AtomicOP::ScD => 0b00011, 1426 AtomicOP::AmoswapD => 0b00001, 1427 AtomicOP::AmoaddD => 0b00000, 1428 AtomicOP::AmoxorD => 0b00100, 1429 AtomicOP::AmoandD => 0b01100, 1430 AtomicOP::AmoorD => 0b01000, 1431 AtomicOP::AmominD => 0b10000, 1432 AtomicOP::AmomaxD => 0b10100, 1433 AtomicOP::AmominuD => 0b11000, 1434 AtomicOP::AmomaxuD => 0b11100, 1435 } 1436 } 1437 load_op(t: Type) -> Self1438 pub(crate) fn load_op(t: Type) -> Self { 1439 if t.bits() <= 32 { Self::LrW } else { Self::LrD } 1440 } store_op(t: Type) -> Self1441 pub(crate) fn store_op(t: Type) -> Self { 1442 if t.bits() <= 32 { Self::ScW } else { Self::ScD } 1443 } 1444 1445 /// extract extract(rd: WritableReg, offset: Reg, rs: Reg, ty: Type) -> SmallInstVec<Inst>1446 pub(crate) fn extract(rd: WritableReg, offset: Reg, rs: Reg, ty: Type) -> SmallInstVec<Inst> { 1447 let mut insts = SmallInstVec::new(); 1448 insts.push(Inst::AluRRR { 1449 alu_op: AluOPRRR::Srl, 1450 rd, 1451 rs1: rs, 1452 rs2: offset, 1453 }); 1454 // 1455 insts.push(Inst::Extend { 1456 rd, 1457 rn: rd.to_reg(), 1458 signed: false, 1459 from_bits: ty.bits() as u8, 1460 to_bits: 64, 1461 }); 1462 insts 1463 } 1464 1465 /// like extract but sign extend the value. 1466 /// suitable for smax,etc. extract_sext( rd: WritableReg, offset: Reg, rs: Reg, ty: Type, ) -> SmallInstVec<Inst>1467 pub(crate) fn extract_sext( 1468 rd: WritableReg, 1469 offset: Reg, 1470 rs: Reg, 1471 ty: Type, 1472 ) -> SmallInstVec<Inst> { 1473 let mut insts = SmallInstVec::new(); 1474 insts.push(Inst::AluRRR { 1475 alu_op: AluOPRRR::Srl, 1476 rd, 1477 rs1: rs, 1478 rs2: offset, 1479 }); 1480 // 1481 insts.push(Inst::Extend { 1482 rd, 1483 rn: rd.to_reg(), 1484 signed: true, 1485 from_bits: ty.bits() as u8, 1486 to_bits: 64, 1487 }); 1488 insts 1489 } 1490 unset( rd: WritableReg, tmp: WritableReg, offset: Reg, ty: Type, ) -> SmallInstVec<Inst>1491 pub(crate) fn unset( 1492 rd: WritableReg, 1493 tmp: WritableReg, 1494 offset: Reg, 1495 ty: Type, 1496 ) -> SmallInstVec<Inst> { 1497 assert!(rd != tmp); 1498 let mut insts = SmallInstVec::new(); 1499 insts.extend(Inst::load_int_mask(tmp, ty)); 1500 insts.push(Inst::AluRRR { 1501 alu_op: AluOPRRR::Sll, 1502 rd: tmp, 1503 rs1: tmp.to_reg(), 1504 rs2: offset, 1505 }); 1506 insts.push(Inst::construct_bit_not(tmp, tmp.to_reg())); 1507 insts.push(Inst::AluRRR { 1508 alu_op: AluOPRRR::And, 1509 rd, 1510 rs1: rd.to_reg(), 1511 rs2: tmp.to_reg(), 1512 }); 1513 insts 1514 } 1515 set( rd: WritableReg, tmp: WritableReg, offset: Reg, rs: Reg, ty: Type, ) -> SmallInstVec<Inst>1516 pub(crate) fn set( 1517 rd: WritableReg, 1518 tmp: WritableReg, 1519 offset: Reg, 1520 rs: Reg, 1521 ty: Type, 1522 ) -> SmallInstVec<Inst> { 1523 assert!(rd != tmp); 1524 let mut insts = SmallInstVec::new(); 1525 // make rs into tmp. 1526 insts.push(Inst::Extend { 1527 rd: tmp, 1528 rn: rs, 1529 signed: false, 1530 from_bits: ty.bits() as u8, 1531 to_bits: 64, 1532 }); 1533 insts.push(Inst::AluRRR { 1534 alu_op: AluOPRRR::Sll, 1535 rd: tmp, 1536 rs1: tmp.to_reg(), 1537 rs2: offset, 1538 }); 1539 insts.push(Inst::AluRRR { 1540 alu_op: AluOPRRR::Or, 1541 rd, 1542 rs1: rd.to_reg(), 1543 rs2: tmp.to_reg(), 1544 }); 1545 insts 1546 } 1547 1548 /// Merge reset part of rs into rd. 1549 /// Call this function must make sure that other part of value is already in rd. merge( rd: WritableReg, tmp: WritableReg, offset: Reg, rs: Reg, ty: Type, ) -> SmallInstVec<Inst>1550 pub(crate) fn merge( 1551 rd: WritableReg, 1552 tmp: WritableReg, 1553 offset: Reg, 1554 rs: Reg, 1555 ty: Type, 1556 ) -> SmallInstVec<Inst> { 1557 let mut insts = Self::unset(rd, tmp, offset, ty); 1558 insts.extend(Self::set(rd, tmp, offset, rs, ty)); 1559 insts 1560 } 1561 } 1562 1563 ///Atomic Memory ordering. 1564 #[derive(Copy, Clone, Debug)] 1565 pub enum AMO { 1566 #[allow(dead_code, reason = "used only in emit tests for now")] 1567 Relax = 0b00, 1568 #[allow(dead_code, reason = "used only in emit tests for now")] 1569 Release = 0b01, 1570 #[allow(dead_code, reason = "used only in emit tests for now")] 1571 Acquire = 0b10, 1572 SeqCst = 0b11, 1573 } 1574 1575 impl AMO { to_static_str(self) -> &'static str1576 pub(crate) fn to_static_str(self) -> &'static str { 1577 match self { 1578 AMO::Relax => "", 1579 AMO::Release => ".rl", 1580 AMO::Acquire => ".aq", 1581 AMO::SeqCst => ".aqrl", 1582 } 1583 } as_u32(self) -> u321584 pub(crate) fn as_u32(self) -> u32 { 1585 self as u32 1586 } 1587 } 1588 1589 impl Inst { 1590 /// fence request bits. 1591 pub(crate) const FENCE_REQ_I: u8 = 1 << 3; 1592 pub(crate) const FENCE_REQ_O: u8 = 1 << 2; 1593 pub(crate) const FENCE_REQ_R: u8 = 1 << 1; 1594 pub(crate) const FENCE_REQ_W: u8 = 1 << 0; fence_req_to_string(x: u8) -> String1595 pub(crate) fn fence_req_to_string(x: u8) -> String { 1596 let mut s = String::default(); 1597 if x & Self::FENCE_REQ_I != 0 { 1598 s.push_str("i"); 1599 } 1600 if x & Self::FENCE_REQ_O != 0 { 1601 s.push_str("o"); 1602 } 1603 if x & Self::FENCE_REQ_R != 0 { 1604 s.push_str("r"); 1605 } 1606 if x & Self::FENCE_REQ_W != 0 { 1607 s.push_str("w"); 1608 } 1609 s 1610 } 1611 } 1612 1613 impl CsrRegOP { funct3(self) -> u321614 pub(crate) fn funct3(self) -> u32 { 1615 match self { 1616 CsrRegOP::CsrRW => 0b001, 1617 CsrRegOP::CsrRS => 0b010, 1618 CsrRegOP::CsrRC => 0b011, 1619 } 1620 } 1621 opcode(self) -> u321622 pub(crate) fn opcode(self) -> u32 { 1623 0b1110011 1624 } 1625 name(self) -> &'static str1626 pub(crate) fn name(self) -> &'static str { 1627 match self { 1628 CsrRegOP::CsrRW => "csrrw", 1629 CsrRegOP::CsrRS => "csrrs", 1630 CsrRegOP::CsrRC => "csrrc", 1631 } 1632 } 1633 } 1634 1635 impl Display for CsrRegOP { fmt(&self, f: &mut Formatter<'_>) -> Result1636 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 1637 write!(f, "{}", self.name()) 1638 } 1639 } 1640 1641 impl CsrImmOP { funct3(self) -> u321642 pub(crate) fn funct3(self) -> u32 { 1643 match self { 1644 CsrImmOP::CsrRWI => 0b101, 1645 CsrImmOP::CsrRSI => 0b110, 1646 CsrImmOP::CsrRCI => 0b111, 1647 } 1648 } 1649 opcode(self) -> u321650 pub(crate) fn opcode(self) -> u32 { 1651 0b1110011 1652 } 1653 name(self) -> &'static str1654 pub(crate) fn name(self) -> &'static str { 1655 match self { 1656 CsrImmOP::CsrRWI => "csrrwi", 1657 CsrImmOP::CsrRSI => "csrrsi", 1658 CsrImmOP::CsrRCI => "csrrci", 1659 } 1660 } 1661 } 1662 1663 impl Display for CsrImmOP { fmt(&self, f: &mut Formatter<'_>) -> Result1664 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 1665 write!(f, "{}", self.name()) 1666 } 1667 } 1668 1669 impl CSR { bits(self) -> Imm121670 pub(crate) fn bits(self) -> Imm12 { 1671 Imm12::from_i16(match self { 1672 CSR::Frm => 0x0002, 1673 }) 1674 } 1675 name(self) -> &'static str1676 pub(crate) fn name(self) -> &'static str { 1677 match self { 1678 CSR::Frm => "frm", 1679 } 1680 } 1681 } 1682 1683 impl Display for CSR { fmt(&self, f: &mut Formatter<'_>) -> Result1684 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 1685 write!(f, "{}", self.name()) 1686 } 1687 } 1688 1689 impl COpcodeSpace { bits(&self) -> u321690 pub fn bits(&self) -> u32 { 1691 match self { 1692 COpcodeSpace::C0 => 0b00, 1693 COpcodeSpace::C1 => 0b01, 1694 COpcodeSpace::C2 => 0b10, 1695 } 1696 } 1697 } 1698 1699 impl CrOp { funct4(&self) -> u321700 pub fn funct4(&self) -> u32 { 1701 // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap 1702 match self { 1703 // `c.jr` has the same op/funct4 as C.MV, but RS2 is 0, which is illegal for mv. 1704 CrOp::CMv | CrOp::CJr => 0b1000, 1705 CrOp::CAdd | CrOp::CJalr | CrOp::CEbreak => 0b1001, 1706 } 1707 } 1708 op(&self) -> COpcodeSpace1709 pub fn op(&self) -> COpcodeSpace { 1710 // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap 1711 match self { 1712 CrOp::CMv | CrOp::CAdd | CrOp::CJr | CrOp::CJalr | CrOp::CEbreak => COpcodeSpace::C2, 1713 } 1714 } 1715 } 1716 1717 impl CaOp { funct2(&self) -> u321718 pub fn funct2(&self) -> u32 { 1719 // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes 1720 match self { 1721 CaOp::CAnd => 0b11, 1722 CaOp::COr => 0b10, 1723 CaOp::CXor => 0b01, 1724 CaOp::CSub => 0b00, 1725 CaOp::CAddw => 0b01, 1726 CaOp::CSubw => 0b00, 1727 CaOp::CMul => 0b10, 1728 } 1729 } 1730 funct6(&self) -> u321731 pub fn funct6(&self) -> u32 { 1732 // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes 1733 match self { 1734 CaOp::CAnd | CaOp::COr | CaOp::CXor | CaOp::CSub => 0b100_011, 1735 CaOp::CSubw | CaOp::CAddw | CaOp::CMul => 0b100_111, 1736 } 1737 } 1738 op(&self) -> COpcodeSpace1739 pub fn op(&self) -> COpcodeSpace { 1740 // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap 1741 match self { 1742 CaOp::CAnd 1743 | CaOp::COr 1744 | CaOp::CXor 1745 | CaOp::CSub 1746 | CaOp::CAddw 1747 | CaOp::CSubw 1748 | CaOp::CMul => COpcodeSpace::C1, 1749 } 1750 } 1751 } 1752 1753 impl CjOp { funct3(&self) -> u321754 pub fn funct3(&self) -> u32 { 1755 // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes 1756 match self { 1757 CjOp::CJ => 0b101, 1758 } 1759 } 1760 op(&self) -> COpcodeSpace1761 pub fn op(&self) -> COpcodeSpace { 1762 // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap 1763 match self { 1764 CjOp::CJ => COpcodeSpace::C1, 1765 } 1766 } 1767 } 1768 1769 impl CiOp { funct3(&self) -> u321770 pub fn funct3(&self) -> u32 { 1771 // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes 1772 match self { 1773 CiOp::CAddi | CiOp::CSlli => 0b000, 1774 CiOp::CAddiw | CiOp::CFldsp => 0b001, 1775 CiOp::CLi | CiOp::CLwsp => 0b010, 1776 CiOp::CAddi16sp | CiOp::CLui | CiOp::CLdsp => 0b011, 1777 } 1778 } 1779 op(&self) -> COpcodeSpace1780 pub fn op(&self) -> COpcodeSpace { 1781 // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap 1782 match self { 1783 CiOp::CAddi | CiOp::CAddiw | CiOp::CAddi16sp | CiOp::CLi | CiOp::CLui => { 1784 COpcodeSpace::C1 1785 } 1786 CiOp::CSlli | CiOp::CLwsp | CiOp::CLdsp | CiOp::CFldsp => COpcodeSpace::C2, 1787 } 1788 } 1789 } 1790 1791 impl CiwOp { funct3(&self) -> u321792 pub fn funct3(&self) -> u32 { 1793 // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes 1794 match self { 1795 CiwOp::CAddi4spn => 0b000, 1796 } 1797 } 1798 op(&self) -> COpcodeSpace1799 pub fn op(&self) -> COpcodeSpace { 1800 // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap 1801 match self { 1802 CiwOp::CAddi4spn => COpcodeSpace::C0, 1803 } 1804 } 1805 } 1806 1807 impl CbOp { funct3(&self) -> u321808 pub fn funct3(&self) -> u32 { 1809 // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes 1810 match self { 1811 CbOp::CSrli | CbOp::CSrai | CbOp::CAndi => 0b100, 1812 } 1813 } 1814 funct2(&self) -> u321815 pub fn funct2(&self) -> u32 { 1816 // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes 1817 match self { 1818 CbOp::CSrli => 0b00, 1819 CbOp::CSrai => 0b01, 1820 CbOp::CAndi => 0b10, 1821 } 1822 } 1823 op(&self) -> COpcodeSpace1824 pub fn op(&self) -> COpcodeSpace { 1825 // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap 1826 match self { 1827 CbOp::CSrli | CbOp::CSrai | CbOp::CAndi => COpcodeSpace::C1, 1828 } 1829 } 1830 } 1831 1832 impl CssOp { funct3(&self) -> u321833 pub fn funct3(&self) -> u32 { 1834 // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes 1835 match self { 1836 CssOp::CFsdsp => 0b101, 1837 CssOp::CSwsp => 0b110, 1838 CssOp::CSdsp => 0b111, 1839 } 1840 } 1841 op(&self) -> COpcodeSpace1842 pub fn op(&self) -> COpcodeSpace { 1843 // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap 1844 match self { 1845 CssOp::CSwsp | CssOp::CSdsp | CssOp::CFsdsp => COpcodeSpace::C2, 1846 } 1847 } 1848 } 1849 1850 impl CsOp { funct3(&self) -> u321851 pub fn funct3(&self) -> u32 { 1852 // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes 1853 match self { 1854 CsOp::CFsd => 0b101, 1855 CsOp::CSw => 0b110, 1856 CsOp::CSd => 0b111, 1857 } 1858 } 1859 op(&self) -> COpcodeSpace1860 pub fn op(&self) -> COpcodeSpace { 1861 // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap 1862 match self { 1863 CsOp::CSw | CsOp::CSd | CsOp::CFsd => COpcodeSpace::C0, 1864 } 1865 } 1866 } 1867 1868 impl ClOp { funct3(&self) -> u321869 pub fn funct3(&self) -> u32 { 1870 // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes 1871 match self { 1872 ClOp::CFld => 0b001, 1873 ClOp::CLw => 0b010, 1874 ClOp::CLd => 0b011, 1875 } 1876 } 1877 op(&self) -> COpcodeSpace1878 pub fn op(&self) -> COpcodeSpace { 1879 // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap 1880 match self { 1881 ClOp::CLw | ClOp::CLd | ClOp::CFld => COpcodeSpace::C0, 1882 } 1883 } 1884 } 1885 1886 impl CsznOp { funct6(&self) -> u321887 pub fn funct6(&self) -> u32 { 1888 // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes 1889 match self { 1890 CsznOp::CNot 1891 | CsznOp::CZextw 1892 | CsznOp::CZextb 1893 | CsznOp::CZexth 1894 | CsznOp::CSextb 1895 | CsznOp::CSexth => 0b100_111, 1896 } 1897 } 1898 funct5(&self) -> u321899 pub fn funct5(&self) -> u32 { 1900 // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes 1901 match self { 1902 CsznOp::CNot => 0b11_101, 1903 CsznOp::CZextb => 0b11_000, 1904 CsznOp::CZexth => 0b11_010, 1905 CsznOp::CZextw => 0b11_100, 1906 CsznOp::CSextb => 0b11_001, 1907 CsznOp::CSexth => 0b11_011, 1908 } 1909 } 1910 op(&self) -> COpcodeSpace1911 pub fn op(&self) -> COpcodeSpace { 1912 // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap 1913 match self { 1914 CsznOp::CNot 1915 | CsznOp::CZextb 1916 | CsznOp::CZexth 1917 | CsznOp::CZextw 1918 | CsznOp::CSextb 1919 | CsznOp::CSexth => COpcodeSpace::C1, 1920 } 1921 } 1922 } 1923 1924 impl ZcbMemOp { funct6(&self) -> u321925 pub fn funct6(&self) -> u32 { 1926 // https://github.com/michaeljclark/riscv-meta/blob/master/opcodes 1927 match self { 1928 ZcbMemOp::CLbu => 0b100_000, 1929 // These two opcodes are differentiated in the imm field of the instruction. 1930 ZcbMemOp::CLhu | ZcbMemOp::CLh => 0b100_001, 1931 ZcbMemOp::CSb => 0b100_010, 1932 ZcbMemOp::CSh => 0b100_011, 1933 } 1934 } 1935 imm_bits(&self) -> u81936 pub fn imm_bits(&self) -> u8 { 1937 match self { 1938 ZcbMemOp::CLhu | ZcbMemOp::CLh | ZcbMemOp::CSh => 1, 1939 ZcbMemOp::CLbu | ZcbMemOp::CSb => 2, 1940 } 1941 } 1942 op(&self) -> COpcodeSpace1943 pub fn op(&self) -> COpcodeSpace { 1944 // https://five-embeddev.com/riscv-isa-manual/latest/rvc-opcode-map.html#rvcopcodemap 1945 match self { 1946 ZcbMemOp::CLbu | ZcbMemOp::CLhu | ZcbMemOp::CLh | ZcbMemOp::CSb | ZcbMemOp::CSh => { 1947 COpcodeSpace::C0 1948 } 1949 } 1950 } 1951 } 1952