forked from libre-chip/cpu
decodes an addi instruction
This commit is contained in:
parent
6d40eaadb3
commit
b7b6a02777
4 changed files with 1560 additions and 399 deletions
|
|
@ -2,7 +2,7 @@
|
|||
// See Notices.txt for copyright information
|
||||
|
||||
use cpu::{
|
||||
decoder::simple_power_isa::decode_one_32bit_insn,
|
||||
decoder::simple_power_isa::decode_one_insn,
|
||||
instruction::{AddSubMOp, MOp, MOpDestReg, MOpRegNum, OutputIntegerMode},
|
||||
util::array_vec::ArrayVec,
|
||||
};
|
||||
|
|
@ -15,7 +15,8 @@ use std::{
|
|||
|
||||
struct TestCase {
|
||||
mnemonic: &'static str,
|
||||
input: u32,
|
||||
first_input: u32,
|
||||
second_input: Option<u32>,
|
||||
output: SimValue<ArrayVec<MOp, ConstUsize<2>>>,
|
||||
loc: &'static std::panic::Location<'static>,
|
||||
}
|
||||
|
|
@ -24,13 +25,21 @@ impl fmt::Debug for TestCase {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self {
|
||||
mnemonic,
|
||||
input,
|
||||
first_input,
|
||||
second_input,
|
||||
output,
|
||||
loc,
|
||||
} = self;
|
||||
f.debug_struct("TestCase")
|
||||
let mut debug_struct = f.debug_struct("TestCase");
|
||||
debug_struct
|
||||
.field("mnemonic", mnemonic)
|
||||
.field("input", &format_args!("0x{input:08x}"))
|
||||
.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()
|
||||
|
|
@ -43,7 +52,8 @@ fn test_cases() -> Vec<TestCase> {
|
|||
#[track_caller]
|
||||
fn insn_single(
|
||||
mnemonic: &'static str,
|
||||
input: u32,
|
||||
first_input: u32,
|
||||
second_input: Option<u32>,
|
||||
output: impl ToSimValue<Type = MOp>,
|
||||
) -> TestCase {
|
||||
let zero_mop = UInt::new_dyn(MOp.canonical().bit_width())
|
||||
|
|
@ -54,7 +64,8 @@ fn test_cases() -> Vec<TestCase> {
|
|||
ArrayVec::elements_sim_mut(&mut single_storage)[0] = output.to_sim_value();
|
||||
TestCase {
|
||||
mnemonic,
|
||||
input,
|
||||
first_input,
|
||||
second_input,
|
||||
output: single_storage.clone(),
|
||||
loc: std::panic::Location::caller(),
|
||||
}
|
||||
|
|
@ -62,8 +73,9 @@ fn test_cases() -> Vec<TestCase> {
|
|||
retval.push(insn_single(
|
||||
"addi 3, 4, 0x1234",
|
||||
0x38641234,
|
||||
None,
|
||||
AddSubMOp::add_sub_i(
|
||||
MOpDestReg::new_sim(&[3], &[]),
|
||||
MOpDestReg::new_sim(&[MOpRegNum::POWER_ISA_GPR_REG_NUMS.start + 3], &[]),
|
||||
[
|
||||
(MOpRegNum::POWER_ISA_GPR_REG_NUMS.start + 4).cast_to_static::<UInt<_>>(),
|
||||
MOpRegNum::CONST_ZERO_REG_NUM.cast_to_static::<UInt<_>>(),
|
||||
|
|
@ -91,7 +103,8 @@ fn test_test_cases_assembly() -> std::io::Result<()> {
|
|||
let mut assembly = String::new();
|
||||
for TestCase {
|
||||
mnemonic,
|
||||
input: _,
|
||||
first_input: _,
|
||||
second_input: _,
|
||||
output: _,
|
||||
loc: _,
|
||||
} in &test_cases
|
||||
|
|
@ -123,15 +136,29 @@ fn test_test_cases_assembly() -> std::io::Result<()> {
|
|||
let mut lines = stdout.lines();
|
||||
let text_line = lines.next();
|
||||
assert_eq!(text_line, Some("\t.text"));
|
||||
for test_case in test_cases {
|
||||
for test_case @ TestCase {
|
||||
mnemonic: _,
|
||||
first_input,
|
||||
second_input,
|
||||
output: _,
|
||||
loc: _,
|
||||
} in test_cases
|
||||
{
|
||||
let Some(line) = lines.next() else {
|
||||
panic!("output missing line for: {test_case:?}");
|
||||
};
|
||||
let Some((_, comment)) = line.split_once('#') else {
|
||||
panic!("output line missing comment. test_case={test_case:?}\nline:\n{line}");
|
||||
};
|
||||
let [b0, b1, b2, b3] = test_case.input.to_le_bytes();
|
||||
let expected_comment = format!(" encoding: [0x{b0:02x},0x{b1:02x},0x{b2:02x},0x{b3:02x}]");
|
||||
let [b0, b1, b2, b3] = first_input.to_le_bytes();
|
||||
let expected_comment = if let Some(second_input) = second_input {
|
||||
let [b4, b5, b6, b7] = second_input.to_le_bytes();
|
||||
format!(
|
||||
" encoding: [0x{b0:02x},0x{b1:02x},0x{b2:02x},0x{b3:02x},0x{b4:02x},0x{b5:02x},0x{b6:02x},0x{b7:02x}]"
|
||||
)
|
||||
} else {
|
||||
format!(" encoding: [0x{b0:02x},0x{b1:02x},0x{b2:02x},0x{b3:02x}]")
|
||||
};
|
||||
assert_eq!(
|
||||
comment, expected_comment,
|
||||
"test_case={test_case:?}\nline:\n{line}"
|
||||
|
|
@ -145,9 +172,9 @@ fn test_test_cases_assembly() -> std::io::Result<()> {
|
|||
|
||||
#[hdl]
|
||||
#[test]
|
||||
fn test_decode_one_32bit_insn() {
|
||||
fn test_decode_insn() {
|
||||
let _n = SourceLocation::normalize_files_for_tests();
|
||||
let m = decode_one_32bit_insn();
|
||||
let m = decode_one_insn();
|
||||
let mut sim = Simulation::new(m);
|
||||
let writer = RcWriter::default();
|
||||
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
|
||||
|
|
@ -165,20 +192,60 @@ fn test_decode_one_32bit_insn() {
|
|||
let mut writer = DumpVcdOnDrop {
|
||||
writer: Some(writer),
|
||||
};
|
||||
for test_case in test_cases() {
|
||||
sim.write(sim.io().input, test_case.input);
|
||||
for test_case @ TestCase {
|
||||
mnemonic: _,
|
||||
first_input,
|
||||
second_input,
|
||||
output: _,
|
||||
loc: _,
|
||||
} in test_cases()
|
||||
{
|
||||
sim.write(sim.io().first_input, first_input);
|
||||
sim.write(
|
||||
sim.io().second_input,
|
||||
if let Some(v) = second_input {
|
||||
#[hdl(sim)]
|
||||
HdlSome(v)
|
||||
} else {
|
||||
#[hdl(sim)]
|
||||
HdlNone()
|
||||
},
|
||||
);
|
||||
sim.advance_time(SimDuration::from_micros(1));
|
||||
let second_input_used = sim.read_bool(sim.io().second_input_used);
|
||||
let is_illegal = sim.read_bool(sim.io().is_illegal);
|
||||
let output = sim.read(sim.io().output);
|
||||
let expected = format!("{:?}", ArrayVec::elements_sim_ref(&test_case.output));
|
||||
let output = format!("{:?}", ArrayVec::elements_sim_ref(&output));
|
||||
#[derive(Debug)]
|
||||
#[expect(dead_code, reason = "used only for Debug formatting")]
|
||||
struct FormattedOutput<'a> {
|
||||
insns: &'a [SimValue<MOp>],
|
||||
second_input_used: bool,
|
||||
is_illegal: bool,
|
||||
}
|
||||
let expected = format!(
|
||||
"{:#?}",
|
||||
FormattedOutput {
|
||||
insns: ArrayVec::elements_sim_ref(&test_case.output),
|
||||
second_input_used: second_input.is_some(),
|
||||
is_illegal: false,
|
||||
},
|
||||
);
|
||||
let output = format!(
|
||||
"{:#?}",
|
||||
FormattedOutput {
|
||||
insns: ArrayVec::elements_sim_ref(&output),
|
||||
second_input_used,
|
||||
is_illegal,
|
||||
},
|
||||
);
|
||||
assert!(
|
||||
expected == output,
|
||||
"test_case={test_case:?}\noutput={output}"
|
||||
"test_case={test_case:#?}\noutput={output}"
|
||||
);
|
||||
}
|
||||
let vcd = String::from_utf8(writer.writer.take().unwrap().take()).unwrap();
|
||||
println!("####### VCD:\n{vcd}\n#######");
|
||||
if vcd != include_str!("expected/decode_one_32bit_insn.vcd") {
|
||||
if vcd != include_str!("expected/decode_one_insn.vcd") {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue