common: fix clippy errors and test arguments

This commit is contained in:
2025-06-15 12:28:13 +01:00
parent c837876960
commit 300c455efd
2 changed files with 92 additions and 153 deletions
+15 -6
View File
@@ -1,6 +1,3 @@
type Offset = u16;
type Immediate = u16;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Interrupt {
Software(u8),
@@ -65,7 +62,7 @@ pub enum Register {
impl Default for Register {
fn default() -> Self {
Register::NoReg
Self::NoReg
}
}
@@ -172,6 +169,17 @@ pub struct ITypeArgs {
pub r2: Register,
}
impl ITypeArgs {
#[must_use]
/// Creates a new [`ITypeArgs`]. If r1 or r2 is unset, they will be replaced with [`Register::NoReg`].
pub fn new(immediate: u16, r1: Option<Register>, r2: Option<Register>) -> Self {
let r1 = r1.unwrap_or_default();
let r2 = r2.unwrap_or_default();
Self { immediate, r1, r2 }
}
}
/// Used by instructions not using immediates (besides 5 bit shift values).
#[derive(Debug, Clone, Copy)]
pub struct RTypeArgs {
@@ -183,8 +191,9 @@ pub struct RTypeArgs {
}
impl RTypeArgs {
/// Args set to None will be replaced with 0 or [Register::NoReg] depending on their type.
fn new(
#[must_use]
/// Creates a new [`RTypeArgs`]. If any registers are unset, they will be replaced with [`Register::NoReg`]. If `shamt` is unset, it will be set to 0.
pub fn new(
sr1: Option<Register>,
sr2: Option<Register>,
dr: Option<Register>,
+77 -147
View File
@@ -1,175 +1,105 @@
use crate::common::instructions::*;
use super::instructions::*;
#[test]
fn test_opcode_basic_instructions() {
assert_eq!(Instruction::Nop.opcode(), 0x0);
assert_eq!(Instruction::Mov(Register::Rg0, Register::Rg1).opcode(), 0x1);
assert_eq!(
Instruction::MovSigned(Register::Rg0, Register::Rg1).opcode(),
0x2
);
assert_eq!(Instruction::Halt.opcode(), 0x24);
fn test_opcode_nop() {
let instr = Instruction::Nop;
assert_eq!(instr.opcode(), 0x0);
}
#[test]
fn test_opcode_data_transfer_instructions() {
assert_eq!(
Instruction::LoadByte(Register::Rg0, 0, Register::Rg1).opcode(),
0x3
);
assert_eq!(
Instruction::LoadByteSigned(Register::Rg0, 0, Register::Rg1).opcode(),
0x4
);
assert_eq!(
Instruction::LoadHalfword(Register::Rg0, 0, Register::Rg1).opcode(),
0x5
);
assert_eq!(
Instruction::LoadHalfwordSigned(Register::Rg0, 0, Register::Rg1).opcode(),
0x6
);
assert_eq!(
Instruction::LoadWord(Register::Rg0, 0, Register::Rg1).opcode(),
0x7
);
assert_eq!(
Instruction::StoreByte(Register::Rg0, 0, Register::Rg1).opcode(),
0x8
);
assert_eq!(
Instruction::StoreHalfword(Register::Rg0, 0, Register::Rg1).opcode(),
0x9
);
assert_eq!(
Instruction::StoreWord(Register::Rg0, 0, Register::Rg1).opcode(),
0xA
);
}
fn test_opcode_data_transfer() {
let args = RTypeArgs::new(None, None, None, None);
assert_eq!(Instruction::Mov(args).opcode(), 0x1);
assert_eq!(Instruction::MovSigned(args).opcode(), 0x2);
#[test]
fn test_opcode_immediate_instructions() {
assert_eq!(
Instruction::LoadLowerImmediate(Register::Rg0, 0).opcode(),
0xB
);
assert_eq!(
Instruction::LoadUpperImmediate(Register::Rg0, 0).opcode(),
0xC
);
let iargs = ITypeArgs::new(0, None, None);
assert_eq!(Instruction::LoadByte(iargs).opcode(), 0x3);
assert_eq!(Instruction::LoadByteSigned(iargs).opcode(), 0x4);
assert_eq!(Instruction::LoadHalfword(iargs).opcode(), 0x5);
assert_eq!(Instruction::LoadHalfwordSigned(iargs).opcode(), 0x6);
assert_eq!(Instruction::LoadWord(iargs).opcode(), 0x7);
assert_eq!(Instruction::StoreByte(iargs).opcode(), 0x8);
assert_eq!(Instruction::StoreHalfword(iargs).opcode(), 0x9);
assert_eq!(Instruction::StoreWord(iargs).opcode(), 0xA);
assert_eq!(Instruction::LoadLowerImmediate(iargs).opcode(), 0xB);
assert_eq!(Instruction::LoadUpperImmediate(iargs).opcode(), 0xC);
}
#[test]
fn test_opcode_jump_instructions() {
assert_eq!(Instruction::Jump(Register::Rg0, 0).opcode(), 0xD);
assert_eq!(Instruction::JumpEq(Register::Rg0, 0).opcode(), 0xE);
assert_eq!(Instruction::JumpNeq(Register::Rg0, 0).opcode(), 0xF);
assert_eq!(Instruction::JumpGt(Register::Rg0, 0).opcode(), 0x10);
assert_eq!(Instruction::JumpGe(Register::Rg0, 0).opcode(), 0x11);
assert_eq!(Instruction::JumpLt(Register::Rg0, 0).opcode(), 0x12);
assert_eq!(Instruction::JumpLe(Register::Rg0, 0).opcode(), 0x13);
let args = ITypeArgs::new(0, None, None);
assert_eq!(Instruction::Jump(args).opcode(), 0xD);
assert_eq!(Instruction::JumpEq(args).opcode(), 0xE);
assert_eq!(Instruction::JumpNeq(args).opcode(), 0xF);
assert_eq!(Instruction::JumpGt(args).opcode(), 0x10);
assert_eq!(Instruction::JumpGe(args).opcode(), 0x11);
assert_eq!(Instruction::JumpLt(args).opcode(), 0x12);
assert_eq!(Instruction::JumpLe(args).opcode(), 0x13);
}
#[test]
fn test_opcode_arithmetic_instructions() {
assert_eq!(
Instruction::Compare(Register::Rg0, Register::Rg1).opcode(),
0x14
);
assert_eq!(Instruction::Increment(Register::Rg0).opcode(), 0x15);
assert_eq!(Instruction::Decrement(Register::Rg0).opcode(), 0x16);
assert_eq!(
Instruction::ShiftLeft(Register::Rg0, Register::Rg1, 0).opcode(),
0x17
);
assert_eq!(
Instruction::ShiftRight(Register::Rg0, Register::Rg1, 0).opcode(),
0x18
);
assert_eq!(
Instruction::Add(Register::Rg0, Register::Rg1, Register::Rg2).opcode(),
0x19
);
assert_eq!(
Instruction::Sub(Register::Rg0, Register::Rg1, Register::Rg2).opcode(),
0x1A
);
fn test_opcode_arithmetic() {
let args = RTypeArgs::new(None, None, None, None);
assert_eq!(Instruction::Compare(args).opcode(), 0x14);
assert_eq!(Instruction::Increment(args).opcode(), 0x15);
assert_eq!(Instruction::Decrement(args).opcode(), 0x16);
assert_eq!(Instruction::ShiftLeft(args).opcode(), 0x17);
assert_eq!(Instruction::ShiftRight(args).opcode(), 0x18);
assert_eq!(Instruction::Add(args).opcode(), 0x19);
assert_eq!(Instruction::Sub(args).opcode(), 0x1A);
}
#[test]
fn test_opcode_logical_instructions() {
assert_eq!(
Instruction::And(Register::Rg0, Register::Rg1, Register::Rg2).opcode(),
0x1B
);
assert_eq!(
Instruction::Or(Register::Rg0, Register::Rg1, Register::Rg2).opcode(),
0x1C
);
assert_eq!(
Instruction::Not(Register::Rg0, Register::Rg1).opcode(),
0x1D
);
assert_eq!(
Instruction::Xor(Register::Rg0, Register::Rg1, Register::Rg2).opcode(),
0x1E
);
assert_eq!(
Instruction::Nand(Register::Rg0, Register::Rg1, Register::Rg2).opcode(),
0x1F
);
assert_eq!(
Instruction::Nor(Register::Rg0, Register::Rg1, Register::Rg2).opcode(),
0x20
);
assert_eq!(
Instruction::Xnor(Register::Rg0, Register::Rg1, Register::Rg2).opcode(),
0x21
);
fn test_opcode_logical() {
let args = RTypeArgs::new(None, None, None, None);
assert_eq!(Instruction::And(args).opcode(), 0x1B);
assert_eq!(Instruction::Or(args).opcode(), 0x1C);
assert_eq!(Instruction::Not(args).opcode(), 0x1D);
assert_eq!(Instruction::Xor(args).opcode(), 0x1E);
assert_eq!(Instruction::Nand(args).opcode(), 0x1F);
assert_eq!(Instruction::Nor(args).opcode(), 0x20);
assert_eq!(Instruction::Xnor(args).opcode(), 0x21);
}
#[test]
fn test_opcode_system_instructions() {
assert_eq!(
Instruction::Interrupt(Interrupt::Software(0)).opcode(),
0x22
);
fn test_opcode_misc() {
let interrupt = Interrupt::Software(5);
assert_eq!(Instruction::Interrupt(interrupt).opcode(), 0x22);
assert_eq!(Instruction::IntReturn.opcode(), 0x23);
assert_eq!(Instruction::Halt.opcode(), 0x24);
}
#[test]
fn test_opcode_top_bits_are_zero() {
// Test that opcodes have top 2 bits as 0 (6-bit opcodes)
let instructions = [
Instruction::Nop,
Instruction::Mov(Register::Rg0, Register::Rg1),
Instruction::Add(Register::Rg0, Register::Rg1, Register::Rg2),
Instruction::Halt,
];
fn test_opcode_with_different_args() {
let args1 = RTypeArgs::new(
Some(Register::Rg0),
Some(Register::Rg1),
Some(Register::Rg2),
Some(5),
);
let args2 = RTypeArgs::new(
Some(Register::Acc),
Some(Register::Spr),
Some(Register::Bpr),
Some(31),
);
for instruction in instructions {
let opcode = instruction.opcode();
assert_eq!(
opcode & 0xC0,
0,
"Top 2 bits should be 0 for opcode {opcode:#02x}"
);
}
// Opcode should be the same regardless of arguments
assert_eq!(
Instruction::Add(args1).opcode(),
Instruction::Add(args2).opcode()
);
assert_eq!(
Instruction::Sub(args1).opcode(),
Instruction::Sub(args2).opcode()
);
}
#[test]
fn test_opcode_same_instruction_different_params() {
// Same instruction type with different parameters should have same opcode
assert_eq!(
Instruction::Mov(Register::Rg0, Register::Rg1).opcode(),
Instruction::Mov(Register::Acc, Register::Spr).opcode()
);
assert_eq!(
Instruction::Add(Register::Rg0, Register::Rg1, Register::Rg2).opcode(),
Instruction::Add(Register::Acc, Register::Spr, Register::Bpr).opcode()
);
assert_eq!(
Instruction::LoadWord(Register::Rg0, 100, Register::Rg1).opcode(),
Instruction::LoadWord(Register::Acc, 500, Register::Spr).opcode()
);
fn test_opcode_boundary_values() {
// Test highest opcode value
assert_eq!(Instruction::Halt.opcode(), 0x24);
// Test lowest opcode value
assert_eq!(Instruction::Nop.opcode(), 0x0);
}