1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // See Notices.txt for copyright information
4 #![cfg_attr(feature = "native_instrs", feature(llvm_asm))]
6 #[cfg(all(feature = "native_instrs", not(target_arch = "powerpc64")))]
7 compile_error!("native_instrs feature requires target_arch to be powerpc64");
12 use serde::{Deserialize, Serialize};
16 ops::{Index, IndexMut},
18 use serde_plain::forward_display_to_serde;
20 fn is_default<T: Default + PartialEq>(v: &T) -> bool {
24 // powerpc bit numbers count from MSB to LSB
25 const fn get_xer_bit_mask(powerpc_bit_num: usize) -> u64 {
26 (1 << 63) >> powerpc_bit_num
29 macro_rules! xer_subset {
31 $struct_vis:vis struct $struct_name:ident {
33 #[bit($powerpc_bit_num:expr, $mask_name:ident)]
34 $field_vis:vis $field_name:ident: bool,
38 #[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
39 $struct_vis struct $struct_name {
41 $field_vis $field_name: bool,
47 $field_vis const $mask_name: u64 = get_xer_bit_mask($powerpc_bit_num);
49 pub const fn from_xer(xer: u64) -> Self {
52 $field_name: (xer & Self::$mask_name) != 0,
56 pub const fn to_xer(self) -> u64 {
57 let mut retval = 0u64;
60 retval |= Self::$mask_name;
70 pub struct OverflowFlags {
71 #[bit(32, XER_SO_MASK)]
73 #[bit(33, XER_OV_MASK)]
75 #[bit(44, XER_OV32_MASK)]
81 pub const fn from_overflow(overflow: bool) -> Self {
91 pub struct CarryFlags {
92 #[bit(34, XER_CA_MASK)]
94 #[bit(45, XER_CA32_MASK)]
99 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
100 pub struct ConditionRegister {
107 impl ConditionRegister {
108 pub const fn from_4_bits(bits: u8) -> Self {
109 // assert bits is 4-bits long
110 // can switch to using assert! once rustc feature const_panic is stabilized
111 [0; 0x10][bits as usize];
120 pub const CR_FIELD_COUNT: usize = 8;
121 pub const fn from_cr_field(cr: u32, field_index: usize) -> Self {
122 // assert field_index is less than CR_FIELD_COUNT
123 // can switch to using assert! once rustc feature const_panic is stabilized
124 [0; Self::CR_FIELD_COUNT][field_index];
126 let reversed_field_index = Self::CR_FIELD_COUNT - field_index - 1;
127 let bits = (cr >> (4 * reversed_field_index)) & 0xF;
128 Self::from_4_bits(bits as u8)
130 pub fn from_signed_int<T: Ord + Default>(value: T, so: bool) -> Self {
131 let ordering = value.cmp(&T::default());
133 lt: ordering == Ordering::Less,
134 gt: ordering == Ordering::Greater,
135 eq: ordering == Ordering::Equal,
141 #[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
142 pub struct InstructionResult {
145 skip_serializing_if = "Option::is_none",
146 with = "serde_hex::SerdeHex"
149 #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
150 pub overflow: Option<OverflowFlags>,
151 #[serde(default, flatten, skip_serializing_if = "Option::is_none")]
152 pub carry: Option<CarryFlags>,
153 #[serde(default, skip_serializing_if = "Option::is_none")]
154 pub cr0: Option<ConditionRegister>,
155 #[serde(default, skip_serializing_if = "Option::is_none")]
156 pub cr1: Option<ConditionRegister>,
157 #[serde(default, skip_serializing_if = "Option::is_none")]
158 pub cr2: Option<ConditionRegister>,
159 #[serde(default, skip_serializing_if = "Option::is_none")]
160 pub cr3: Option<ConditionRegister>,
161 #[serde(default, skip_serializing_if = "Option::is_none")]
162 pub cr4: Option<ConditionRegister>,
163 #[serde(default, skip_serializing_if = "Option::is_none")]
164 pub cr5: Option<ConditionRegister>,
165 #[serde(default, skip_serializing_if = "Option::is_none")]
166 pub cr6: Option<ConditionRegister>,
167 #[serde(default, skip_serializing_if = "Option::is_none")]
168 pub cr7: Option<ConditionRegister>,
172 pub struct MissingInstructionInput {
173 pub input: InstructionInputRegister,
176 impl fmt::Display for MissingInstructionInput {
177 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178 write!(f, "missing instruction input: {}", self.input)
182 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
183 pub enum InstructionInputRegister {
184 #[serde(rename = "ra")]
186 #[serde(rename = "rb")]
188 #[serde(rename = "rc")]
190 #[serde(rename = "ca")]
194 forward_display_to_serde!(InstructionInputRegister);
196 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
197 pub struct InstructionInput {
198 #[serde(with = "serde_hex::SerdeHex")]
202 skip_serializing_if = "Option::is_none",
203 with = "serde_hex::SerdeHex"
208 skip_serializing_if = "Option::is_none",
209 with = "serde_hex::SerdeHex"
212 #[serde(default, skip_serializing_if = "Option::is_none", flatten)]
213 pub carry: Option<CarryFlags>,
216 fn is_false(v: &bool) -> bool {
220 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
221 pub struct TestCase {
224 pub inputs: InstructionInput,
225 #[serde(default, skip_serializing_if = "Option::is_none")]
226 pub native_outputs: Option<InstructionResult>,
227 pub model_outputs: InstructionResult,
228 #[serde(default, skip_serializing_if = "is_false")]
229 pub model_mismatch: bool,
232 #[derive(Clone, Debug, Serialize, Deserialize)]
233 pub struct WholeTest {
234 #[serde(default, skip_serializing_if = "Vec::is_empty")]
235 pub test_cases: Vec<TestCase>,
236 pub any_model_mismatch: bool,
239 #[cfg(feature = "native_instrs")]
240 macro_rules! map_instr_asm_args {
244 ([], [], [$string0:literal $($strings:literal)*]) => {
245 concat!(" ", $string0, $(", ", $strings),*)
247 ([$($args:ident)*], [rt $($results:ident)*], [$($strings:literal)*]) => {
248 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)* "$0"])
250 ([ra $($args:ident)*], [$($results:ident)*], [$($strings:literal)*]) => {
251 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)* "$3"])
253 ([rb $($args:ident)*], [$($results:ident)*], [$($strings:literal)*]) => {
254 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)* "$4"])
256 ([rc $($args:ident)*], [$($results:ident)*], [$($strings:literal)*]) => {
257 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)* "$5"])
259 ([$($args:ident)*], [ov $($results:ident)*], [$($strings:literal)*]) => {
260 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
262 ([$($args:ident)*], [cr0 $($results:ident)*], [$($strings:literal)*]) => {
263 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
265 ([$($args:ident)*], [cr1 $($results:ident)*], [$($strings:literal)*]) => {
266 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
268 ([$($args:ident)*], [cr2 $($results:ident)*], [$($strings:literal)*]) => {
269 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
271 ([$($args:ident)*], [cr3 $($results:ident)*], [$($strings:literal)*]) => {
272 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
274 ([$($args:ident)*], [cr4 $($results:ident)*], [$($strings:literal)*]) => {
275 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
277 ([$($args:ident)*], [cr5 $($results:ident)*], [$($strings:literal)*]) => {
278 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
280 ([$($args:ident)*], [cr6 $($results:ident)*], [$($strings:literal)*]) => {
281 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
283 ([$($args:ident)*], [cr7 $($results:ident)*], [$($strings:literal)*]) => {
284 map_instr_asm_args!([$($args)*], [$($results)*], [$($strings)*])
288 macro_rules! map_instr_input_registers {
289 ([], [$($reg:expr,)*]) => {
292 ([ra $($args:ident)*], [$($reg:expr,)*]) => {
293 map_instr_input_registers!([$($args)*], [InstructionInputRegister::Ra, $($reg,)*])
295 ([rb $($args:ident)*], [$($reg:expr,)*]) => {
296 map_instr_input_registers!([$($args)*], [InstructionInputRegister::Rb, $($reg,)*])
298 ([rc $($args:ident)*], [$($reg:expr,)*]) => {
299 map_instr_input_registers!([$($args)*], [InstructionInputRegister::Rc, $($reg,)*])
303 #[cfg(feature = "native_instrs")]
304 macro_rules! map_instr_results {
305 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, []) => {};
306 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [rt $($args:ident)*]) => {
307 $retval.rt = Some($rt);
308 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
310 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [ov $($args:ident)*]) => {
311 $retval.overflow = Some(OverflowFlags::from_xer($xer));
312 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
314 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr0 $($args:ident)*]) => {
315 $retval.cr0 = Some(ConditionRegister::from_cr_field($cr, 0));
316 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
318 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr1 $($args:ident)*]) => {
319 $retval.cr1 = Some(ConditionRegister::from_cr_field($cr, 1));
320 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
322 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr2 $($args:ident)*]) => {
323 $retval.cr2 = Some(ConditionRegister::from_cr_field($cr, 2));
324 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
326 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr3 $($args:ident)*]) => {
327 $retval.cr3 = Some(ConditionRegister::from_cr_field($cr, 3));
328 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
330 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr4 $($args:ident)*]) => {
331 $retval.cr4 = Some(ConditionRegister::from_cr_field($cr, 4));
332 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
334 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr5 $($args:ident)*]) => {
335 $retval.cr5 = Some(ConditionRegister::from_cr_field($cr, 5));
336 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
338 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr6 $($args:ident)*]) => {
339 $retval.cr6 = Some(ConditionRegister::from_cr_field($cr, 6));
340 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
342 ($rt:ident, $xer:ident, $cr:ident, $retval:ident, [cr7 $($args:ident)*]) => {
343 $retval.cr7 = Some(ConditionRegister::from_cr_field($cr, 7));
344 map_instr_results!($rt, $xer, $cr, $retval, [$($args)*]);
348 #[cfg(feature = "native_instrs")]
351 #[enumerant = $enumerant:ident]
352 fn $fn:ident($($args:ident),*) -> ($($results:ident),*) {
356 pub fn $fn(inputs: InstructionInput) -> InstructionResult {
357 #![allow(unused_variables, unused_assignments)]
358 let InstructionInput {
373 map_instr_asm_args!([$($args)*], [$($results)*], []),
378 : "=&b"(rt), "=&b"(xer), "=&b"(cr)
379 : "b"(ra), "b"(rb), "b"(rc), "b"(0u64), "b"(!0x8000_0000u64)
382 let mut retval = InstructionResult::default();
383 map_instr_results!(rt, xer, cr, retval, [$($results)*]);
389 macro_rules! instrs {
392 #[enumerant = $enumerant:ident]
393 fn $fn:ident($($args:ident),*) -> ($($results:ident),*) {
398 #[cfg(feature = "python")]
399 macro_rules! wrap_all_instr_fns {
404 $(fn $fn(inputs: InstructionInput) -> InstructionResult;)*
409 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
412 #[serde(rename = $instr)]
418 #[cfg(feature = "native_instrs")]
419 pub fn get_native_fn(self) -> fn(InstructionInput) -> InstructionResult {
422 Self::$enumerant => native_instrs::$fn,
426 pub fn get_model_fn(self) -> fn(InstructionInput) -> InstructionResult {
429 Self::$enumerant => instr_models::$fn,
433 pub fn get_used_input_registers(self) -> &'static [InstructionInputRegister] {
436 Self::$enumerant => &map_instr_input_registers!([$($args)*], []),
440 pub fn name(self) -> &'static str {
443 Self::$enumerant => $instr,
447 pub const VALUES: &'static [Self] = &[
454 #[cfg(feature = "native_instrs")]
455 pub mod native_instrs {
460 #[enumerant = $enumerant]
461 fn $fn($($args),*) -> ($($results),*) {
473 fn add(ra, rb) -> (rt) {
477 fn addo(ra, rb) -> (rt, ov) {
481 fn add_(ra, rb) -> (rt, cr0) {
485 fn addo_(ra, rb) -> (rt, ov, cr0) {
491 fn subf(ra, rb) -> (rt) {
495 fn subfo(ra, rb) -> (rt, ov) {
499 fn subf_(ra, rb) -> (rt, cr0) {
502 #[enumerant = SubFO_]
503 fn subfo_(ra, rb) -> (rt, ov, cr0) {
509 fn divde(ra, rb) -> (rt) {
512 #[enumerant = DivDEO]
513 fn divdeo(ra, rb) -> (rt, ov) {
516 #[enumerant = DivDE_]
517 fn divde_(ra, rb) -> (rt, cr0) {
520 #[enumerant = DivDEO_]
521 fn divdeo_(ra, rb) -> (rt, ov, cr0) {
526 #[enumerant = DivDEU]
527 fn divdeu(ra, rb) -> (rt) {
530 #[enumerant = DivDEUO]
531 fn divdeuo(ra, rb) -> (rt, ov) {
534 #[enumerant = DivDEU_]
535 fn divdeu_(ra, rb) -> (rt, cr0) {
538 #[enumerant = DivDEUO_]
539 fn divdeuo_(ra, rb) -> (rt, ov, cr0) {
545 fn divd(ra, rb) -> (rt) {
549 fn divdo(ra, rb) -> (rt, ov) {
553 fn divd_(ra, rb) -> (rt, cr0) {
556 #[enumerant = DivDO_]
557 fn divdo_(ra, rb) -> (rt, ov, cr0) {
563 fn divdu(ra, rb) -> (rt) {
566 #[enumerant = DivDUO]
567 fn divduo(ra, rb) -> (rt, ov) {
570 #[enumerant = DivDU_]
571 fn divdu_(ra, rb) -> (rt, cr0) {
574 #[enumerant = DivDUO_]
575 fn divduo_(ra, rb) -> (rt, ov, cr0) {
581 fn divwe(ra, rb) -> (rt) {
584 #[enumerant = DivWEO]
585 fn divweo(ra, rb) -> (rt, ov) {
588 #[enumerant = DivWE_]
589 fn divwe_(ra, rb) -> (rt, cr0) {
592 #[enumerant = DivWEO_]
593 fn divweo_(ra, rb) -> (rt, ov, cr0) {
598 #[enumerant = DivWEU]
599 fn divweu(ra, rb) -> (rt) {
602 #[enumerant = DivWEUO]
603 fn divweuo(ra, rb) -> (rt, ov) {
606 #[enumerant = DivWEU_]
607 fn divweu_(ra, rb) -> (rt, cr0) {
610 #[enumerant = DivWEUO_]
611 fn divweuo_(ra, rb) -> (rt, ov, cr0) {
617 fn divw(ra, rb) -> (rt) {
621 fn divwo(ra, rb) -> (rt, ov) {
625 fn divw_(ra, rb) -> (rt, cr0) {
628 #[enumerant = DivWO_]
629 fn divwo_(ra, rb) -> (rt, ov, cr0) {
635 fn divwu(ra, rb) -> (rt) {
638 #[enumerant = DivWUO]
639 fn divwuo(ra, rb) -> (rt, ov) {
642 #[enumerant = DivWU_]
643 fn divwu_(ra, rb) -> (rt, cr0) {
646 #[enumerant = DivWUO_]
647 fn divwuo_(ra, rb) -> (rt, ov, cr0) {
653 fn modsd(ra, rb) -> (rt) {
657 fn modud(ra, rb) -> (rt) {
661 fn modsw(ra, rb) -> (rt) {
665 fn moduw(ra, rb) -> (rt) {
671 fn mullw(ra, rb) -> (rt) {
674 #[enumerant = MulLWO]
675 fn mullwo(ra, rb) -> (rt, ov) {
678 #[enumerant = MulLW_]
679 fn mullw_(ra, rb) -> (rt, cr0) {
682 #[enumerant = MulLWO_]
683 fn mullwo_(ra, rb) -> (rt, ov, cr0) {
689 fn mulhw(ra, rb) -> (rt) {
692 #[enumerant = MulHW_]
693 fn mulhw_(ra, rb) -> (rt, cr0) {
698 #[enumerant = MulHWU]
699 fn mulhwu(ra, rb) -> (rt) {
702 #[enumerant = MulHWU_]
703 fn mulhwu_(ra, rb) -> (rt, cr0) {
709 fn mulld(ra, rb) -> (rt) {
712 #[enumerant = MulLDO]
713 fn mulldo(ra, rb) -> (rt, ov) {
716 #[enumerant = MulLD_]
717 fn mulld_(ra, rb) -> (rt, cr0) {
720 #[enumerant = MulLDO_]
721 fn mulldo_(ra, rb) -> (rt, ov, cr0) {
727 fn mulhd(ra, rb) -> (rt) {
730 #[enumerant = MulHD_]
731 fn mulhd_(ra, rb) -> (rt, cr0) {
736 #[enumerant = MulHDU]
737 fn mulhdu(ra, rb) -> (rt) {
740 #[enumerant = MulHDU_]
741 fn mulhdu_(ra, rb) -> (rt, cr0) {
746 #[enumerant = MAddHD]
747 fn maddhd(ra, rb, rc) -> (rt) {
750 #[enumerant = MAddHDU]
751 fn maddhdu(ra, rb, rc) -> (rt) {
754 #[enumerant = MAddLD]
755 fn maddld(ra, rb, rc) -> (rt) {
760 // must be after instrs macro call since it uses a macro definition
764 // must be after instrs macro call since it uses a macro definition