diff --git a/snes-core/src/cpu/cycles.rs b/snes-core/src/cpu/cycles.rs index 6fd9fe6..5ec5f78 100644 --- a/snes-core/src/cpu/cycles.rs +++ b/snes-core/src/cpu/cycles.rs @@ -384,7 +384,7 @@ pub fn increment_cycles_sep() -> (u16, usize) { } pub fn increment_cycles_return_subroutine() -> (u16, usize) { - (0, 6) + (1, 6) } pub fn increment_cycles_return_interrupt(is_emulation_mode: bool) -> (u16, usize) { diff --git a/snes-core/src/cpu/instructions/pla.rs b/snes-core/src/cpu/instructions/pla.rs index 5521179..e9d2d0d 100644 --- a/snes-core/src/cpu/instructions/pla.rs +++ b/snes-core/src/cpu/instructions/pla.rs @@ -11,10 +11,10 @@ pub struct PLA {} impl CPUInstruction for PLA { fn execute(&self, registers: &mut Registers, bus: &mut Bus) { if registers.is_16bit_mode() { - let bytes = pull_common::do_pull(registers, bus, 2); + let bytes = pull_common::do_pull(registers, bus, 2, true); registers.a = (bytes[0] as u16) | ((bytes[1] as u16) << 8); } else { - let bytes = pull_common::do_pull(registers, bus, 1); + let bytes = pull_common::do_pull(registers, bus, 1, true); registers.set_low_a(bytes[0]); } let (bytes, cycles) = cycles::increment_cycles_pla(registers.is_16bit_mode()); diff --git a/snes-core/src/cpu/instructions/plb.rs b/snes-core/src/cpu/instructions/plb.rs index 4ba1733..480fbd4 100644 --- a/snes-core/src/cpu/instructions/plb.rs +++ b/snes-core/src/cpu/instructions/plb.rs @@ -10,7 +10,7 @@ pub struct PLB {} impl CPUInstruction for PLB { fn execute(&self, registers: &mut Registers, bus: &mut Bus) { - registers.dbr = pull_common::do_pull(registers, bus, 1)[0]; + registers.dbr = pull_common::do_pull(registers, bus, 1, true)[0]; let (bytes, cycles) = cycles::increment_cycles_plb(); registers.increment_pc(bytes); registers.cycles += cycles; } diff --git a/snes-core/src/cpu/instructions/pld.rs b/snes-core/src/cpu/instructions/pld.rs index 33a8722..a3a0978 100644 --- a/snes-core/src/cpu/instructions/pld.rs +++ b/snes-core/src/cpu/instructions/pld.rs @@ -10,7 +10,7 @@ pub struct PLD {} impl CPUInstruction for PLD { fn execute(&self, registers: &mut Registers, bus: &mut Bus) { - let bytes = pull_common::do_pull(registers, bus, 2); + let bytes = pull_common::do_pull(registers, bus, 2, true); registers.d = (bytes[0] as u16) | ((bytes[1] as u16) << 8); let (bytes, cycles) = cycles::increment_cycles_pld(); registers.increment_pc(bytes); registers.cycles += cycles; diff --git a/snes-core/src/cpu/instructions/plp.rs b/snes-core/src/cpu/instructions/plp.rs index 5aaf52b..7e536f9 100644 --- a/snes-core/src/cpu/instructions/plp.rs +++ b/snes-core/src/cpu/instructions/plp.rs @@ -10,7 +10,7 @@ pub struct PLP {} impl CPUInstruction for PLP { fn execute(&self, registers: &mut Registers, bus: &mut Bus) { - let bytes = pull_common::do_pull(registers, bus, 1); + let bytes = pull_common::do_pull(registers, bus, 1, true); registers.p = bytes[0]; let (bytes, cycles) = cycles::increment_cycles_plp(); registers.increment_pc(bytes); registers.cycles += cycles; diff --git a/snes-core/src/cpu/instructions/plx.rs b/snes-core/src/cpu/instructions/plx.rs index f9b5008..78afb16 100644 --- a/snes-core/src/cpu/instructions/plx.rs +++ b/snes-core/src/cpu/instructions/plx.rs @@ -11,10 +11,10 @@ pub struct PLX {} impl CPUInstruction for PLX { fn execute(&self, registers: &mut Registers, bus: &mut Bus) { if registers.is_16bit_index() { - let bytes = pull_common::do_pull(registers, bus, 2); + let bytes = pull_common::do_pull(registers, bus, 2, true); registers.x = (bytes[0] as u16) | ((bytes[1] as u16) << 8); } else { - let bytes = pull_common::do_pull(registers, bus, 1); + let bytes = pull_common::do_pull(registers, bus, 1, true); registers.set_low_x(bytes[0]); } let (bytes, cycles) = cycles::increment_cycles_pl_index(registers.is_16bit_index()); diff --git a/snes-core/src/cpu/instructions/ply.rs b/snes-core/src/cpu/instructions/ply.rs index 800a437..7bfe5ef 100644 --- a/snes-core/src/cpu/instructions/ply.rs +++ b/snes-core/src/cpu/instructions/ply.rs @@ -11,10 +11,10 @@ pub struct PLY {} impl CPUInstruction for PLY { fn execute(&self, registers: &mut Registers, bus: &mut Bus) { if registers.is_16bit_index() { - let bytes = pull_common::do_pull(registers, bus, 2); + let bytes = pull_common::do_pull(registers, bus, 2, true); registers.y = (bytes[0] as u16) | ((bytes[1] as u16) << 8); } else { - let bytes = pull_common::do_pull(registers, bus, 1); + let bytes = pull_common::do_pull(registers, bus, 1, true); registers.set_low_y(bytes[0]); } let (bytes, cycles) = cycles::increment_cycles_pl_index(registers.is_16bit_index()); diff --git a/snes-core/src/cpu/instructions/pull_common.rs b/snes-core/src/cpu/instructions/pull_common.rs index 426269f..6d588c1 100644 --- a/snes-core/src/cpu/instructions/pull_common.rs +++ b/snes-core/src/cpu/instructions/pull_common.rs @@ -1,7 +1,7 @@ use crate::cpu::{registers::Registers, bus::Bus}; -pub fn do_pull(registers: &mut Registers, bus: &mut Bus, count: usize) -> Vec { +pub fn do_pull(registers: &mut Registers, bus: &mut Bus, count: usize, alter_flags: bool) -> Vec { let mut bytes = vec![]; let mut is_zero = true; for _ in 0..count { @@ -12,11 +12,13 @@ pub fn do_pull(registers: &mut Registers, bus: &mut Bus, count: usize) -> Vec> 7) == 1); + if alter_flags { + registers.set_zero_flag(is_zero); + if !bytes.is_empty() { + // Low byte is pulled first, so we need to check + // for the last byte that we pull + registers.set_negative_flag((bytes[bytes.len() - 1] >> 7) == 1); + } } bytes } \ No newline at end of file diff --git a/snes-core/src/cpu/instructions/rti.rs b/snes-core/src/cpu/instructions/rti.rs index d32d0f0..3f28a61 100644 --- a/snes-core/src/cpu/instructions/rti.rs +++ b/snes-core/src/cpu/instructions/rti.rs @@ -10,11 +10,15 @@ pub struct RTI {} impl CPUInstruction for RTI { fn execute(&self, registers: &mut Registers, bus: &mut Bus) { - registers.p = pull_common::do_pull(registers, bus, 1)[0]; - let pc_bytes = pull_common::do_pull(registers, bus, 2); - registers.pc = (pc_bytes[0] as u16) | ((pc_bytes[1] as u16) << 8); - if !registers.emulation_mode { - registers.pbr = pull_common::do_pull(registers, bus, 1)[0]; + if registers.emulation_mode { + registers.p = pull_common::do_pull(registers, bus, 1, false)[0]; + let pc_bytes = pull_common::do_pull(registers, bus, 2, false); + registers.pc = (pc_bytes[0] as u16) | ((pc_bytes[1] as u16) << 8); + } else { + registers.p = pull_common::do_pull(registers, bus, 1, false)[0]; + let pc_bytes = pull_common::do_pull(registers, bus, 2, false); + registers.pc = (pc_bytes[0] as u16) | ((pc_bytes[1] as u16) << 8); + registers.pbr = pull_common::do_pull(registers, bus, 1, false)[0]; } let (bytes, cycles) = cycles::increment_cycles_return_interrupt(registers.emulation_mode); registers.increment_pc(bytes); registers.cycles += cycles; diff --git a/snes-core/src/cpu/instructions/rtl.rs b/snes-core/src/cpu/instructions/rtl.rs index 13654d2..dfcdc45 100644 --- a/snes-core/src/cpu/instructions/rtl.rs +++ b/snes-core/src/cpu/instructions/rtl.rs @@ -10,7 +10,7 @@ pub struct RTL {} impl CPUInstruction for RTL { fn execute(&self, registers: &mut Registers, bus: &mut Bus) { - let bytes = pull_common::do_pull(registers, bus, 3); + let bytes = pull_common::do_pull(registers, bus, 3, false); // Low byte of PC is pulled first, then high byte and then PBR registers.pc = (bytes[0] as u16) | ((bytes[1] as u16) << 8); registers.pbr = bytes[2]; @@ -41,7 +41,7 @@ mod cpu_instructions_tests { let instruction = RTL{}; instruction.execute(&mut registers, &mut bus); assert_eq!(registers.pbr, 0x12); - assert_eq!(registers.pc, 0x3456); + assert_eq!(registers.pc, 0x3457); assert_eq!(registers.cycles, 6); } } diff --git a/snes-core/src/cpu/instructions/rts.rs b/snes-core/src/cpu/instructions/rts.rs index d347ef7..2cb6ccd 100644 --- a/snes-core/src/cpu/instructions/rts.rs +++ b/snes-core/src/cpu/instructions/rts.rs @@ -10,7 +10,7 @@ pub struct RTS {} impl CPUInstruction for RTS { fn execute(&self, registers: &mut Registers, bus: &mut Bus) { - let bytes = pull_common::do_pull(registers, bus, 2); + let bytes = pull_common::do_pull(registers, bus, 2, false); // Low byte of PC is pulled first, then high byte registers.pc = (bytes[0] as u16) | ((bytes[1] as u16) << 8); let (bytes, cycles) = cycles::increment_cycles_return_subroutine(); @@ -39,7 +39,7 @@ mod cpu_instructions_tests { let instruction = RTS{}; instruction.execute(&mut registers, &mut bus); assert_eq!(registers.pbr, 0x00); - assert_eq!(registers.pc, 0x1234); + assert_eq!(registers.pc, 0x1235); assert_eq!(registers.cycles, 6); } } diff --git a/snes-core/src/cpu/instructions/tcd.rs b/snes-core/src/cpu/instructions/tcd.rs index f28b11b..504b037 100644 --- a/snes-core/src/cpu/instructions/tcd.rs +++ b/snes-core/src/cpu/instructions/tcd.rs @@ -12,7 +12,7 @@ impl CPUInstruction for TCD { fn execute(&self, registers: &mut Registers, _bus: &mut Bus) { let result = registers.a; registers.d = result; - registers.set_negative_flag((result >> 7) == 1); + registers.set_negative_flag((result >> 15) == 1); registers.set_zero_flag(result == 0); let (bytes, cycles) = cycles::increment_cycles_transfer(); registers.increment_pc(bytes); registers.cycles += cycles; diff --git a/snes-core/src/cpu/instructions/tcs.rs b/snes-core/src/cpu/instructions/tcs.rs index 1a61fa9..3c36346 100644 --- a/snes-core/src/cpu/instructions/tcs.rs +++ b/snes-core/src/cpu/instructions/tcs.rs @@ -11,9 +11,11 @@ pub struct TCS {} impl CPUInstruction for TCS { fn execute(&self, registers: &mut Registers, _bus: &mut Bus) { let result = registers.a; - registers.sp = result; - registers.set_negative_flag((result >> 7) == 1); - registers.set_zero_flag(result == 0); + if registers.emulation_mode { + registers.set_low_sp(result as u8); + } else { + registers.sp = result; + } let (bytes, cycles) = cycles::increment_cycles_transfer(); registers.increment_pc(bytes); registers.cycles += cycles; } @@ -37,7 +39,7 @@ mod cpu_instructions_tests { registers.sp = 0x0000; let instruction = TCS{}; instruction.execute(&mut registers, &mut bus); - assert_eq!(registers.sp, 0xF0F0); + assert_eq!(registers.sp, 0x00F0); assert_eq!(registers.pc, 0x0001); assert_eq!(registers.cycles, 2); } diff --git a/snes-core/src/cpu/instructions/tdc.rs b/snes-core/src/cpu/instructions/tdc.rs index 28a55c4..90e76e9 100644 --- a/snes-core/src/cpu/instructions/tdc.rs +++ b/snes-core/src/cpu/instructions/tdc.rs @@ -12,7 +12,7 @@ impl CPUInstruction for TDC { fn execute(&self, registers: &mut Registers, _bus: &mut Bus) { let result = registers.d; registers.a = result; - registers.set_negative_flag((result >> 7) == 1); + registers.set_negative_flag((result >> 15) == 1); registers.set_zero_flag(result == 0); let (bytes, cycles) = cycles::increment_cycles_transfer(); registers.increment_pc(bytes); registers.cycles += cycles; diff --git a/snes-core/src/cpu/instructions/tsc.rs b/snes-core/src/cpu/instructions/tsc.rs index d36275f..5e07d8c 100644 --- a/snes-core/src/cpu/instructions/tsc.rs +++ b/snes-core/src/cpu/instructions/tsc.rs @@ -12,7 +12,7 @@ impl CPUInstruction for TSC { fn execute(&self, registers: &mut Registers, _bus: &mut Bus) { let result = registers.sp; registers.a = result; - registers.set_negative_flag((result >> 7) == 1); + registers.set_negative_flag((result >> 15) == 1); registers.set_zero_flag(result == 0); let (bytes, cycles) = cycles::increment_cycles_transfer(); registers.increment_pc(bytes); registers.cycles += cycles; diff --git a/snes-core/src/cpu/instructions/txs.rs b/snes-core/src/cpu/instructions/txs.rs index 40178c1..993db70 100644 --- a/snes-core/src/cpu/instructions/txs.rs +++ b/snes-core/src/cpu/instructions/txs.rs @@ -34,9 +34,7 @@ pub struct TXS8 {} impl CPUInstruction for TXS8 { fn execute(&self, registers: &mut Registers, _bus: &mut Bus) { let result = registers.x as u8; - registers.set_low_sp(result); - registers.set_negative_flag((result >> 7) == 1); - registers.set_zero_flag(result == 0); + registers.sp = result as u16; let (bytes, cycles) = cycles::increment_cycles_transfer(); registers.increment_pc(bytes); registers.cycles += cycles; } @@ -52,8 +50,6 @@ impl CPUInstruction for TXS16 { fn execute(&self, registers: &mut Registers, _bus: &mut Bus) { let result = registers.x; registers.sp = result; - registers.set_negative_flag((result >> 15) == 1); - registers.set_zero_flag(result == 0); let (bytes, cycles) = cycles::increment_cycles_transfer(); registers.increment_pc(bytes); registers.cycles += cycles; } diff --git a/snes-core/src/utils/addressing.rs b/snes-core/src/utils/addressing.rs index 13be771..2b5ffd4 100644 --- a/snes-core/src/utils/addressing.rs +++ b/snes-core/src/utils/addressing.rs @@ -76,8 +76,13 @@ pub fn direct_page_indirect_long(bus: &mut Bus, pc_addr: u32, direct_page_regist /// OPCODE addr,X /// OPCODE addr,Y -pub fn absolute_indexed(bus: &mut Bus, pc_addr: u32, xy: u16, dbr: u8) -> u32 { - absolute(bus, pc_addr, dbr) + (xy as u32) +pub fn absolute_indexed(bus: &mut Bus, pc_addr: u32, xy: u16, dbr: u8, is_16bit_index: bool) -> u32 { + let operand = (bus.read(pc_addr + 1) as u16) | ((bus.read(pc_addr + 2) as u16) << 8); + let mut effective_yx = xy; + if !is_16bit_index { + effective_yx &= 0xFF; + } + (((dbr as u32) << 16) | (operand as u32)) + (effective_yx as u32) } /// OPCODE (addr,X) @@ -96,8 +101,15 @@ pub fn absolute_indexed_indirect(bus: &mut Bus, pc_addr: u32, xy: u16, is_16bit_ /// OPCODE long,X /// OPCODE long,Y -pub fn absolute_long_indexed(bus: &mut Bus, pc_addr: u32, xy: u16) -> u32 { - absolute_long(bus, pc_addr) + (xy as u32) +pub fn absolute_long_indexed(bus: &mut Bus, pc_addr: u32, xy: u16, is_16bit_index: bool) -> u32 { + let operand = (bus.read(pc_addr + 1) as u32) | + ((bus.read(pc_addr + 2) as u32) << 8) | + ((bus.read(pc_addr + 3) as u32) << 16); + let mut effective_xy = xy; + if !is_16bit_index { + effective_xy &= 0xFF; + } + operand + (effective_xy as u32) } /// OPCODE dp,X @@ -194,9 +206,9 @@ impl AddressingMode { 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::AbsoluteIndexed(idx) => absolute_indexed(bus, p.pc_addr, if idx == X {p.x} else {p.y}, p.dbr, p.is_16bit_index), 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::AbsoluteLongIndexed(idx) => absolute_long_indexed(bus, p.pc_addr, if idx == X {p.x} else {p.y}, p.is_16bit_index), 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), Self::DirectPageIndirectIndexed(idx) => direct_page_indirect_indexed(bus, p.pc_addr, p.direct_page_register, if idx == X {p.x} else {p.y}, p.dbr), @@ -373,13 +385,13 @@ mod addressing_modes_tests { let pc_addr = 0x000000; bus.write(pc_addr + 1, 0x01); bus.write(pc_addr + 2, 0x02); - assert_eq!(absolute_indexed(&mut bus, pc_addr, 0x02, 0x00), 0x000203); + assert_eq!(absolute_indexed(&mut bus, pc_addr, 0x02, 0x00, true), 0x000203); let mut bus = Bus::new(); let pc_addr = 0x7F0000; bus.write(pc_addr + 1, 0x01); bus.write(pc_addr + 2, 0x02); - assert_eq!(absolute_indexed(&mut bus, pc_addr, 0x02, 0x7F), 0x7F0203); + assert_eq!(absolute_indexed(&mut bus, pc_addr, 0x02, 0x7F, true), 0x7F0203); } #[test] @@ -400,14 +412,14 @@ mod addressing_modes_tests { bus.write(pc_addr + 1, 0x01); bus.write(pc_addr + 2, 0x02); bus.write(pc_addr + 3, 0x03); - assert_eq!(absolute_long_indexed(&mut bus, pc_addr, 0x02), 0x030203); + assert_eq!(absolute_long_indexed(&mut bus, pc_addr, 0x02, true), 0x030203); let mut bus = Bus::new(); let pc_addr = 0x7E0010; bus.write(pc_addr + 1, 0x01); bus.write(pc_addr + 2, 0x02); bus.write(pc_addr + 3, 0x03); - assert_eq!(absolute_long_indexed(&mut bus, pc_addr, 0x02), 0x030203); + assert_eq!(absolute_long_indexed(&mut bus, pc_addr, 0x02, true), 0x030203); } #[test]