cpu/crates/cpu/tests/simple_power_isa_decoder/test_cases.rs

168 lines
5.5 KiB
Rust

// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use cpu::{instruction::MOp, util::array_vec::ArrayVec};
use fayalite::prelude::*;
use std::fmt;
mod branch;
mod condition_register;
mod fixed_point_arithmetic;
mod fixed_point_compare;
mod fixed_point_load;
mod fixed_point_logical;
mod fixed_point_rotate_and_shift;
mod fixed_point_store;
mod move_to_from_system_register;
mod prefixed_no_operation;
#[hdl(get(|_| 3))]
pub type TestCaseOutputLen<C: PhantomConstGet<()>> = DynSize;
pub struct TestCase {
pub mnemonic: &'static str,
pub first_input: u32,
pub second_input: Option<u32>,
pub output: SimValue<ArrayVec<TraceAsString<MOp>, TestCaseOutputLen<PhantomConst<()>>>>,
pub loc: &'static std::panic::Location<'static>,
}
impl TestCase {
pub fn output_ty() -> ArrayVec<TraceAsString<MOp>, TestCaseOutputLen<PhantomConst<()>>> {
ArrayVec[TraceAsString[MOp]][TestCaseOutputLen[PhantomConst::default()]]
}
}
impl fmt::Debug for TestCase {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
mnemonic,
first_input,
second_input,
output,
loc,
} = self;
let mut debug_struct = f.debug_struct("TestCase");
debug_struct
.field("mnemonic", mnemonic)
.field("first_input", &format_args!("0x{first_input:08x}"));
if let Some(second_input) = second_input {
debug_struct.field("second_input", &format_args!("0x{second_input:08x}"));
} else {
debug_struct.field("second_input", &format_args!("None"));
}
debug_struct
.field("output", &ArrayVec::elements_sim_ref(output))
.field("loc", &format_args!("{loc}"))
.finish()
}
}
#[inline(never)] // prevent stack overflow
#[track_caller]
fn insn_empty(mnemonic: &'static str, first_input: u32, second_input: Option<u32>) -> TestCase {
let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
.zero()
.cast_bits_to(MOp)
.into_trace_as_string();
TestCase {
mnemonic,
first_input,
second_input,
output: TestCase::output_ty().new_sim(zero_mop),
loc: std::panic::Location::caller(),
}
}
#[inline(never)] // prevent stack overflow
#[track_caller]
fn insn_single<T: ToSimValue<Type = MOp>>(
mnemonic: &'static str,
first_input: u32,
second_input: Option<u32>,
// use a closure to avoid having too many variables in one function causing a stack overflow
output: impl FnOnce() -> T,
) -> TestCase {
let mut retval = insn_empty(mnemonic, first_input, second_input);
ArrayVec::try_push_sim(
&mut retval.output,
output().into_sim_value().into_trace_as_string(),
)
.expect("known to have space");
retval
}
#[inline(never)] // prevent stack overflow
#[track_caller]
fn insn_double<T: ToSimValue<Type = MOp>>(
mnemonic: &'static str,
first_input: u32,
second_input: Option<u32>,
// use a closure to avoid having too many variables in one function causing a stack overflow
insns: impl FnOnce() -> [T; 2],
) -> TestCase {
let mut retval = insn_empty(mnemonic, first_input, second_input);
let [insn0, insn1] = insns();
ArrayVec::try_push_sim(
&mut retval.output,
insn0.into_sim_value().into_trace_as_string(),
)
.expect("known to have space");
ArrayVec::try_push_sim(
&mut retval.output,
insn1.into_sim_value().into_trace_as_string(),
)
.expect("known to have space");
retval
}
#[inline(never)] // prevent stack overflow
#[track_caller]
fn insn_triple<T: ToSimValue<Type = MOp>>(
mnemonic: &'static str,
first_input: u32,
second_input: Option<u32>,
// use a closure to avoid having too many variables in one function causing a stack overflow
insns: impl FnOnce() -> [T; 3],
) -> TestCase {
let mut retval = insn_empty(mnemonic, first_input, second_input);
let [insn0, insn1, insn2] = insns();
ArrayVec::try_push_sim(
&mut retval.output,
insn0.into_sim_value().into_trace_as_string(),
)
.expect("known to have space");
ArrayVec::try_push_sim(
&mut retval.output,
insn1.into_sim_value().into_trace_as_string(),
)
.expect("known to have space");
ArrayVec::try_push_sim(
&mut retval.output,
insn2.into_sim_value().into_trace_as_string(),
)
.expect("known to have space");
retval
}
pub fn test_cases() -> Vec<TestCase> {
let mut retval = Vec::new();
branch::test_cases_book_i_2_4_branch(&mut retval);
condition_register::test_cases_book_i_2_5_condition_register(&mut retval);
fixed_point_load::test_cases_book_i_3_3_2_fixed_point_load(&mut retval);
fixed_point_store::test_cases_book_i_3_3_3_fixed_point_store(&mut retval);
fixed_point_arithmetic::test_cases_book_i_3_3_9_fixed_point_arithmetic(&mut retval);
fixed_point_compare::test_cases_book_i_3_3_10_fixed_point_compare(&mut retval);
fixed_point_logical::test_cases_book_i_3_3_13_fixed_point_logical(&mut retval);
fixed_point_rotate_and_shift::test_cases_book_i_3_3_14_fixed_point_rotate_and_shift(
&mut retval,
);
move_to_from_system_register::test_cases_book_i_3_3_19_move_to_from_system_register(
&mut retval,
);
prefixed_no_operation::test_cases_book_i_3_3_20_prefixed_no_operation(&mut retval);
move_to_from_system_register::test_cases_book_iii_5_4_4_move_to_from_system_register(
&mut retval,
);
retval
}