Refactor decode_and_execute to streamline NOP and MOV handling; add real ADD instruction test

This commit is contained in:
Nikilite
2025-06-22 18:49:33 +02:00
parent eac3473ce8
commit be1d86ef78
2 changed files with 50 additions and 35 deletions

View File

@@ -55,35 +55,52 @@ impl CPU {
/// Decode and execute a single ARM64 opcode.
pub fn decode_and_execute(&mut self, opcode: u32) {
// 1) NOP and fake ADD cases first
match opcode {
0xD503201F => {
// NOP: do nothing
self.regs.pc = self.regs.pc.wrapping_add(4);
return;
}
0xD2802674 => {
// Fake ADD X0, X1, X2
self.regs.add_with_flags(0, self.regs.x[1], self.regs.x[2]);
self.regs.pc = self.regs.pc.wrapping_add(4);
return;
}
_ => {}
// 1) NOP
if opcode == 0xD503201F {
self.regs.pc = self.regs.pc.wrapping_add(4);
return;
}
// 2) MOV alias: ORR Xd, XZR, #imm12 (dynamic)
const MOV_MASK: u32 = 0b1111111 << 25; // bits 3125
const MOV_PATTERN: u32 = 0b1010000 << 25; // pattern for ORR immediate
// 2) MOV (ORR Xd, XZR, #imm12)
const MOV_MASK: u32 = 0b1111111 << 25;
const MOV_PATTERN: u32 = 0b1010000 << 25;
if (opcode & MOV_MASK) == MOV_PATTERN {
let rd = (opcode & 0x1F) as usize; // bits [4:0]
let imm12 = ((opcode >> 10) & 0xFFF) as u64; // bits [21:10]
let rd = (opcode & 0x1F) as usize;
let imm12 = ((opcode >> 10) & 0xFFF) as u64;
self.regs.x[rd] = imm12;
self.regs.set_nz(imm12);
self.regs.pc = self.regs.pc.wrapping_add(4);
return;
}
// 3) Unimplemented
// 3) ADD/SUB (register-register)
// Pattern bits [31:21] = 10001011000 (ADD), 11001011000 (SUB)
const ARITH_MASK: u32 = 0xFFE00000; // mask bits 31..21
const ADD_OPCODE: u32 = 0x8B000000; // ADD Xd, Xn, Xm
const SUB_OPCODE: u32 = 0xCB000000; // SUB Xd, Xn, Xm
if (opcode & ARITH_MASK) == ADD_OPCODE || (opcode & ARITH_MASK) == SUB_OPCODE {
let rd = (opcode & 0x1F) as usize;
let rn = ((opcode >> 5) & 0x1F) as usize;
let rm = ((opcode >> 16) & 0x1F) as usize;
let src1 = self.regs.x[rn];
let src2 = self.regs.x[rm];
let result = if (opcode & ARITH_MASK) == ADD_OPCODE {
self.regs.set_cv_add(src1, src2);
src1.wrapping_add(src2)
} else {
self.regs.set_cv_add(src1, !src2 + 1);
src1.wrapping_sub(src2)
};
self.regs.x[rd] = result;
self.regs.set_nz(result);
self.regs.pc = self.regs.pc.wrapping_add(4);
return;
}
// 4) Fallback
println!("⚠️ Unimplemented opcode: {:08X}", opcode);
self.regs.pc = self.regs.pc.wrapping_add(4);
}

View File

@@ -1,6 +1,5 @@
use oboromi::cpu::CPU;
use oboromi::memory::Memory;
use oboromi::cpu::Flags;
/// Simple helper to decode basic ARM64 instruction fields from a 32-bit opcode.
/// Returns a tuple (sf, opc, rn, rd).
@@ -35,20 +34,6 @@ fn main() {
assert_eq!(cpu.regs.pc, 4);
println!("✅ NOP executed correctly, PC = {}", cpu.regs.pc);
// 3) Test ADD with flags: fake opcode 0xD2802674 implements ADD X0, X1, X2
cpu.regs.x[1] = 5;
cpu.regs.x[2] = 7;
cpu.regs.pc = 0;
let add = 0xD2802674_u32.to_le_bytes();
for i in 0..4 {
cpu.memory.write_byte(i, add[i]);
}
cpu.step();
// After ADD, X0 = 5 + 7 = 12, Zero flag should be false
assert_eq!(cpu.regs.x[0], 12);
assert!(!cpu.regs.flags.contains(Flags::ZERO));
println!("✅ ADD executed: X0 = {}, Flags = {:?}", cpu.regs.x[0], cpu.regs.flags);
// 4) Test dynamic MOV Xd, #imm decoding
// MOV X5, #0x2A => ORR X5, XZR, #0x2A
let mut cpu2 = CPU::new(1024);
@@ -71,4 +56,17 @@ fn main() {
let (sf, opc, rn, rd) = decode_arm64_fields(opcode);
println!("Decoded 0x{:08X}: sf={}, opc={}, rn={}, rd={}", opcode, sf, opc, rn, rd);
}
// 5) Test istruzione reale: ADD X1, X1, X2 (opcode: 0x8B020021)
let add_real = 0x8B020021_u32.to_le_bytes();
for i in 0..4 {
cpu.memory.write_byte(i, add_real[i]);
}
cpu.regs.x[1] = 10;
cpu.regs.x[2] = 32;
cpu.regs.pc = 0;
cpu.step();
assert_eq!(cpu.regs.x[1], 42);
println!("✅ Real ADD executed correctly: X1 = {}", cpu.regs.x[1]);
}