From e5a40041252bfbf21312c933fdb4c9a111c26278 Mon Sep 17 00:00:00 2001 From: Brooke Chalmers Date: Wed, 22 Nov 2023 20:37:32 -0500 Subject: [PATCH] Implement NMOS quirks --- src/cpu/execute.rs | 31 ++++++++++++++++++++++++++++++- src/cpu/fetch.rs | 24 ++++++++++++++++++++---- src/cpu/mod.rs | 2 +- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/cpu/execute.rs b/src/cpu/execute.rs index a2279a4f..9aaeb2c1 100644 --- a/src/cpu/execute.rs +++ b/src/cpu/execute.rs @@ -2,6 +2,8 @@ use crate::cpu::fetch::Fetch; use crate::cpu::registers::{flags, Alu}; use crate::cpu::{InterruptHandler, MemoryIO, Mos6502, Stack}; +use super::Mos6502Variant; + pub trait Execute { /// Execute the given opcode, returning either the number of cycles used or an error. fn execute(&mut self, opcode: u8) -> Result; @@ -133,6 +135,10 @@ impl Execute for Mos6502 { // ASL let (address, cycles) = self.fetch_operand_address(opcode); let value = self.read(address); + + if let Mos6502Variant::NMOS = self.variant { + self.write(address, value); + } let result = value << 1; self.registers.sr.write(flags::CARRY, value & 0x80 != 0); @@ -154,6 +160,11 @@ impl Execute for Mos6502 { // LSR let (address, cycles) = self.fetch_operand_address(opcode); let value = self.read(address); + + if let Mos6502Variant::NMOS = self.variant { + self.write(address, value); + } + let result = value >> 1; self.registers.sr.write(flags::CARRY, value & 0x01 != 0); @@ -176,6 +187,11 @@ impl Execute for Mos6502 { // ROL let (address, cycles) = self.fetch_operand_address(opcode); let value = self.read(address); + + if let Mos6502Variant::NMOS = self.variant { + self.write(address, value); + } + let result = (value << 1) | (self.registers.sr.read(flags::CARRY) as u8); self.registers.sr.write(flags::CARRY, value & 0x80 != 0); @@ -198,6 +214,11 @@ impl Execute for Mos6502 { // ROR let (address, cycles) = self.fetch_operand_address(opcode); let value = self.read(address); + + if let Mos6502Variant::NMOS = self.variant { + self.write(address, value); + } + let result = value >> 1 | (self.registers.sr.read(flags::CARRY) as u8) << 7; self.registers.sr.write(flags::CARRY, value & 0x01 != 0); @@ -341,7 +362,15 @@ impl Execute for Mos6502 { 0x4C => (self.fetch_word(), 3), 0x6C => { let indirect = self.fetch_word(); - (self.read_word(indirect), 5) + + if self.variant == Mos6502Variant::NMOS && indirect & 0xFF == 0xFF { + let lo = self.read(indirect); + let hi = self.read(indirect & 0xFF00); + ((hi as u16) << 8 | lo as u16, 5) + } else { + // normal behavior + (self.read_word(indirect), 5) + } } _ => unreachable!(), }; diff --git a/src/cpu/fetch.rs b/src/cpu/fetch.rs index d4afd398..ec6b73e7 100644 --- a/src/cpu/fetch.rs +++ b/src/cpu/fetch.rs @@ -1,5 +1,7 @@ use crate::cpu::{MemoryIO, Mos6502}; +use super::Mos6502Variant; + /// Fetch values or addresses from memory, optionally dependent on the current /// opcode. pub trait Fetch { @@ -88,15 +90,29 @@ impl Fetch for Mos6502 { 0x1C | 0x1D => { // Absolute,X let base = self.fetch_word(); - (base + self.registers.x as u16, 4) + let indexed = base + self.registers.x as u16; + + if self.variant == Mos6502Variant::NMOS && base & 0xFF00 != indexed & 0xFF00 { + self.read(base & 0xFF00 | indexed & 0x00FF); + (indexed, 5) + } else { + (indexed, 4) + } } 0x1E | 0x1F => { // Absolute,X or Absolute,Y let base = self.fetch_word(); - if opcode & 0xC0 == 0x80 { - (base + self.registers.y as u16, 4) + let indexed = if opcode & 0xC0 == 0x80 { + base + self.registers.y as u16 + } else { + base + self.registers.x as u16 + }; + + if self.variant == Mos6502Variant::NMOS && base & 0xFF00 != indexed & 0xFF00 { + self.read(base & 0xFF00 | indexed & 0x00FF); + (indexed, 5) } else { - (base + self.registers.x as u16, 4) + (indexed, 4) } } _ => unreachable!(), diff --git a/src/cpu/mod.rs b/src/cpu/mod.rs index b259eb27..aa6b9524 100644 --- a/src/cpu/mod.rs +++ b/src/cpu/mod.rs @@ -8,7 +8,7 @@ use registers::{flags, Registers}; const CLOCKS_PER_POLL: u32 = 100; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq)] pub enum Mos6502Variant { /// 6502 NMOS,