mirror of
https://github.com/FranLMSP/snes.git
synced 2026-10-03 16:05:18 -04:00
Fix jump addressing modes
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
use crate::cpu::{bus::Bus, registers::Registers};
|
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::read_write_common::get_effective_address;
|
||||||
use super::CPUInstruction;
|
use super::CPUInstruction;
|
||||||
@@ -15,7 +15,13 @@ pub struct JMP {
|
|||||||
impl CPUInstruction for JMP {
|
impl CPUInstruction for JMP {
|
||||||
fn execute(&self, registers: &mut Registers, bus: &mut Bus) {
|
fn execute(&self, registers: &mut Registers, bus: &mut Bus) {
|
||||||
let effective_address = get_effective_address(registers, bus, self.addressing_mode);
|
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;
|
registers.pc = effective_address as u16;
|
||||||
if is_long {
|
if is_long {
|
||||||
registers.pbr = (effective_address >> 16) as u8;
|
registers.pbr = (effective_address >> 16) as u8;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::cpu::{bus::Bus, registers::Registers};
|
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::read_write_common::get_effective_address;
|
||||||
use super::{CPUInstruction, push_common};
|
use super::{CPUInstruction, push_common};
|
||||||
@@ -15,10 +15,15 @@ pub struct JSR {
|
|||||||
impl CPUInstruction for JSR {
|
impl CPUInstruction for JSR {
|
||||||
fn execute(&self, registers: &mut Registers, bus: &mut Bus) {
|
fn execute(&self, registers: &mut Registers, bus: &mut Bus) {
|
||||||
let effective_address = get_effective_address(registers, bus, self.addressing_mode);
|
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
|
// We need to push the *next* instruction onto the stack
|
||||||
let (bytes, cycles) = cycles::increment_cycles_jsr(self.addressing_mode);
|
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();
|
let value = registers.get_pc_address();
|
||||||
if is_long {
|
if is_long {
|
||||||
push_common::do_push(registers, bus, &[
|
push_common::do_push(registers, bus, &[
|
||||||
@@ -64,7 +69,7 @@ mod cpu_instructions_tests {
|
|||||||
instruction.execute(&mut registers, &mut bus);
|
instruction.execute(&mut registers, &mut bus);
|
||||||
assert_eq!(bus.read(0x1FC), 0x00);
|
assert_eq!(bus.read(0x1FC), 0x00);
|
||||||
assert_eq!(bus.read(0x1FB), 0x12);
|
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.pbr, 0xAA);
|
||||||
assert_eq!(registers.pc, 0xBBCC);
|
assert_eq!(registers.pc, 0xBBCC);
|
||||||
assert_eq!(registers.sp, 0x1F9);
|
assert_eq!(registers.sp, 0x1F9);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ pub fn get_effective_address(registers: &Registers, bus: &mut Bus, addressing_mo
|
|||||||
stack_pointer: registers.sp,
|
stack_pointer: registers.sp,
|
||||||
x: registers.x, y: registers.y,
|
x: registers.x, y: registers.y,
|
||||||
dbr: registers.dbr,
|
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,
|
stack_pointer: registers.sp,
|
||||||
x: registers.x, y: registers.y,
|
x: registers.x, y: registers.y,
|
||||||
dbr: registers.dbr,
|
dbr: registers.dbr,
|
||||||
|
is_16bit_index: registers.is_16bit_index(),
|
||||||
},
|
},
|
||||||
bus,
|
bus,
|
||||||
)
|
)
|
||||||
@@ -39,6 +41,7 @@ pub fn read_16bit_from_address(registers: &Registers, bus: &mut Bus, addressing_
|
|||||||
stack_pointer: registers.sp,
|
stack_pointer: registers.sp,
|
||||||
x: registers.x, y: registers.y,
|
x: registers.x, y: registers.y,
|
||||||
dbr: registers.dbr,
|
dbr: registers.dbr,
|
||||||
|
is_16bit_index: registers.is_16bit_index(),
|
||||||
},
|
},
|
||||||
bus,
|
bus,
|
||||||
)
|
)
|
||||||
@@ -55,6 +58,7 @@ pub fn write_8bit_to_address(registers: &mut Registers, bus: &mut Bus, addressin
|
|||||||
stack_pointer: registers.sp,
|
stack_pointer: registers.sp,
|
||||||
x: registers.x, y: registers.y,
|
x: registers.x, y: registers.y,
|
||||||
dbr: registers.dbr,
|
dbr: registers.dbr,
|
||||||
|
is_16bit_index: registers.is_16bit_index(),
|
||||||
},
|
},
|
||||||
bus,
|
bus,
|
||||||
value,
|
value,
|
||||||
@@ -72,6 +76,7 @@ pub fn write_16bit_to_address(registers: &mut Registers, bus: &mut Bus, addressi
|
|||||||
stack_pointer: registers.sp,
|
stack_pointer: registers.sp,
|
||||||
x: registers.x, y: registers.y,
|
x: registers.x, y: registers.y,
|
||||||
dbr: registers.dbr,
|
dbr: registers.dbr,
|
||||||
|
is_16bit_index: registers.is_16bit_index(),
|
||||||
},
|
},
|
||||||
bus,
|
bus,
|
||||||
value,
|
value,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ pub struct ResolveAddressParams {
|
|||||||
pub stack_pointer: u16,
|
pub stack_pointer: u16,
|
||||||
pub x: u16,
|
pub x: u16,
|
||||||
pub y: 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)
|
/// OPCODE (addr)
|
||||||
pub fn absolute_indirect(bus: &mut Bus, pc_addr: u32, dbr: u8) -> u32 {
|
pub fn absolute_indirect(bus: &mut Bus, pc_addr: u32) -> u32 {
|
||||||
let addr = absolute(bus, pc_addr, dbr);
|
let pbr = pc_addr & 0xFF0000;
|
||||||
let dbr = pc_addr & 0xFF0000;
|
let addr = ((bus.read(pc_addr + 2) as u32) << 8) | (bus.read(pc_addr + 1) as u32);
|
||||||
dbr | ((bus.read(addr) as u32) << 8) | (bus.read(addr + 1) as u32)
|
pbr | ((bus.read(addr + 1) as u32) << 8) | (bus.read(addr) as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// OPCODE long
|
/// OPCODE long
|
||||||
@@ -45,11 +46,11 @@ pub fn absolute_long(bus: &mut Bus, pc_addr: u32) -> u32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// OPCODE (addr)
|
/// OPCODE (addr)
|
||||||
pub fn absolute_indirect_long(bus: &mut Bus, pc_addr: u32, dbr: u8) -> u32 {
|
pub fn absolute_indirect_long(bus: &mut Bus, pc_addr: u32) -> u32 {
|
||||||
let addr = absolute(bus, pc_addr, dbr);
|
let addr = (bus.read(pc_addr + 1) as u32) | ((bus.read(pc_addr + 2) as u32) << 8);
|
||||||
((bus.read(addr) as u32) << 16) |
|
(bus.read(addr) as u32) |
|
||||||
((bus.read(addr + 1) as u32) << 8) |
|
((bus.read(addr + 1) as u32) << 8) |
|
||||||
(bus.read(addr + 2) as u32)
|
((bus.read(addr + 2) as u32) << 16)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// OPCODE dp
|
/// 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)
|
absolute(bus, pc_addr, dbr) + (xy as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// OPCODE (addr)
|
/// OPCODE (addr,X)
|
||||||
pub fn absolute_indexed_indirect(bus: &mut Bus, pc_addr: u32, xy: u16, dbr: u8) -> u32 {
|
/// OPCODE (addr,Y)
|
||||||
let addr = absolute_indexed(bus, pc_addr, xy, dbr);
|
pub fn absolute_indexed_indirect(bus: &mut Bus, pc_addr: u32, xy: u16, is_16bit_index: bool) -> u32 {
|
||||||
let dbr = pc_addr & 0xFF0000;
|
let pbr = pc_addr & 0xFF0000;
|
||||||
dbr | ((bus.read(addr) as u32) << 8) | (bus.read(addr + 1) as u32)
|
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::Accumulator => p.pc_addr,
|
||||||
Self::Immediate => immediate(p.pc_addr),
|
Self::Immediate => immediate(p.pc_addr),
|
||||||
Self::Absolute => absolute(bus, p.pc_addr, p.dbr),
|
Self::Absolute => absolute(bus, p.pc_addr, p.dbr),
|
||||||
Self::AbsoluteIndirect => absolute_indirect(bus, p.pc_addr, p.dbr),
|
Self::AbsoluteIndirect => absolute_indirect(bus, p.pc_addr),
|
||||||
Self::AbsoluteIndirectLong => absolute_indirect_long(bus, p.pc_addr, p.dbr),
|
Self::AbsoluteIndirectLong => absolute_indirect_long(bus, p.pc_addr),
|
||||||
Self::AbsoluteLong => absolute_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::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::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::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),
|
||||||
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::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::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::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(pc_addr + 1, addr);
|
||||||
bus.write(addr as u32, 0x02);
|
bus.write(addr as u32, 0x02);
|
||||||
bus.write((addr + 1) as u32, 0x01);
|
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 pc_addr = 0x7E0010;
|
||||||
let addr = 0x55;
|
let addr = 0x55;
|
||||||
bus.write(pc_addr + 1, addr);
|
bus.write(pc_addr + 1, addr);
|
||||||
bus.write(addr as u32, 0x02);
|
bus.write(addr as u32, 0x02);
|
||||||
bus.write((addr + 1) as u32, 0x01);
|
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 pc_addr = 0x7E0010;
|
||||||
let addr = 0x55;
|
let addr = 0x55;
|
||||||
bus.write(pc_addr + 1, addr);
|
bus.write(pc_addr + 1, addr);
|
||||||
bus.write(addr as u32, 0x02);
|
bus.write(addr as u32, 0x02);
|
||||||
bus.write((addr + 1) as u32, 0x01);
|
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]
|
#[test]
|
||||||
@@ -297,7 +304,7 @@ mod addressing_modes_tests {
|
|||||||
bus.write(addr as u32, 0x03);
|
bus.write(addr as u32, 0x03);
|
||||||
bus.write((addr + 1) as u32, 0x02);
|
bus.write((addr + 1) as u32, 0x02);
|
||||||
bus.write((addr + 2) as u32, 0x01);
|
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(pc_addr + 1, addr);
|
||||||
bus.write(addr as u32, 0x02);
|
bus.write(addr as u32, 0x02);
|
||||||
bus.write((addr + 1) as u32, 0x01);
|
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]
|
#[test]
|
||||||
@@ -523,7 +530,7 @@ mod addressing_modes_tests {
|
|||||||
bus.write(pc_addr + 2, 0x10);
|
bus.write(pc_addr + 2, 0x10);
|
||||||
bus.write(0x001020, 0xFE);
|
bus.write(0x001020, 0xFE);
|
||||||
let val = AddressingMode::Absolute.read_8bit(
|
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,
|
&mut bus,
|
||||||
);
|
);
|
||||||
assert_eq!(val, 0xFE);
|
assert_eq!(val, 0xFE);
|
||||||
@@ -535,7 +542,7 @@ mod addressing_modes_tests {
|
|||||||
bus.write(0x001020, 0xFF);
|
bus.write(0x001020, 0xFF);
|
||||||
bus.write(0x001021, 0xEE);
|
bus.write(0x001021, 0xEE);
|
||||||
let val = AddressingMode::Absolute.read_16bit(
|
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,
|
&mut bus,
|
||||||
);
|
);
|
||||||
assert_eq!(val, 0xEEFF);
|
assert_eq!(val, 0xEEFF);
|
||||||
|
|||||||
Reference in New Issue
Block a user