#![allow(clippy::unwrap_used)] use crate::prelude::*; #[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_instruction_decode_nop() { let instr = Instruction::Nop; let encoded = instr.encode(); let decoded = Instruction::decode(encoded).unwrap(); assert_eq!(instr, decoded); } #[test] fn test_instruction_decode_data_transfer() { let args = RTypeArgs::new( Some(Register::Rg0), Some(Register::Rg1), Some(Register::Rg2), Some(5), ); let instr = Instruction::Mov(args); let encoded = instr.encode(); let decoded = Instruction::decode(encoded).unwrap(); assert_eq!(instr, decoded); let iargs = ITypeArgs::new(100, Some(Register::Rg3), Some(Register::Rg4)); let instr = Instruction::LoadWord(iargs); let encoded = instr.encode(); let decoded = Instruction::decode(encoded).unwrap(); assert_eq!(instr, decoded); } #[test] fn test_instruction_decode_jump() { let args = ITypeArgs::new(200, Some(Register::Acc), Some(Register::Spr)); let instr = Instruction::Jump(args); let encoded = instr.encode(); let decoded = Instruction::decode(encoded).unwrap(); assert_eq!(instr, decoded); let instr = Instruction::JumpEq(args); let encoded = instr.encode(); let decoded = Instruction::decode(encoded).unwrap(); assert_eq!(instr, decoded); } #[test] fn test_instruction_decode_arithmetic() { let args = RTypeArgs::new( Some(Register::Bpr), Some(Register::Rg7), Some(Register::Rgf), Some(31), ); let instr = Instruction::Add(args); let encoded = instr.encode(); let decoded = Instruction::decode(encoded).unwrap(); assert_eq!(instr, decoded); let instr = Instruction::Compare(args); let encoded = instr.encode(); let decoded = Instruction::decode(encoded).unwrap(); assert_eq!(instr, decoded); } #[test] fn test_instruction_decode_logical() { let args = RTypeArgs::new( Some(Register::Rg8), Some(Register::Rg9), Some(Register::Rga), Some(15), ); let instr = Instruction::And(args); let encoded = instr.encode(); let decoded = Instruction::decode(encoded).unwrap(); assert_eq!(instr, decoded); let instr = Instruction::Xor(args); let encoded = instr.encode(); let decoded = Instruction::decode(encoded).unwrap(); assert_eq!(instr, decoded); } #[test] fn test_instruction_decode_misc() { let instr = Instruction::Halt; let encoded = instr.encode(); let decoded = Instruction::decode(encoded).unwrap(); assert_eq!(instr, decoded); } #[test] fn test_instruction_decode_invalid() { // Test with invalid opcode. let invalid_encoded = 0xF500_0000; let decode = Instruction::decode(invalid_encoded); dbg!(&decode); assert!(decode.is_err()); } // TODO: Get interrupts working. // #[test] // fn test_instruction_decode_interrupt() { // let interrupt = Interrupt::Software(10); // let instr = Instruction::Interrupt(interrupt); // let encoded = instr.encode(); // let decoded = Instruction::decode(encoded).unwrap(); // assert_eq!(instr, decoded); // }