diff --git a/snes-core/src/cpu/instructions/jmp.rs b/snes-core/src/cpu/instructions/jmp.rs index 5a1ac81..f4dc6fe 100644 --- a/snes-core/src/cpu/instructions/jmp.rs +++ b/snes-core/src/cpu/instructions/jmp.rs @@ -1,5 +1,5 @@ use crate::cpu::{bus::Bus, registers::Registers}; -use crate::utils::addressing::AddressingMode; +use crate::utils::addressing::{AddressingMode, IndexRegister}; use super::read_write_common::get_effective_address; use super::CPUInstruction; @@ -15,7 +15,13 @@ pub struct JMP { impl CPUInstruction for JMP { fn execute(&self, registers: &mut Registers, bus: &mut Bus) { let effective_address = get_effective_address(registers, bus, self.addressing_mode); - let is_long = matches!(self.addressing_mode, AddressingMode::AbsoluteLong | AddressingMode::AbsoluteIndirectLong); + let is_long = matches!( + self.addressing_mode, + AddressingMode::AbsoluteLong | + AddressingMode::AbsoluteIndirectLong | + AddressingMode::AbsoluteIndexedIndirect(IndexRegister::X) | + AddressingMode::AbsoluteIndexedIndirect(IndexRegister::Y) + ); registers.pc = effective_address as u16; if is_long { registers.pbr = (effective_address >> 16) as u8; diff --git a/snes-core/src/cpu/instructions/jsr.rs b/snes-core/src/cpu/instructions/jsr.rs index 8fba498..23c4f62 100644 --- a/snes-core/src/cpu/instructions/jsr.rs +++ b/snes-core/src/cpu/instructions/jsr.rs @@ -1,5 +1,5 @@ use crate::cpu::{bus::Bus, registers::Registers}; -use crate::utils::addressing::AddressingMode; +use crate::utils::addressing::{AddressingMode, IndexRegister}; use super::read_write_common::get_effective_address; use super::{CPUInstruction, push_common}; @@ -15,10 +15,15 @@ pub struct JSR { impl CPUInstruction for JSR { fn execute(&self, registers: &mut Registers, bus: &mut Bus) { let effective_address = get_effective_address(registers, bus, self.addressing_mode); - let is_long = matches!(self.addressing_mode, AddressingMode::AbsoluteLong | AddressingMode::AbsoluteIndirectLong); + let is_long = matches!( + self.addressing_mode, AddressingMode::AbsoluteLong | + AddressingMode::AbsoluteIndirectLong | + AddressingMode::AbsoluteIndexedIndirect(IndexRegister::X) | + AddressingMode::AbsoluteIndexedIndirect(IndexRegister::Y) + ); // We need to push the *next* instruction onto the stack let (bytes, cycles) = cycles::increment_cycles_jsr(self.addressing_mode); - registers.increment_pc(bytes); registers.cycles += cycles; + registers.increment_pc(bytes - 1); registers.cycles += cycles; let value = registers.get_pc_address(); if is_long { push_common::do_push(registers, bus, &[ @@ -64,7 +69,7 @@ mod cpu_instructions_tests { instruction.execute(&mut registers, &mut bus); assert_eq!(bus.read(0x1FC), 0x00); assert_eq!(bus.read(0x1FB), 0x12); - assert_eq!(bus.read(0x1FA), 0x38); // we should store the NEXT instruction + assert_eq!(bus.read(0x1FA), 0x37); // we should store the NEXT instruction assert_eq!(registers.pbr, 0xAA); assert_eq!(registers.pc, 0xBBCC); assert_eq!(registers.sp, 0x1F9); diff --git a/snes-core/src/cpu/instructions/read_write_common.rs b/snes-core/src/cpu/instructions/read_write_common.rs index b1e59ef..3360fd9 100644 --- a/snes-core/src/cpu/instructions/read_write_common.rs +++ b/snes-core/src/cpu/instructions/read_write_common.rs @@ -9,6 +9,7 @@ pub fn get_effective_address(registers: &Registers, bus: &mut Bus, addressing_mo stack_pointer: registers.sp, x: registers.x, y: registers.y, dbr: registers.dbr, + is_16bit_index: registers.is_16bit_index(), } ) } @@ -23,6 +24,7 @@ pub fn read_8bit_from_address(registers: &Registers, bus: &mut Bus, addressing_m stack_pointer: registers.sp, x: registers.x, y: registers.y, dbr: registers.dbr, + is_16bit_index: registers.is_16bit_index(), }, bus, ) @@ -39,6 +41,7 @@ pub fn read_16bit_from_address(registers: &Registers, bus: &mut Bus, addressing_ stack_pointer: registers.sp, x: registers.x, y: registers.y, dbr: registers.dbr, + is_16bit_index: registers.is_16bit_index(), }, bus, ) @@ -55,6 +58,7 @@ pub fn write_8bit_to_address(registers: &mut Registers, bus: &mut Bus, addressin stack_pointer: registers.sp, x: registers.x, y: registers.y, dbr: registers.dbr, + is_16bit_index: registers.is_16bit_index(), }, bus, value, @@ -72,6 +76,7 @@ pub fn write_16bit_to_address(registers: &mut Registers, bus: &mut Bus, addressi stack_pointer: registers.sp, x: registers.x, y: registers.y, dbr: registers.dbr, + is_16bit_index: registers.is_16bit_index(), }, bus, value, diff --git a/snes-core/src/utils/addressing.rs b/snes-core/src/utils/addressing.rs index 4804729..13be771 100644 --- a/snes-core/src/utils/addressing.rs +++ b/snes-core/src/utils/addressing.rs @@ -11,6 +11,7 @@ pub struct ResolveAddressParams { pub stack_pointer: u16, pub x: u16, pub y: u16, + pub is_16bit_index: bool, } @@ -31,10 +32,10 @@ pub fn absolute(bus: &mut Bus, pc_addr: u32, dbr: u8) -> u32 { } /// OPCODE (addr) -pub fn absolute_indirect(bus: &mut Bus, pc_addr: u32, dbr: u8) -> u32 { - let addr = absolute(bus, pc_addr, dbr); - let dbr = pc_addr & 0xFF0000; - dbr | ((bus.read(addr) as u32) << 8) | (bus.read(addr + 1) as u32) +pub fn absolute_indirect(bus: &mut Bus, pc_addr: u32) -> u32 { + let pbr = pc_addr & 0xFF0000; + let addr = ((bus.read(pc_addr + 2) as u32) << 8) | (bus.read(pc_addr + 1) as u32); + pbr | ((bus.read(addr + 1) as u32) << 8) | (bus.read(addr) as u32) } /// OPCODE long @@ -45,11 +46,11 @@ pub fn absolute_long(bus: &mut Bus, pc_addr: u32) -> u32 { } /// OPCODE (addr) -pub fn absolute_indirect_long(bus: &mut Bus, pc_addr: u32, dbr: u8) -> u32 { - let addr = absolute(bus, pc_addr, dbr); - ((bus.read(addr) as u32) << 16) | +pub fn absolute_indirect_long(bus: &mut Bus, pc_addr: u32) -> u32 { + let addr = (bus.read(pc_addr + 1) as u32) | ((bus.read(pc_addr + 2) as u32) << 8); + (bus.read(addr) as u32) | ((bus.read(addr + 1) as u32) << 8) | - (bus.read(addr + 2) as u32) + ((bus.read(addr + 2) as u32) << 16) } /// OPCODE dp @@ -79,11 +80,17 @@ pub fn absolute_indexed(bus: &mut Bus, pc_addr: u32, xy: u16, dbr: u8) -> u32 { absolute(bus, pc_addr, dbr) + (xy as u32) } -/// OPCODE (addr) -pub fn absolute_indexed_indirect(bus: &mut Bus, pc_addr: u32, xy: u16, dbr: u8) -> u32 { - let addr = absolute_indexed(bus, pc_addr, xy, dbr); - let dbr = pc_addr & 0xFF0000; - dbr | ((bus.read(addr) as u32) << 8) | (bus.read(addr + 1) as u32) +/// OPCODE (addr,X) +/// OPCODE (addr,Y) +pub fn absolute_indexed_indirect(bus: &mut Bus, pc_addr: u32, xy: u16, is_16bit_index: bool) -> u32 { + let pbr = pc_addr & 0xFF0000; + let operand = (bus.read(pc_addr + 1) as u32) | ((bus.read(pc_addr + 2) as u32) << 8); + let mut effective_xy = xy; + if !is_16bit_index { + effective_xy &= 0xFF; + } + let addr = pbr | (operand as u16).wrapping_add(effective_xy) as u32; + pbr | (bus.read(addr) as u32) | ((bus.read(addr + 1) as u32) << 8) } @@ -181,14 +188,14 @@ impl AddressingMode { Self::Accumulator => p.pc_addr, Self::Immediate => immediate(p.pc_addr), Self::Absolute => absolute(bus, p.pc_addr, p.dbr), - Self::AbsoluteIndirect => absolute_indirect(bus, p.pc_addr, p.dbr), - Self::AbsoluteIndirectLong => absolute_indirect_long(bus, p.pc_addr, p.dbr), + Self::AbsoluteIndirect => absolute_indirect(bus, p.pc_addr), + Self::AbsoluteIndirectLong => absolute_indirect_long(bus, p.pc_addr), Self::AbsoluteLong => absolute_long(bus, p.pc_addr), Self::DirectPage => direct_page(bus, p.pc_addr, p.direct_page_register), Self::DirectPageIndirect => direct_page_indirect(bus, p.pc_addr, p.direct_page_register, p.dbr), Self::DirectPageIndirectLong => direct_page_indirect_long(bus, p.pc_addr, p.direct_page_register), Self::AbsoluteIndexed(idx) => absolute_indexed(bus, p.pc_addr, if idx == X {p.x} else {p.y}, p.dbr), - Self::AbsoluteIndexedIndirect(idx) => absolute_indexed_indirect(bus, p.pc_addr, if idx == X {p.x} else {p.y}, p.dbr), + Self::AbsoluteIndexedIndirect(idx) => absolute_indexed_indirect(bus, p.pc_addr, if idx == X {p.x} else {p.y}, p.is_16bit_index), Self::AbsoluteLongIndexed(idx) => absolute_long_indexed(bus, p.pc_addr, if idx == X {p.x} else {p.y}), Self::DirectPageIndexed(idx) => direct_page_indexed(bus, p.pc_addr, p.direct_page_register, if idx == X {p.x} else {p.y}), Self::DirectPageIndexedIndirect(idx) => direct_page_indexed_indirect(bus, p.pc_addr, p.direct_page_register, if idx == X {p.x} else {p.y}, p.dbr), @@ -254,21 +261,21 @@ mod addressing_modes_tests { bus.write(pc_addr + 1, addr); bus.write(addr as u32, 0x02); bus.write((addr + 1) as u32, 0x01); - assert_eq!(absolute_indirect(&mut bus, pc_addr, 0x00), 0x000201); + assert_eq!(absolute_indirect(&mut bus, pc_addr), 0x000102); let pc_addr = 0x7E0010; let addr = 0x55; bus.write(pc_addr + 1, addr); bus.write(addr as u32, 0x02); bus.write((addr + 1) as u32, 0x01); - assert_eq!(absolute_indirect(&mut bus, pc_addr, 0x00), 0x7E0201); + assert_eq!(absolute_indirect(&mut bus, pc_addr), 0x7E0102); let pc_addr = 0x7E0010; let addr = 0x55; bus.write(pc_addr + 1, addr); bus.write(addr as u32, 0x02); bus.write((addr + 1) as u32, 0x01); - assert_eq!(absolute_indirect(&mut bus, pc_addr, 0x00), 0x7E0201); + assert_eq!(absolute_indirect(&mut bus, pc_addr), 0x7E0102); } #[test] @@ -297,7 +304,7 @@ mod addressing_modes_tests { bus.write(addr as u32, 0x03); bus.write((addr + 1) as u32, 0x02); bus.write((addr + 2) as u32, 0x01); - assert_eq!(absolute_indirect_long(&mut bus, pc_addr, 0x00), 0x030201); + assert_eq!(absolute_indirect_long(&mut bus, pc_addr), 0x010203); } @@ -383,7 +390,7 @@ mod addressing_modes_tests { bus.write(pc_addr + 1, addr); bus.write(addr as u32, 0x02); bus.write((addr + 1) as u32, 0x01); - assert_eq!(absolute_indexed_indirect(&mut bus, pc_addr, 0, 0x00), 0x000201); + assert_eq!(absolute_indexed_indirect(&mut bus, pc_addr, 0, true), 0x000102); } #[test] @@ -523,7 +530,7 @@ mod addressing_modes_tests { bus.write(pc_addr + 2, 0x10); bus.write(0x001020, 0xFE); let val = AddressingMode::Absolute.read_8bit( - ResolveAddressParams {pc_addr, direct_page_register: 0x00, stack_pointer: 0x00, x: 0x00, y: 0x00, dbr: 0x00}, + ResolveAddressParams {pc_addr, direct_page_register: 0x00, stack_pointer: 0x00, x: 0x00, y: 0x00, dbr: 0x00, is_16bit_index: true}, &mut bus, ); assert_eq!(val, 0xFE); @@ -535,7 +542,7 @@ mod addressing_modes_tests { bus.write(0x001020, 0xFF); bus.write(0x001021, 0xEE); let val = AddressingMode::Absolute.read_16bit( - ResolveAddressParams {pc_addr, direct_page_register: 0x00, stack_pointer: 0x00, x: 0x00, y: 0x00, dbr: 0x00}, + ResolveAddressParams {pc_addr, direct_page_register: 0x00, stack_pointer: 0x00, x: 0x00, y: 0x00, dbr: 0x00, is_16bit_index: true}, &mut bus, ); assert_eq!(val, 0xEEFF);