use crate::common::instructions::args::{ITypeArgs, RTypeArgs}; use super::instructions::*; #[test] fn test_opcode_nop() { let instr = Instruction::Nop; assert_eq!(instr.opcode(), 0x0); } #[test] 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); 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() { 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() { 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() { 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_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_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), ); // 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_boundary_values() { // Test highest opcode value assert_eq!(Instruction::Halt.opcode(), 0x24); // Test lowest opcode value assert_eq!(Instruction::Nop.opcode(), 0x0); } #[test] fn test_encode_nop() { let no_reg = Register::NoReg as u32; let no_op = u32::from(Instruction::Nop.opcode()); let expected = no_op << 26 | no_reg << 21 | no_reg << 16 | no_reg << 11; let got = Instruction::Nop.encode(); assert_eq!(expected, got); } #[test] fn test_encode_mov() { let rg0 = Register::Rg0 as u32; let rg1 = Register::Rg1 as u32; let no_reg = Register::NoReg as u32; let instruction = Instruction::Mov(RTypeArgs::new( Some(Register::Rg0), None, Some(Register::Rg1), None, )); let mov = u32::from(instruction.opcode()); let expected = mov << 26 | rg0 << 21 | no_reg << 16 | rg1 << 11; let got = instruction.encode(); assert_eq!(expected, got); } #[test] fn test_encode_load_byte() { let rg0 = Register::Rg0 as u32; let rg1 = Register::Rg1 as u32; let immediate = 100; let instruction = Instruction::LoadByte(ITypeArgs::new( immediate, Some(Register::Rg0), Some(Register::Rg1), )); let load_byte = u32::from(instruction.opcode()); let expected = load_byte << 26 | rg0 << 21 | rg1 << 16 | u32::from(immediate); let got = instruction.encode(); assert_eq!(expected, got); } #[test] fn test_encode_shift_left_shamt() { let rg0 = Register::Rg0 as u32; let no_reg = Register::NoReg as u32; let shift_amount = 5; let instruction = Instruction::ShiftLeft(RTypeArgs::new( Some(Register::Rg0), None, None, Some(shift_amount), )); let shift_left = u32::from(instruction.opcode()); let expected = shift_left << 26 | rg0 << 21 | no_reg << 16 | no_reg << 11 | u32::from(shift_amount) << 6; let got = instruction.encode(); assert_eq!(expected, got); } #[test] fn test_encode_shift_left_reg() { let rg0 = Register::Rg0 as u32; let rg1 = Register::Rg1 as u32; let no_reg = Register::NoReg as u32; let instruction = Instruction::ShiftLeft(RTypeArgs::new( Some(Register::Rg0), Some(Register::Rg1), None, None, )); let shift_left = u32::from(instruction.opcode()); let expected = shift_left << 26 | rg0 << 21 | rg1 << 16 | no_reg << 11; let got = instruction.encode(); assert_eq!(expected, got); }