168 lines
5.5 KiB
Rust
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
|
|
}
|