f6fd4ac1e1555bfeb70a896fa000feb8ea867cb7
[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_FFFF,
16 0x8000_0000_0000_0000,
17 0x1234_5678_0000_0000,
18 0x1234_5678_8000_0000,
19 0x1234_5678_FFFF_FFFF,
20 0x1234_5678_7FFF_FFFF,
21 ];
22
23 const BOOL_VALUES: &[bool] = &[false, true];
24
25 fn call_with_inputs(
26 mut inputs: InstructionInput,
27 input_registers: &[InstructionInputRegister],
28 f: &mut impl FnMut(InstructionInput) -> Result<(), MissingInstructionInput>,
29 ) -> Result<(), MissingInstructionInput> {
30 if let Some((&input_register, input_registers)) = input_registers.split_first() {
31 match input_register {
32 InstructionInputRegister::Ra => {
33 for &i in TEST_VALUES {
34 inputs.ra = Some(i);
35 call_with_inputs(inputs, input_registers, f)?;
36 }
37 }
38 InstructionInputRegister::Rb => {
39 for &i in TEST_VALUES {
40 inputs.rb = Some(i);
41 call_with_inputs(inputs, input_registers, f)?;
42 }
43 }
44 InstructionInputRegister::Rc => {
45 for &i in TEST_VALUES {
46 inputs.rc = Some(i);
47 call_with_inputs(inputs, input_registers, f)?;
48 }
49 }
50 InstructionInputRegister::Carry => {
51 for &ca in BOOL_VALUES {
52 for &ca32 in BOOL_VALUES {
53 inputs.carry = Some(CarryFlags { ca, ca32 });
54 call_with_inputs(inputs, input_registers, f)?;
55 }
56 }
57 }
58 InstructionInputRegister::Overflow => {
59 for &so in BOOL_VALUES {
60 for &ov in BOOL_VALUES {
61 for &ov32 in BOOL_VALUES {
62 inputs.overflow = Some(OverflowFlags { so, ov, ov32 });
63 call_with_inputs(inputs, input_registers, f)?;
64 }
65 }
66 }
67 }
68 }
69 } else {
70 f(inputs)?;
71 }
72 Ok(())
73 }
74
75 fn main() -> Result<(), String> {
76 let mut test_cases = Vec::new();
77 let mut any_model_mismatch = false;
78 for &instr in Instr::VALUES {
79 call_with_inputs(
80 InstructionInput::default(),
81 instr.get_used_input_registers(),
82 &mut |inputs| -> Result<(), _> {
83 let model_outputs = instr.get_model_fn()(inputs)?;
84 #[cfg(feature = "native_instrs")]
85 let native_outputs = Some(instr.get_native_fn()(inputs)?);
86 #[cfg(not(feature = "native_instrs"))]
87 let native_outputs = None;
88 let model_mismatch = match native_outputs {
89 Some(native_outputs) if native_outputs != model_outputs => true,
90 _ => false,
91 };
92 any_model_mismatch |= model_mismatch;
93 test_cases.push(TestCase {
94 instr,
95 inputs,
96 native_outputs,
97 model_outputs,
98 model_mismatch,
99 });
100 Ok(())
101 },
102 )
103 .map_err(|err| format!("instruction {}: {}", instr.name(), err))?;
104 }
105 let whole_test = WholeTest {
106 test_cases,
107 any_model_mismatch,
108 };
109 serde_json::to_writer_pretty(std::io::stdout().lock(), &whole_test).unwrap();
110 println!();
111 Ok(())
112 }