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