From 97d6b3fd89dcfc06d9d4bb221c9b011db3495416 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Tue, 23 Apr 2024 17:07:05 +0100 Subject: [PATCH] split the Indirect addressing mode into BuggyIndirect and IndirectWithFix --- src/cpu.rs | 23 ++++++++++++++++++++--- src/instruction.rs | 21 ++++++++++++++++++--- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index f01bced..3953c77 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -147,12 +147,29 @@ impl CPU { // (Output: a 16-bit address) OpInput::UseAddress(address_from_bytes(slice[0], slice[1]).wrapping_add(y.into())) } - AddressingMode::Indirect => { + AddressingMode::IndirectWithFix => { // Use [u8, ..2] from instruction as an address. Interpret the // two bytes starting at that address as an address. // (Output: a 16-bit address) - let slice = read_address(memory, arr_to_addr(&slice)); - OpInput::UseAddress(arr_to_addr(&slice)) + // TODO: If the pointer ends in 0xff, then incrementing it would propagate + // the carry to the high byte of the pointer. This incurs a cost of one + // machine on the real 65C02, which is not implemented here. + let slice = read_address(memory, address_from_bytes(slice[0], slice[1])); + OpInput::UseAddress(address_from_bytes(slice[0], slice[1])) + } + AddressingMode::BuggyIndirect => { + // Use [u8, ..2] from instruction as an address. Interpret the + // two bytes starting at that address as an address. + // (Output: a 16-bit address) + let pointer = address_from_bytes(slice[0], slice[1]); + + let low_byte_of_target = memory.get_byte(pointer); + + let low_byte_of_incremented_pointer = pointer.to_le_bytes()[0].wrapping_add(1); + let incremented_pointer = u16::from_le_bytes([low_byte_of_incremented_pointer, pointer.to_le_bytes()[1]]); + + let high_byte_of_target = memory.get_byte(incremented_pointer); + OpInput::UseAddress(address_from_bytes(low_byte_of_target, high_byte_of_target)) } AddressingMode::IndexedIndirectX => { // Use [u8, ..1] from instruction diff --git a/src/instruction.rs b/src/instruction.rs index b579c6d..d3b1775 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -127,7 +127,8 @@ pub enum AddressingMode { Absolute, // 3 JMP $1000 full 16-bit address AbsoluteX, // 3 STA $1000,X full 16-bit address plus X register AbsoluteY, // 3 STA $1000,Y full 16-bit address plus Y register - Indirect, // 3 JMP ($1000) jump to address stored at address + BuggyIndirect, // 3 JMP ($1000) jump to address stored at address + IndirectWithFix, // 3 JMP ($1000) jump to address stored at address IndexedIndirectX, // 2 LDA ($10,X) load from address stored at (constant // zero page address plus X register) IndirectIndexedY, // 2 LDA ($10),Y load from (address stored at constant @@ -147,7 +148,8 @@ impl AddressingMode { AddressingMode::Absolute => 2, AddressingMode::AbsoluteX => 2, AddressingMode::AbsoluteY => 2, - AddressingMode::Indirect => 2, + AddressingMode::IndirectWithFix => 2, + AddressingMode::BuggyIndirect => 2, AddressingMode::IndexedIndirectX => 1, AddressingMode::IndirectIndexedY => 1, } @@ -270,7 +272,7 @@ impl crate::Variant for Nmos6502 { 0x69 => Some((Instruction::ADC, AddressingMode::Immediate)), 0x6a => Some((Instruction::ROR, AddressingMode::Accumulator)), 0x6b => None, - 0x6c => Some((Instruction::JMP, AddressingMode::Indirect)), + 0x6c => Some((Instruction::JMP, AddressingMode::BuggyIndirect)), 0x6d => Some((Instruction::ADC, AddressingMode::Absolute)), 0x6e => Some((Instruction::ROR, AddressingMode::Absolute)), 0x6f => None, @@ -466,3 +468,16 @@ impl crate::Variant for RevisionA { } } } + +/// Emulates the 65C02, which has a few bugfixes, and another addressing mode +pub struct Cmos6502; + +impl crate::Variant for Cmos6502 { + fn decode(opcode: u8) -> Option<(Instruction, AddressingMode)> { + // TODO: We obviously need to add the other CMOS isntructions here. + match opcode { + 0x6c => Some((Instruction::JMP, AddressingMode::IndirectWithFix)), + _ => Nmos6502::decode(opcode), + } + } +}