mirror of
https://github.com/FranLMSP/snes.git
synced 2026-01-01 07:21:35 -05:00
Fix more instructions
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::cpu::{registers::Registers, bus::Bus};
|
||||
|
||||
|
||||
pub fn do_pull(registers: &mut Registers, bus: &mut Bus, count: usize) -> Vec<u8> {
|
||||
pub fn do_pull(registers: &mut Registers, bus: &mut Bus, count: usize, alter_flags: bool) -> Vec<u8> {
|
||||
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<u8
|
||||
}
|
||||
bytes.push(byte);
|
||||
}
|
||||
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);
|
||||
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
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user