From 5dc793a70926dbef6a238fd85bd1832372e0cb77 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 25 Nov 2023 09:48:36 +0100 Subject: [PATCH] SPC700: implement AND1, EOR1, OR1, NOT1, MOV1 --- src/snes/cpu_spc700/cpu.rs | 97 +++++++++++++++++++++++++++++++ src/test/processortests_spc700.rs | 16 ++--- 2 files changed, 105 insertions(+), 8 deletions(-) diff --git a/src/snes/cpu_spc700/cpu.rs b/src/snes/cpu_spc700/cpu.rs index adbe11c..e91bd51 100644 --- a/src/snes/cpu_spc700/cpu.rs +++ b/src/snes/cpu_spc700/cpu.rs @@ -264,6 +264,11 @@ where InstructionType::BVS => self.op_branch(instr, self.regs.test_flag(Flag::V)), InstructionType::BRA => self.op_branch(instr, true), InstructionType::ADDW => self.op_addw(instr), + InstructionType::AND1 => self.op_and1(instr), + InstructionType::EOR1 => self.op_eor1(instr), + InstructionType::OR1 => self.op_or1(instr), + InstructionType::MOV1 => self.op_mov1(instr), + InstructionType::NOT1 => self.op_not1(instr), _ => todo!(), } } @@ -382,10 +387,31 @@ where .wrapping_add(self.regs.read(Register::Y)); Ok((imm_idx + 1, self.read_tick(addr), Some(addr))) } + Operand::AbsoluteBooleanBit | Operand::AbsoluteNotBooleanBit => unreachable!(), + _ => todo!(), } } + /// Resolve an address for the m.b addressing modes + fn resolve_address_mb(&mut self, instr: &Instruction) -> (SpcAddress, u8) { + let i = instr.imm16(); + let bit = (i >> 13) as u8; + (i & 0x1FFF, bit) + } + + /// Resolve bit for the m.b addressing modes + fn resolve_value_mb(&mut self, instr: &Instruction, opidx: usize) -> bool { + let (addr, bit) = self.resolve_address_mb(instr); + let val = self.read_tick(addr); + + match instr.def.operands[opidx] { + Operand::AbsoluteBooleanBit => (val & (1 << bit)) != 0, + Operand::AbsoluteNotBooleanBit => (val & (1 << bit)) == 0, + _ => unreachable!(), + } + } + /// Translate 8-bit relative address from operands /// to a full address (P flag). fn map_pageflag>(&self, addr: T) -> SpcAddress { @@ -903,4 +929,75 @@ where Ok(()) } + + /// AND1 + fn op_and1(&mut self, instr: &Instruction) -> Result<()> { + let val = self.resolve_value_mb(instr, 1); + let result = self.regs.test_flag(Flag::C) & val; + self.regs.write_flags(&[(Flag::C, result)]); + + Ok(()) + } + + /// EOR1 + fn op_eor1(&mut self, instr: &Instruction) -> Result<()> { + let val = self.resolve_value_mb(instr, 1); + let result = self.regs.test_flag(Flag::C) ^ val; + self.regs.write_flags(&[(Flag::C, result)]); + + // Internal cycle + self.tick_bus(1)?; + + Ok(()) + } + + /// OR1 + fn op_or1(&mut self, instr: &Instruction) -> Result<()> { + let val = self.resolve_value_mb(instr, 1); + let result = self.regs.test_flag(Flag::C) | val; + self.regs.write_flags(&[(Flag::C, result)]); + + // Internal cycle + self.tick_bus(1)?; + + Ok(()) + } + + /// MOV1 + fn op_mov1(&mut self, instr: &Instruction) -> Result<()> { + match instr.def.operands[0] { + Operand::AbsoluteBooleanBit => { + // MOV1 m.b, C + let (addr, bit) = self.resolve_address_mb(instr); + let val = self.read_tick(addr); + let result = if self.regs.test_flag(Flag::C) { + val | (1 << bit) + } else { + val & !(1 << bit) + }; + + // Internal cycle + self.tick_bus(1)?; + + self.write_tick(addr, result); + } + Operand::None => { + // MOV1 C, m.b + let result = self.resolve_value_mb(instr, 1); + self.regs.write_flags(&[(Flag::C, result)]); + } + _ => unreachable!(), + } + + Ok(()) + } + + /// NOT1 + fn op_not1(&mut self, instr: &Instruction) -> Result<()> { + let (addr, bit) = self.resolve_address_mb(instr); + let val = self.read_tick(addr); + self.write_tick(addr, val ^ (1 << bit)); + + Ok(()) + } } diff --git a/src/test/processortests_spc700.rs b/src/test/processortests_spc700.rs index 42e111d..bf7b441 100644 --- a/src/test/processortests_spc700.rs +++ b/src/test/processortests_spc700.rs @@ -121,8 +121,8 @@ fn run_testcase(testcase: &Value, check_trace: bool, multi_steps: bool) { dbg!(testcase); dbg_hex!(bus_trace); panic!( - "Addr {:06X} - expected {:02X}, saw {:02X}", - addr, exp_val, val + "Addr {:06X} - expected {:02X}, saw {:02X} - registers: {}", + addr, exp_val, val, cpu.regs ); } } @@ -259,7 +259,7 @@ cpu_test!(instr_48, 0x48); // Decoder reads immediate values first but real CPU follows the // first indirection first. cpu_test_no_trace!(instr_49, 0x49); -//cpu_test!(instr_4a, 0x4a); +cpu_test!(instr_4a, 0x4a); cpu_test!(instr_4b, 0x4b); cpu_test!(instr_4c, 0x4c); cpu_test!(instr_4d, 0x4d); @@ -294,7 +294,7 @@ cpu_test!(instr_67, 0x67); cpu_test!(instr_68, 0x68); // Read indirection during fetch cpu_test_no_trace!(instr_69, 0x69); -//cpu_test!(instr_6a, 0x6a); +cpu_test!(instr_6a, 0x6a); //cpu_test!(instr_6b, 0x6b); //cpu_test!(instr_6c, 0x6c); cpu_test!(instr_6d, 0x6d); @@ -328,7 +328,7 @@ cpu_test!(instr_87, 0x87); cpu_test!(instr_88, 0x88); // Read indirection during fetch cpu_test_no_trace!(instr_89, 0x89); -//cpu_test!(instr_8a, 0x8a); +cpu_test!(instr_8a, 0x8a); cpu_test!(instr_8b, 0x8b); cpu_test!(instr_8c, 0x8c); cpu_test!(instr_8d, 0x8d); @@ -362,7 +362,7 @@ cpu_test!(instr_a7, 0xa7); cpu_test!(instr_a8, 0xa8); // Read indirection during fetch cpu_test_no_trace!(instr_a9, 0xa9); -//cpu_test!(instr_aa, 0xaa); +cpu_test!(instr_aa, 0xaa); cpu_test!(instr_ab, 0xab); cpu_test!(instr_ac, 0xac); cpu_test!(instr_ad, 0xad); @@ -396,7 +396,7 @@ cpu_test!(instr_c6, 0xc6); cpu_test!(instr_c7, 0xc7); //cpu_test!(instr_c8, 0xc8); cpu_test!(instr_c9, 0xc9); -//cpu_test!(instr_ca, 0xca); +cpu_test!(instr_ca, 0xca); cpu_test!(instr_cb, 0xcb); cpu_test!(instr_cc, 0xcc); cpu_test!(instr_cd, 0xcd); @@ -429,7 +429,7 @@ cpu_test!(instr_e6, 0xe6); cpu_test!(instr_e7, 0xe7); cpu_test!(instr_e8, 0xe8); cpu_test!(instr_e9, 0xe9); -//cpu_test!(instr_ea, 0xea); +cpu_test!(instr_ea, 0xea); cpu_test!(instr_eb, 0xeb); cpu_test!(instr_ec, 0xec); cpu_test!(instr_ed, 0xed);