Fix more instructions

This commit is contained in:
2024-03-15 22:52:00 -05:00
parent e68e9f2281
commit d32aa96825
17 changed files with 63 additions and 47 deletions

View File

@@ -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) {

View File

@@ -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());

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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());

View File

@@ -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());

View File

@@ -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
}

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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]