bf421d6ddb872a534d47cb0668657f5a3a644bec
[power-instruction-analyzer.git] / src / main.rs
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // See Notices.txt for copyright information
3
4 use power_instruction_analyzer::{
5 CarryFlags, Instr, InstructionInput, InstructionInputRegister, MissingInstructionInput,
6 OverflowFlags, TestCase, WholeTest,
7 };
8
9 const TEST_VALUES: &[u64] = &[
10 0x0,
11 0x1,
12 0x2,
13 0xFFFF_FFFF_FFFF_FFFF,
14 0xFFFF_FFFF_FFFF_FFFE,
15 0x7FFF_FFFF_FFFF_FFFE,
16 0x7FFF_FFFF_FFFF_FFFF,
17 0x8000_0000_0000_0000,
18 0x8000_0000_0000_0001,
19 0x1234_5678_0000_0000,
20 0x1234_5678_7FFF_FFFE,
21 0x1234_5678_7FFF_FFFF,
22 0x1234_5678_8000_0000,
23 0x1234_5678_8000_0001,
24 0x1234_5678_FFFF_FFFF,
25 0x7FFE,
26 0x7FFF,
27 0x8000,
28 0x8001,
29 ];
30
31 const IMMED16_TEST_VALUES: &[u16] = &[
32 0x0, 0x1, 0x2, 0xFFFF, 0xFFFE, 0x7FFE, 0x7FFF, 0x8000, 0x8001,
33 ];
34
35 const BOOL_VALUES: &[bool] = &[false, true];
36
37 fn call_with_inputs(
38 mut inputs: InstructionInput,
39 input_registers: &[InstructionInputRegister],
40 f: &mut impl FnMut(InstructionInput) -> Result<(), MissingInstructionInput>,
41 ) -> Result<(), MissingInstructionInput> {
42 if let Some((&input_register, input_registers)) = input_registers.split_first() {
43 match input_register {
44 InstructionInputRegister::Ra => {
45 for &i in TEST_VALUES {
46 inputs.ra = Some(i);
47 call_with_inputs(inputs, input_registers, f)?;
48 }
49 }
50 InstructionInputRegister::Rb => {
51 for &i in TEST_VALUES {
52 inputs.rb = Some(i);
53 call_with_inputs(inputs, input_registers, f)?;
54 }
55 }
56 InstructionInputRegister::Rc => {
57 for &i in TEST_VALUES {
58 inputs.rc = Some(i);
59 call_with_inputs(inputs, input_registers, f)?;
60 }
61 }
62 InstructionInputRegister::ImmediateS16 => {
63 for &i in IMMED16_TEST_VALUES {
64 inputs.immediate = Some(i as i16 as u64);
65 call_with_inputs(inputs, input_registers, f)?;
66 }
67 }
68 InstructionInputRegister::ImmediateU16 => {
69 for &i in IMMED16_TEST_VALUES {
70 inputs.immediate = Some(i as u64);
71 call_with_inputs(inputs, input_registers, f)?;
72 }
73 }
74 InstructionInputRegister::Carry => {
75 for &ca in BOOL_VALUES {
76 for &ca32 in BOOL_VALUES {
77 inputs.carry = Some(CarryFlags { ca, ca32 });
78 call_with_inputs(inputs, input_registers, f)?;
79 }
80 }
81 }
82 InstructionInputRegister::Overflow => {
83 for &so in BOOL_VALUES {
84 for &ov in BOOL_VALUES {
85 for &ov32 in BOOL_VALUES {
86 inputs.overflow = Some(OverflowFlags { so, ov, ov32 });
87 call_with_inputs(inputs, input_registers, f)?;
88 }
89 }
90 }
91 }
92 }
93 } else {
94 f(inputs)?;
95 }
96 Ok(())
97 }
98
99 fn main() -> Result<(), String> {
100 let mut test_cases = Vec::new();
101 let mut any_model_mismatch = false;
102 for &instr in Instr::VALUES {
103 call_with_inputs(
104 InstructionInput::default(),
105 instr.get_used_input_registers(),
106 &mut |inputs| -> Result<(), _> {
107 let model_outputs = instr.get_model_fn()(inputs)?;
108 #[cfg(feature = "native_instrs")]
109 let native_outputs = Some(instr.get_native_fn()(inputs)?);
110 #[cfg(not(feature = "native_instrs"))]
111 let native_outputs = None;
112 let model_mismatch = match native_outputs {
113 Some(native_outputs) if native_outputs != model_outputs => true,
114 _ => false,
115 };
116 any_model_mismatch |= model_mismatch;
117 test_cases.push(TestCase {
118 instr,
119 inputs,
120 native_outputs,
121 model_outputs,
122 model_mismatch,
123 });
124 Ok(())
125 },
126 )
127 .map_err(|err| format!("instruction {}: {}", instr.name(), err))?;
128 }
129 let whole_test = WholeTest {
130 test_cases,
131 any_model_mismatch,
132 };
133 serde_json::to_writer_pretty(std::io::stdout().lock(), &whole_test).unwrap();
134 println!();
135 Ok(())
136 }