From 6ed5f0339a06245295af8c215cf7e25f8cfe518d Mon Sep 17 00:00:00 2001 From: Daniel Bauer Date: Sat, 4 Jan 2020 23:13:06 +0100 Subject: [PATCH] refractoring of NES --- src/main.rs | 25 ++- src/nes.rs | 67 +++++-- src/nes/bus.rs | 204 -------------------- src/nes/cartridge.rs | 2 +- src/nes/cpu.rs | 448 +++++++++++++++++++++---------------------- src/nes/disasm.rs | 8 +- src/nes/memory.rs | 107 +++++++++++ src/nes/ppu.rs | 10 +- 8 files changed, 393 insertions(+), 478 deletions(-) delete mode 100644 src/nes/bus.rs create mode 100644 src/nes/memory.rs diff --git a/src/main.rs b/src/main.rs index dc157be..8da7bc2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,13 +9,10 @@ extern crate rand; mod nes; +use crate::nes::*; use std::path::Path; use piston_window::*; -use nes::NES; -use nes::types::*; use nes::cpu::*; -use nes::bus::*; -use nes::cartridge::*; use nes::disasm::*; use opengl_graphics::OpenGL; use log::Level; @@ -42,12 +39,12 @@ fn main() -> Result<(), Error> { let mut nes = NES::new(); let cartridge = Path::new("test_roms/nestest.nes"); let cartridge = Cartridge::new(cartridge)?; - nes.insert_cartrige(cartridge); - nes.cpu.find_pc_addr(&nes.bus); + nes.insert_cartridge(cartridge); + nes.start(); // nes.cpu.regs.pc = 0xC000; // disassemble instructions - let disasm = Disasm::disassemble(&nes.bus, 0xC000, 0xFFFF).unwrap(); + let disasm = Disasm::disassemble(&nes.memory, 0xC000, 0xFFFF).unwrap(); // Prepare window and drawing resources let mut window: PistonWindow = WindowSettings::new("xXx NESemu xXx", [256*3, 240*2+50]) @@ -92,7 +89,7 @@ fn main() -> Result<(), Error> { let transform = c.transform.trans(256.0, 50.0).scale(2.0, 2.0); image(&texture, transform, g); }); - render_debug(&mut window, &event, &mut glyph_brush, &nes.cpu, &nes.bus, &disasm); + render_debug(&mut window, &event, &mut glyph_brush, &nes.cpu, &nes, &disasm); } if let Some(Button::Keyboard(key)) = event.press_args() { match key { @@ -103,7 +100,7 @@ fn main() -> Result<(), Error> { nes.clock(); } } - Key::R => nes.cpu.reset(&mut nes.bus), + Key::R => nes.reset(), Key::Space => run = !run, Key::Up => { event_settings.ups = (event_settings.ups as f64 * 1.1) as u64 + 1; @@ -124,7 +121,7 @@ fn main() -> Result<(), Error> { fn render_debug(window: &mut PistonWindow, event: &Event, glyphs: &mut GlyphBrush, - cpu: &CPU, _bus: &Bus, disasm: &Disasm) { + cpu: &CPU, _nes: &NES, disasm: &Disasm) { window.draw_2d(event, |_c, _g, _d| { @@ -132,7 +129,7 @@ fn render_debug(window: &mut PistonWindow, event: &Event, render_cpu(glyphs, cpu, debug_offset); render_disasm(glyphs, disasm, cpu.regs.pc, [debug_offset[0], debug_offset[1] + (7.0 * (FT_LINE_DISTANCE+FT_SIZE_PX))]); - // render_memory(glyphs, bus, + // render_memory(glyphs, nes, // [debug_offset[0] + 400.0, debug_offset[1]]); }); glyphs.use_queue().draw(&mut window.encoder, &window.output_color).unwrap(); @@ -289,13 +286,13 @@ fn render_disasm(glyphs: &mut GlyphBrush, } } -fn render_memory(glyphs: &mut GlyphBrush, bus: &Bus, offset: [f32; 2]) { +fn render_memory(glyphs: &mut GlyphBrush, nes: &NES, offset: [f32; 2]) { let mut position_y = (offset[0], offset[1]); for page in (0x0000..0x00FF).step_by(16) { position_y.1 += FT_LINE_DISTANCE + FT_SIZE_PX; let mut line = format!("{:#06x}:", page); (0u16..16u16).map(|offset| offset + page) - .map(|addr| bus.readb(addr)) + .map(|addr| nes.memory.readb(addr)) .map(|val| format!(" {:02x}", val)) .for_each(|s| line.push_str(&s)); glyphs.queue(Section { @@ -312,7 +309,7 @@ fn render_memory(glyphs: &mut GlyphBrush, bus: &Bus, offset: position_y.1 += FT_LINE_DISTANCE + FT_SIZE_PX; let mut line = format!("{:#06x}:", page); (0u16..16u16).map(|offset| offset + page) - .map(|addr| bus.readb(addr)) + .map(|addr| nes.memory.readb(addr)) .map(|val| format!(" {:02x}", val)) .for_each(|s| line.push_str(&s)); glyphs.queue(Section { diff --git a/src/nes.rs b/src/nes.rs index f3b32d2..537ed49 100644 --- a/src/nes.rs +++ b/src/nes.rs @@ -1,46 +1,87 @@ -use crate::nes::bus::*; -use crate::nes::cartridge::Cartridge; -use crate::nes::ppu::*; -use crate::nes::cpu::*; +pub use crate::nes::cartridge::Cartridge; +pub use crate::nes::ppu::PPU; +pub use crate::nes::cpu::CPU; +pub use crate::nes::types::*; +pub use crate::nes::memory::*; #[allow(non_snake_case)] pub mod cpu; -pub mod bus; +pub mod memory; pub mod types; pub mod disasm; pub mod cartridge; pub mod mappers; pub mod ppu; - +// The NES class connects all elements of the NES together. It acts +// as the mediator between the different components and hold the RAM pub struct NES { - pub bus: Bus, pub cpu: CPU, pub ppu: PPU, + pub memory: NESMemory, pub clock_count: u64, } impl NES { pub fn new() -> Self { NES { - bus: Bus::new(), cpu: CPU::new(), ppu: PPU::new(), + memory: NESMemory::new(), clock_count: 0, } } - pub fn insert_cartrige(&mut self, cartrige: Cartridge) { - self.bus.insert_cartrige(cartrige); + pub fn insert_cartridge(&mut self, cartridge: Cartridge) { + self.memory.insert_cartridge(cartridge); + } + + pub fn start(&mut self) { + self.cpu.find_pc_addr(&self.memory); + } + + pub fn reset(&mut self) { + self.clock_count = 0; + self.cpu.reset(&self.memory); } pub fn clock(&mut self) { self.clock_count += 1; if self.clock_count % 3 == 0 { - self.cpu.clock(&mut self.bus); + self.cpu.clock(&mut self.memory); } - self.ppu.clock(&mut self.bus); - + self.ppu.clock(&mut self.memory); } } + +// impl PPUMemory for NES { +// fn readb_ppu(&self, addr: Addr) -> Byte { +// if let Some(cartridge) = &self.cartridge { +// if CART_ADDR_RANGE[0] <= addr && addr <= CART_ADDR_RANGE[1] { +// return cartridge.readb(addr) +// } +// } + +// if RAM_ADDR_RANGE[0] <= addr && addr <= RAM_ADDR_RANGE[1] { +// // Ram is 3x mirrored after 07ff +// return self.ram[(addr & RAM_PHYS_RANGE[1]) as usize] +// } +// 0x0000 // generic response +// } + +// fn writeb_ppu(&mut self, addr: Addr, data: Byte) { +// if let Some(cartridge) = &mut self.cartridge { +// if CART_ADDR_RANGE[0] <= addr && addr <= CART_ADDR_RANGE[1] { +// cartridge.writeb(addr, data) +// } +// } + +// if RAM_ADDR_RANGE[0] <= addr && addr <= RAM_ADDR_RANGE[1] { +// // Ram is 3x mirrored after 07ff +// self.ram[(addr & RAM_PHYS_RANGE[1]) as usize] = data +// } +// } +// } + + diff --git a/src/nes/bus.rs b/src/nes/bus.rs deleted file mode 100644 index 90aa958..0000000 --- a/src/nes/bus.rs +++ /dev/null @@ -1,204 +0,0 @@ -use crate::nes::types::*; -use crate::nes::cartridge::Cartridge; - -const RAM_ADDR_RANGE: [Addr; 2] = [0x0000, 0x1fff]; -const RAM_PHYS_RANGE: [Addr; 2] = [0x0000, 0x07ff]; -const PPU_ADDR_RANGE: [Addr; 2] = [0x2000, 0x3fff]; -const PPU_PHYS_RANGE: [Addr; 2] = [0x2000, 0x2007]; -const CART_ADDR_RANGE: [Addr; 2] = [0x4020, 0xffff]; - -// Generic interface for a device allowing to read/write memory -pub trait Memory { - fn readb(&self, addr: Addr) -> Byte; - fn writeb(&mut self, addr: Addr, data: Byte); - fn readw(&self, addr: Addr) -> Word { - let lo = self.readb(addr); - let hi = self.readb(addr+1); - (hi as Word) << 8 | lo as Word - } - fn writew(&mut self, addr: Addr, data: Word) { - self.writeb(addr, data as Byte); - self.writeb(addr + 1, (data >> 8) as Byte); - } -} - -// PPU interface to allow read/write of memory -pub trait PPUMemory { - fn readb_ppu(&self, addr: Addr) -> Byte; - fn writeb_ppu(&mut self, addr: Addr, data: Byte); - fn readw_ppu(&self, addr: Addr) -> Word { - let lo = self.readb_ppu(addr); - let hi = self.readb_ppu(addr+1); - (hi as Word) << 8 | lo as Word - } - fn writew_ppu(&mut self, addr: Addr, data: Word) { - self.writeb_ppu(addr, data as Byte); - self.writeb_ppu(addr + 1, (data >> 8) as Byte); - } -} - -// Impl by devices to access the Bus -pub trait BusDevice { - fn readb(&self, bus: &T, addr: Addr) -> Byte { - bus.readb(addr) - } - - fn readw(&self, bus: &T, addr: Addr) -> Word { - bus.readw(addr) - } - - fn writeb(&mut self, bus: &mut T, addr: Addr, data: Byte) { - bus.writeb(addr, data) - } -} - -// Impl by devices to access the Bus -pub trait PPUBusDevice { - fn readb(&self, bus: &T, addr: Addr) -> Byte { - bus.readb_ppu(addr) - } - - fn readw(&self, bus: &T, addr: Addr) -> Word { - bus.readw_ppu(addr) - } - - fn writeb(&mut self, bus: &mut T, addr: Addr, data: Byte) { - bus.writeb_ppu(addr, data) - } -} - -// Impl by devices to do stuff on bus clock -pub trait Clockable { - fn clock(&mut self, bus: &mut T); -} - - -// A simple bus giving access to a chunk of memory -// and the cartrige -pub struct Bus { - ram: [Byte; 0x0800], // 2kb - cartrige: Option -} - -impl Bus { - pub fn new() -> Bus { - Bus { - ram: [0; 0x0800], - cartrige: None, - } - } - - pub fn insert_cartrige(&mut self, cartrige: Cartridge) { - self.cartrige = Some(cartrige); - } -} - -impl Memory for Bus { - - fn readb(&self, addr: Addr) -> Byte { - if let Some(cartrige) = &self.cartrige { - if CART_ADDR_RANGE[0] <= addr && addr <= CART_ADDR_RANGE[1] { - return cartrige.readb(addr) - } - } - - if RAM_ADDR_RANGE[0] <= addr && addr <= RAM_ADDR_RANGE[1] { - // Ram is 3x mirrored after 0x07ff - return self.ram[(addr & RAM_PHYS_RANGE[1]) as usize] - } - // if PPU_ADDR_RANGE[0] <= addr && addr <= PPU_ADDR_RANGE[1] { - // // PPU memory is mirrored after 0x2007 to 0x3fff - // return self.ram[(addr & PPU_PHYS_RANGE[1]) as usize] - // } - 0x0000 // generic response - } - - fn writeb(&mut self, addr: Addr, data: Byte) { - if let Some(cartrige) = &mut self.cartrige { - if CART_ADDR_RANGE[0] <= addr && addr <= CART_ADDR_RANGE[1] { - cartrige.writeb(addr, data) - } - } - if RAM_ADDR_RANGE[0] <= addr && addr <= RAM_ADDR_RANGE[1] { - // Ram is 3x mirrored after 07ff - self.ram[(addr & RAM_PHYS_RANGE[1]) as usize] = data - } - // if PPU_ADDR_RANGE[0] <= addr && addr <= PPU_ADDR_RANGE[1] { - // // PPU memory is mirrored after 0x2007 to 0x3fff - // self.ram[(addr & PPU_PHYS_RANGE[1]) as usize] = data - // } - } -} - -impl PPUMemory for Bus { - fn readb_ppu(&self, addr: Addr) -> Byte { - if let Some(cartrige) = &self.cartrige { - if CART_ADDR_RANGE[0] <= addr && addr <= CART_ADDR_RANGE[1] { - return cartrige.readb(addr) - } - } - - if RAM_ADDR_RANGE[0] <= addr && addr <= RAM_ADDR_RANGE[1] { - // Ram is 3x mirrored after 07ff - return self.ram[(addr & 0x07ff) as usize] - } - 0x0000 // generic response - } - - fn writeb_ppu(&mut self, addr: Addr, data: Byte) { - if let Some(cartrige) = &mut self.cartrige { - if CART_ADDR_RANGE[0] <= addr && addr <= CART_ADDR_RANGE[1] { - cartrige.writeb(addr, data) - } - } - - if RAM_ADDR_RANGE[0] <= addr && addr <= RAM_ADDR_RANGE[1] { - // Ram is 3x mirrored after 07ff - self.ram[(addr & 0x07ff) as usize] = data - } - } -} - - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_consts() { - assert_eq!(RAM_ADDR_RANGE[1] - RAM_ADDR_RANGE[0] + 1, 2048*4); - assert_eq!(RAM_PHYS_RANGE[1] - RAM_PHYS_RANGE[0] + 1, 2048); - - } - - #[test] - fn test_read_write_ram() { - let mut bus = Bus::new(); - - // read/write to ram addr - bus.writeb(0x0000, 1); - assert_eq!(1, bus.readb(0x0000)); - assert_eq!(1, bus.readb(0x0800)); - - // read/write to mirrored ram - bus.writeb(0x0801, 2); - assert_eq!(2, bus.readb(0x0801)); - assert_eq!(2, bus.readb(0x0001)); - } - - #[test] - fn test_read_write_cartrige() { - let mut bus = Bus::new(); - - // read/write non-existant to cartrige - bus.writeb(0x4030, 3); - assert_eq!(0, bus.readb(0x4030)); - - let cartrige = Cartridge::dummy(); - bus.insert_cartrige(cartrige); - bus.writeb(0x4030, 3); - assert_eq!(3, bus.readb(0x4030)); - } - - -} \ No newline at end of file diff --git a/src/nes/cartridge.rs b/src/nes/cartridge.rs index 30524bb..458f246 100644 --- a/src/nes/cartridge.rs +++ b/src/nes/cartridge.rs @@ -1,5 +1,5 @@ use crate::nes::mappers::*; -use crate::nes::bus::Memory; +use crate::nes::Memory; use failure::Error; use std::io::prelude::*; use std::fs::File; diff --git a/src/nes/cpu.rs b/src/nes/cpu.rs index d10ff2d..617ddfe 100644 --- a/src/nes/cpu.rs +++ b/src/nes/cpu.rs @@ -1,11 +1,11 @@ +use crate::nes::{Memory,MemoryReader}; +use crate::nes::types::*; + pub mod instructions; use instructions::{Instruction,Operation,AddrMode}; use core::fmt::{Debug,Formatter,Result}; -use crate::nes::bus::*; -use crate::nes::types::*; use log::{debug}; -use failure::err_msg; pub struct Registers { pub a: Byte, @@ -58,31 +58,8 @@ pub struct CPU { stopped: bool, } -// Default implementation to read/write from bus -impl BusDevice for CPU { } - -// A cpu is clockable -impl Clockable for CPU { - fn clock(&mut self, bus: &mut T) { - // if processor is halted, we do nothing anymore - if self.stopped { - panic!("Stopped processor clock'ed!"); - } - - if self.cycles_ahead == 0 { - let opcode = self.readb_pc(bus); - self.curr_op = opcode; - let instruction = Instruction::decode_op(opcode); - - info!("{:#06X} {:02X} {} A:{:02X} X:{:02X} Y:{:02X} P:{:02X} SP:{:02X} CYC:{}", - self.regs.pc-1, opcode, instruction.operation, - self.regs.a, self.regs.x, self.regs.y, self.regs.flags, self.regs.sp, self.cycles); - self.cycles_ahead += self.run_instruction(bus, instruction); - } - self.cycles_ahead -= 1; - self.cycles += 1 - } -} +// Default implementation to read/write from mem +impl MemoryReader for CPU { } impl CPU { pub fn new() -> Self { @@ -95,25 +72,45 @@ impl CPU { } } + pub fn clock(&mut self, mem: &mut T) { + // if processor is halted, we do nothing anymore + if self.stopped { + panic!("Stopped processor clock'ed!"); + } + + if self.cycles_ahead == 0 { + let opcode = self.readb_pc(mem); + self.curr_op = opcode; + let instruction = Instruction::decode_op(opcode); + + info!("{:#06X} {:02X} {} A:{:02X} X:{:02X} Y:{:02X} P:{:02X} SP:{:02X} CYC:{}", + self.regs.pc-1, opcode, instruction.operation, + self.regs.a, self.regs.x, self.regs.y, self.regs.flags, self.regs.sp, self.cycles); + self.cycles_ahead += self.run_instruction(mem, instruction); + } + self.cycles_ahead -= 1; + self.cycles += 1 + } + // sets PC - pub fn find_pc_addr(&mut self, bus: &T) { + pub fn find_pc_addr(&mut self, mem: &T) { // 0xfffc and 0xfffc+1 stores the location of the first op code (where // the program starts). Read it and set pc accordingly. let addr: u16 = 0xfffc; - let lo = bus.readb(addr); - let hi = bus.readb(addr + 1); + let lo = mem.readb(addr); + let hi = mem.readb(addr + 1); self.regs.pc = (hi as u16) << 8 | lo as u16; debug!("PC set to: {:#06x}", self.regs.pc); } // Brings the CPU to a known state. Resets all registers and flags // Read location of pc from 0xfffc - pub fn reset(&mut self, bus: &T) { + pub fn reset(&mut self, mem: &T) { // reset registers self.regs.sp = self.regs.sp - 3; self.set_flag(IRQ, true); - self.find_pc_addr(bus); + self.find_pc_addr(mem); // A reset takes 8 CPU clocks self.cycles = 8; @@ -128,46 +125,29 @@ impl CPU { } // read the next opcode and increment pc - fn readb_pc(&mut self, bus: &T) -> Byte { - let val = self.readb(bus, self.regs.pc); + fn readb_pc(&mut self, mem: &T) -> Byte { + let val = self.readb(mem, self.regs.pc); self.regs.pc += 1; val } // read whole Word from pc - fn readw_pc(&mut self, bus: &T) -> Word { - let val = self.readw(bus, self.regs.pc); + fn readw_pc(&mut self, mem: &T) -> Word { + let val = self.readw(mem, self.regs.pc); self.regs.pc += 2; val } // Pop a byte from the SP - fn popb_sp(&mut self, bus: &T) -> Byte { + fn popb_sp(&mut self, mem: &T) -> Byte { self.regs.sp += 1; - let val = self.readb(bus, STACK_BASE_ADDR + self.regs.sp as Word); + let val = self.readb(mem, STACK_BASE_ADDR + self.regs.sp as Word); val } - // Pop a word from the stack - fn popw_sp(&mut self, bus: &T) -> Word { - let hi = self.popb_sp(bus); - let lo = self.popb_sp(bus); - (hi << 8) as Word & lo as Word - } - // Push a byte to the SP. - fn pushb_sp(&mut self, bus: &mut T, val: Byte) { - self.writeb(bus, STACK_BASE_ADDR + self.regs.sp as Word, val); - self.regs.sp -= 1; - } - - // push a word to the stack, lo first, hi second - fn pushw_sp(&mut self, bus: &mut T, val: Word) { - let lo = ((val >> 8) & LO) as Byte; - let hi = (val & LO) as Byte; - self.writeb(bus, STACK_BASE_ADDR + self.regs.sp as Word, lo); - self.regs.sp -= 1; - self.writeb(bus, STACK_BASE_ADDR + self.regs.sp as Word, hi); + fn pushb_sp(&mut self, mem: &mut T, val: Byte) { + self.writeb(mem, STACK_BASE_ADDR + self.regs.sp as Word, val); self.regs.sp -= 1; } @@ -198,82 +178,82 @@ impl CPU { self.regs.pc = addr; } - fn run_instruction(&mut self, bus: &mut T, i: &Instruction) -> u8 { + fn run_instruction(&mut self, mem: &mut T, i: &Instruction) -> u8 { let (value, page_cross) = match &i.addr_mode { AddrMode::IMP => self.am_IMP(), AddrMode::IMM => self.am_IMM(), - AddrMode::ZP0 => self.am_ZP0(bus), - AddrMode::ZPX => self.am_ZPX(bus), - AddrMode::ZPY => self.am_ZPY(bus), - AddrMode::REL => self.am_REL(bus), - AddrMode::ABS => self.am_ABS(bus), - AddrMode::ABX => self.am_ABX(bus), - AddrMode::ABY => self.am_ABY(bus), - AddrMode::IND => self.am_IND(bus), - AddrMode::IZX => self.am_IZX(bus), - AddrMode::IZY => self.am_IZY(bus), + AddrMode::ZP0 => self.am_ZP0(mem), + AddrMode::ZPX => self.am_ZPX(mem), + AddrMode::ZPY => self.am_ZPY(mem), + AddrMode::REL => self.am_REL(mem), + AddrMode::ABS => self.am_ABS(mem), + AddrMode::ABX => self.am_ABX(mem), + AddrMode::ABY => self.am_ABY(mem), + AddrMode::IND => self.am_IND(mem), + AddrMode::IZX => self.am_IZX(mem), + AddrMode::IZY => self.am_IZY(mem), }; let extra_cycle_on_page_cross = match i.operation { - Operation::ADC => self.op_ADC(bus, value), - Operation::AND => self.op_AND(bus, value), - Operation::ASL => self.op_ASL(bus, value), - Operation::BCC => self.op_BCC(bus, value), + Operation::ADC => self.op_ADC(mem, value), + Operation::AND => self.op_AND(mem, value), + Operation::ASL => self.op_ASL(mem, value), + Operation::BCC => self.op_BCC(value), Operation::BCS => self.op_BCS(value), - Operation::BEQ => self.op_BEQ(bus, value), - Operation::BIT => self.op_BIT(bus, value), - Operation::BMI => self.op_BMI(bus, value), + Operation::BEQ => self.op_BEQ(value), + Operation::BIT => self.op_BIT(mem, value), + Operation::BMI => self.op_BMI(value), Operation::BNE => self.op_BNE(value), - Operation::BPL => self.op_BPL(bus, value), - Operation::BRK => self.op_BRK(bus), + Operation::BPL => self.op_BPL(value), + Operation::BRK => self.op_BRK(mem), Operation::BVC => self.op_BVC(value), Operation::BVS => self.op_BVS(value), Operation::CLC => self.op_CLC(), Operation::CLD => self.op_CLD(), Operation::CLI => self.op_CLI(), Operation::CLV => self.op_CLV(), - Operation::CMP => self.op_CMP(bus, value), - Operation::CPX => self.op_CPX(bus, value), - Operation::CPY => self.op_CPY(bus, value), - Operation::DCP => self.op_DCP(bus, value), - Operation::DEC => self.op_DEC(bus, value), + Operation::CMP => self.op_CMP(mem, value), + Operation::CPX => self.op_CPX(mem, value), + Operation::CPY => self.op_CPY(mem, value), + Operation::DCP => self.op_DCP(mem, value), + Operation::DEC => self.op_DEC(mem, value), Operation::DEX => self.op_DEX(), Operation::DEY => self.op_DEY(), - Operation::EOR => self.op_EOR(bus, value), - Operation::INC => self.op_INC(bus, value), + Operation::EOR => self.op_EOR(mem, value), + Operation::INC => self.op_INC(mem, value), Operation::INX => self.op_INX(), Operation::INY => self.op_INY(), - Operation::ISB => self.op_ISB(bus, value), + Operation::ISB => self.op_ISB(mem, value), Operation::JMP => self.op_JMP(value), - Operation::JSR => self.op_JSR(bus, value), + Operation::JSR => self.op_JSR(mem, value), Operation::KIL => self.op_KIL(), - Operation::LAX => self.op_LAX(bus, value), - Operation::LDA => self.op_LDA(bus, value), - Operation::LDX => self.op_LDX(bus, value), - Operation::LDY => self.op_LDY(bus, value), - Operation::LSR => self.op_LSR(bus, value), + Operation::LAX => self.op_LAX(mem, value), + Operation::LDA => self.op_LDA(mem, value), + Operation::LDX => self.op_LDX(mem, value), + Operation::LDY => self.op_LDY(mem, value), + Operation::LSR => self.op_LSR(mem, value), Operation::NOP => self.op_NOP(), - Operation::ORA => self.op_ORA(bus, value), - Operation::PHA => self.op_PHA(bus), - Operation::PHP => self.op_PHP(bus), - Operation::PLA => self.op_PLA(bus), - Operation::ROL => self.op_ROL(bus, value), - Operation::PLP => self.op_PLP(bus), - Operation::RLA => self.op_RLA(bus, value), - Operation::ROR => self.op_ROR(bus, value), - Operation::RRA => self.op_RRA(bus, value), - Operation::RTI => self.op_RTI(bus), - Operation::RTS => self.op_RTS(bus), - Operation::SAX => self.op_SAX(bus, value), - Operation::SBC => self.op_SBC(bus, value), + Operation::ORA => self.op_ORA(mem, value), + Operation::PHA => self.op_PHA(mem), + Operation::PHP => self.op_PHP(mem), + Operation::PLA => self.op_PLA(mem), + Operation::ROL => self.op_ROL(mem, value), + Operation::PLP => self.op_PLP(mem), + Operation::RLA => self.op_RLA(mem, value), + Operation::ROR => self.op_ROR(mem, value), + Operation::RRA => self.op_RRA(mem, value), + Operation::RTI => self.op_RTI(mem), + Operation::RTS => self.op_RTS(mem), + Operation::SAX => self.op_SAX(mem, value), + Operation::SBC => self.op_SBC(mem, value), Operation::SEC => self.op_SEC(), Operation::SED => self.op_SED(), Operation::SEI => self.op_SEI(), - Operation::SLO => self.op_SLO(bus, value), - Operation::SRE => self.op_SRE(bus, value), - Operation::STA => self.op_STA(bus, value), - Operation::STX => self.op_STX(bus, value), - Operation::STY => self.op_STY(bus, value), + Operation::SLO => self.op_SLO(mem, value), + Operation::SRE => self.op_SRE(mem, value), + Operation::STA => self.op_STA(mem, value), + Operation::STX => self.op_STX(mem, value), + Operation::STY => self.op_STY(mem, value), Operation::TAX => self.op_TAX(), Operation::TAY => self.op_TAY(), Operation::TSX => self.op_TSX(), @@ -308,33 +288,33 @@ impl CPU { } // Absolute address on zero page - fn am_ZP0(&mut self, bus: &T) -> (Word, bool) { - let addr = self.readb_pc(bus); + fn am_ZP0(&mut self, mem: &T) -> (Word, bool) { + let addr = self.readb_pc(mem); (LO & addr as Word, false) } // Absolute address on zero page with x offset - fn am_ZPX(&mut self, bus: &T) -> (Word, bool) { - let addr = self.readb_pc(bus).wrapping_add(self.regs.x); + fn am_ZPX(&mut self, mem: &T) -> (Word, bool) { + let addr = self.readb_pc(mem).wrapping_add(self.regs.x); (LO & addr as Word , false) } // Absolute address on zero page with y offset - fn am_ZPY(&mut self, bus: &T) -> (Word, bool) { - let addr = self.readb_pc(bus).wrapping_add(self.regs.y); + fn am_ZPY(&mut self, mem: &T) -> (Word, bool) { + let addr = self.readb_pc(mem).wrapping_add(self.regs.y); (LO & addr as Word, false) } // Absolute address. Next 2 bytes of pc are the address - fn am_ABS(&mut self, bus: &T) -> (Word, bool) { - let addr = self.readw_pc(bus); + fn am_ABS(&mut self, mem: &T) -> (Word, bool) { + let addr = self.readw_pc(mem); (addr, false) } // Absolute address with offset. Next 2 bytes of pc are the address // additional cycle on page wrap - fn am_ABX(&mut self, bus: &T) -> (Word, bool) { - let tmp_addr = self.readw_pc(bus); + fn am_ABX(&mut self, mem: &T) -> (Word, bool) { + let tmp_addr = self.readw_pc(mem); let addr = tmp_addr.wrapping_add(self.regs.x as Word); let page_cross = addr & HI != tmp_addr & HI; @@ -343,8 +323,8 @@ impl CPU { // Absolute address with offset. Next 2 bytes of pc are the address // additional cycle on page wrap - fn am_ABY(&mut self, bus: &T) -> (Word, bool) { - let tmp_addr = self.readw_pc(bus); + fn am_ABY(&mut self, mem: &T) -> (Word, bool) { + let tmp_addr = self.readw_pc(mem); let addr = tmp_addr.wrapping_add(self.regs.y as Word); let page_cross = addr & HI != tmp_addr & HI; @@ -353,8 +333,8 @@ impl CPU { // Relative addressing. Only used for branching. The next byte on the // pc is a signed offset from the current pc location - fn am_REL(&mut self, bus: &T) -> (Word, bool) { - let rel_addr = self.readb_pc(bus) as Word; + fn am_REL(&mut self, mem: &T) -> (Word, bool) { + let rel_addr = self.readb_pc(mem) as Word; let base_addr = self.regs.pc; // If rel_addr > 0x8000, we substract 256 to make a negative jump @@ -372,19 +352,19 @@ impl CPU { // Hardware bug: Normally, if lo of the supplied address is 0xFF, high byte // must be read from the next page. Instead it wraps around and reads from // the same page! - fn am_IND(&mut self, bus: &T) -> (Word, bool) { - let ind_addr = self.readw_pc(bus); + fn am_IND(&mut self, mem: &T) -> (Word, bool) { + let ind_addr = self.readw_pc(mem); // page boundary bug: If LO is 0x00FF, we are at the page border // and need to wrap around. So hi is fetched from 0x0000 instead of // 0x0100 let addr = if ind_addr & LO == 0x00FF { - let lo = self.readb(bus, ind_addr); + let lo = self.readb(mem, ind_addr); let hi_addr = ind_addr - 0x00FF; - let hi = self.readb(bus, hi_addr); + let hi = self.readb(mem, hi_addr); (((hi as Word) << 8) | lo as Word) } else { // normal behaviour - self.readw(bus, ind_addr) + self.readw(mem, ind_addr) }; (addr, false) @@ -392,21 +372,21 @@ impl CPU { // the next 8 bits + x are an address on the zero page. This address stores the real address // that is used for the operation. - fn am_IZX(&mut self, bus: &T) -> (Word, bool) { - let ind_addr = self.readb_pc(bus); + fn am_IZX(&mut self, mem: &T) -> (Word, bool) { + let ind_addr = self.readb_pc(mem); let lo_addr = ind_addr.wrapping_add(self.regs.x); let hi_addr = ind_addr.wrapping_add(self.regs.x).wrapping_add(1); - let lo = self.readb(bus, lo_addr as Word); - let hi = self.readb(bus, hi_addr as Word); + let lo = self.readb(mem, lo_addr as Word); + let hi = self.readb(mem, hi_addr as Word); ((hi as Word) << 8 | lo as Word, false) } - fn am_IZY(&mut self, bus: &T) -> (Word, bool) { - let ind_addr = self.readb_pc(bus); + fn am_IZY(&mut self, mem: &T) -> (Word, bool) { + let ind_addr = self.readb_pc(mem); - let lo = self.readb(bus, ind_addr as Word); - let hi = self.readb(bus, ind_addr.wrapping_add(1) as Word); + let lo = self.readb(mem, ind_addr as Word); + let hi = self.readb(mem, ind_addr.wrapping_add(1) as Word); let addr = (hi as Word) << 8 | lo as Word; let addr = addr.wrapping_add(self.regs.y as Word); @@ -427,8 +407,8 @@ impl CPU { // carry bit is set, this enables multiple byte addition to be performed. // If the result is 0, Zero bit is set. If the result if negative, // Negative bit is set - fn op_ADC(&mut self, bus: &T, addr: Word) -> bool { - let val = self.readb(bus, addr) as Word; + fn op_ADC(&mut self, mem: &T, addr: Word) -> bool { + let val = self.readb(mem, addr) as Word; let tmp = self.regs.a as Word + val + self.get_flag(CARRY) as Word; self.set_flag(CARRY, tmp > 255); @@ -451,8 +431,8 @@ impl CPU { // using the contents of a byte of memory. // If the result is 0, Zero bit is set. If the result if negative, // Negative bit is set - fn op_AND(&mut self, bus: &T, addr: Addr) -> bool { - let val = self.readb(bus, addr); + fn op_AND(&mut self, mem: &T, addr: Addr) -> bool { + let val = self.readb(mem, addr); self.regs.a &= val; self.set_flag_nz(self.regs.a); true @@ -467,13 +447,13 @@ impl CPU { // carry if the result will not fit in 8 bits. // If the result is 0, Zero bit is set. If the result if negative, // Negative bit is set - fn op_ASL(&mut self, bus: &mut T, addr: Addr) -> bool { + fn op_ASL(&mut self, mem: &mut T, addr: Addr) -> bool { // LSR works on memory or A. We can differenciate by the addr mode let addr_mode = &Instruction::decode_op(self.curr_op).addr_mode; let val = if *addr_mode == AddrMode::IMP { self.regs.a } else { - self.readb(bus, addr) + self.readb(mem, addr) }; let shifted = (val << 1) as Byte; self.set_flag(CARRY, (val & 0b10000000) > 0); @@ -481,7 +461,7 @@ impl CPU { if *addr_mode == AddrMode::IMP { self.regs.a = shifted; } else { - self.writeb(bus, addr, shifted); + self.writeb(mem, addr, shifted); } self.set_flag_nz(shifted); @@ -492,7 +472,7 @@ impl CPU { // BCC - Branch if Carry Clear // If the carry flag is clear then add the relative displacement to // the program counter to cause a branch to a new location. - fn op_BCC(&mut self, bus: &T, addr: Addr) -> bool { + fn op_BCC(&mut self, addr: Addr) -> bool { if self.get_flag(CARRY) == 0 { self.jump(addr); self.cycles_ahead += 1; @@ -516,7 +496,7 @@ impl CPU { // BEQ - Branch if Equal // If the zero flag is set then add the relative displacement to // the program counter to cause a branch to a new location. - fn op_BEQ(&mut self, bus: &T, addr: Addr) -> bool { + fn op_BEQ(&mut self, addr: Addr) -> bool { if self.get_flag(ZERO) == 1 { self.jump(addr); self.cycles_ahead += 1; @@ -529,8 +509,8 @@ impl CPU { // A & M, N = M7, V = M6 // bits 7 and 6 of operand are transfered to bit 7 and 6 of SR (N,V); // the zeroflag is set to the result of operand AND accumulator. - fn op_BIT(&mut self, bus: &T, addr: Word) -> bool { - let val = self.readb(bus, addr); + fn op_BIT(&mut self, mem: &T, addr: Word) -> bool { + let val = self.readb(mem, addr); self.set_flag(OVERFLOW, (val & OVERFLOW) > 1); self.set_flag(NEGATIVE, (val & NEGATIVE) > 1); self.set_flag(ZERO, (val & self.regs.a) == 0); @@ -540,7 +520,7 @@ impl CPU { // BMI - Branch if Minus // If the negative flag is set then add the relative displacement to the // program counter to cause a branch to a new location. - fn op_BMI(&mut self, bus: &T, addr: Addr) -> bool { + fn op_BMI(&mut self, addr: Addr) -> bool { if self.get_flag(NEGATIVE) == 1 { self.jump(addr); self.cycles_ahead += 1; @@ -564,7 +544,7 @@ impl CPU { // BPL - Branch if Positive // If the negative flag is clear then add the relative displacement to // the program counter to cause a branch to a new location. - fn op_BPL(&mut self, bus: &T, addr: Addr) -> bool { + fn op_BPL(&mut self, addr: Addr) -> bool { if self.get_flag(NEGATIVE) == 0 { self.jump(addr); self.cycles_ahead += 1; @@ -578,21 +558,21 @@ impl CPU { // The program counter and processor status are pushed on the stack // then the IRQ interrupt vector at $FFFE/F is loaded into the PC and // the break flag in the status set to one. - fn op_BRK(&mut self, bus: &mut T) -> bool { + fn op_BRK(&mut self, mem: &mut T) -> bool { self.regs.pc += 1; self.set_flag(IRQ, true); // Push pc to stack - self.pushb_sp(bus, (self.regs.pc >> 8) as Byte); - self.pushb_sp(bus, self.regs.pc as Byte); + self.pushb_sp(mem, (self.regs.pc >> 8) as Byte); + self.pushb_sp(mem, self.regs.pc as Byte); // Push flags to stack self.set_flag(BREAK, true); - self.pushb_sp(bus, self.regs.flags); + self.pushb_sp(mem, self.regs.flags); self.set_flag(BREAK, false); // set PC to IRQ vector - self.regs.pc = self.readw(bus, 0xFFFE); + self.regs.pc = self.readw(mem, 0xFFFE); false } @@ -649,8 +629,8 @@ impl CPU { // Z,C,N = A-M // This instruction compares the contents of the accumulator with another // memory held value and sets the zero and carry flags as appropriate. - fn op_CMP(&mut self, bus: &mut T, addr: Addr) -> bool { - let val = self.readb(bus, addr); + fn op_CMP(&mut self, mem: &mut T, addr: Addr) -> bool { + let val = self.readb(mem, addr); let tmp = (self.regs.a as Word).wrapping_sub(val as Word); self.set_flag(CARRY, self.regs.a >= val); @@ -659,8 +639,8 @@ impl CPU { } // Compare X - fn op_CPX(&mut self, bus: &T, addr: Addr) -> bool { - let val = self.readb(bus, addr); + fn op_CPX(&mut self, mem: &T, addr: Addr) -> bool { + let val = self.readb(mem, addr); let tmp = (self.regs.x as Word).wrapping_sub(val as Word); self.set_flag(CARRY, self.regs.x >= val); @@ -669,8 +649,8 @@ impl CPU { } // Compare Y - fn op_CPY(&mut self, bus: &T, addr: Addr) -> bool { - let val = self.readb(bus, addr); + fn op_CPY(&mut self, mem: &T, addr: Addr) -> bool { + let val = self.readb(mem, addr); let tmp = (self.regs.y as Word).wrapping_sub(val as Word); self.set_flag(CARRY, self.regs.y >= val); @@ -679,9 +659,9 @@ impl CPU { } // Unofficial: DEC value, then CMP - fn op_DCP(&mut self, bus: &mut T, addr: Word) -> bool { - self.op_DEC(bus, addr); - self.op_CMP(bus, addr); + fn op_DCP(&mut self, mem: &mut T, addr: Word) -> bool { + self.op_DEC(mem, addr); + self.op_CMP(mem, addr); false } @@ -689,10 +669,10 @@ impl CPU { // M,Z,N = M-1 // Subtracts one from the value held at a specified memory location // setting the zero and negative flags as appropriate. - fn op_DEC(&mut self, bus: &mut T, addr: Word) -> bool { - let val = self.readb(bus, addr); + fn op_DEC(&mut self, mem: &mut T, addr: Word) -> bool { + let val = self.readb(mem, addr); let val = val.wrapping_sub(1); - self.writeb(bus, addr, val); + self.writeb(mem, addr, val); self.set_flag_nz(val); false @@ -724,8 +704,8 @@ impl CPU { // A,Z,N = A^M // An exclusive OR is performed, bit by bit, on the accumulator contents // using the contents of a byte of memory. - fn op_EOR(&mut self, bus: &T, addr: Addr) -> bool { - let val = self.readb(bus, addr); + fn op_EOR(&mut self, mem: &T, addr: Addr) -> bool { + let val = self.readb(mem, addr); self.regs.a = self.regs.a ^ val; self.set_flag_nz(self.regs.a); @@ -736,10 +716,10 @@ impl CPU { // M,Z,N = M+1 // Adds one to the value held at a specified memory location setting the // zero and negative flags as appropriate. - fn op_INC(&mut self, bus: &mut T, addr: Word) -> bool { - let val = self.readb(bus, addr); + fn op_INC(&mut self, mem: &mut T, addr: Word) -> bool { + let val = self.readb(mem, addr); let val = val.wrapping_add(1); - self.writeb(bus, addr, val); + self.writeb(mem, addr, val); self.set_flag_nz(val); false } @@ -764,9 +744,9 @@ impl CPU { } // Unofficial opcode: INC, then SBC - fn op_ISB(&mut self, bus: &mut T, addr: Addr) -> bool { - self.op_INC(bus, addr); - self.op_SBC(bus, addr); + fn op_ISB(&mut self, mem: &mut T, addr: Addr) -> bool { + self.op_INC(mem, addr); + self.op_SBC(mem, addr); false } @@ -777,11 +757,11 @@ impl CPU { } // Jump to subroutine (leaves trace on the stack) - fn op_JSR(&mut self, bus: &mut T, addr: Word) -> bool { + fn op_JSR(&mut self, mem: &mut T, addr: Word) -> bool { self.regs.pc -= 1; - self.writeb(bus, STACK_BASE_ADDR + self.regs.sp as Word, ((self.regs.pc >> 8) & 0x00ff) as Byte); + self.writeb(mem, STACK_BASE_ADDR + self.regs.sp as Word, ((self.regs.pc >> 8) & 0x00ff) as Byte); self.regs.sp -= 1; - self.writeb(bus, STACK_BASE_ADDR + self.regs.sp as Word, (self.regs.pc & 0x00ff) as Byte); + self.writeb(mem, STACK_BASE_ADDR + self.regs.sp as Word, (self.regs.pc & 0x00ff) as Byte); self.regs.sp -= 1; self.jump(addr); false @@ -796,8 +776,8 @@ impl CPU { } // Unofficial op code! Shortcut for LDA, TAX - fn op_LAX(&mut self, bus: &T, addr: Word) -> bool { - self.op_LDA(bus, addr); + fn op_LAX(&mut self, mem: &T, addr: Word) -> bool { + self.op_LDA(mem, addr); self.op_TAX(); match Instruction::decode_op(self.curr_op).addr_mode { @@ -807,24 +787,24 @@ impl CPU { } // Read value from addr into A - fn op_LDA(&mut self, bus: &T, addr: Word) -> bool { - let val = self.readb(bus, addr); + fn op_LDA(&mut self, mem: &T, addr: Word) -> bool { + let val = self.readb(mem, addr); self.regs.a = val; self.set_flag_nz(val); true } // Read value from addr into X - fn op_LDX(&mut self, bus: &T, addr: Word) -> bool { - let val = self.readb(bus, addr); + fn op_LDX(&mut self, mem: &T, addr: Word) -> bool { + let val = self.readb(mem, addr); self.regs.x = val; self.set_flag_nz(val); true } // Read value from addr into Y - fn op_LDY(&mut self, bus: &T, addr: Word) -> bool { - let val = self.readb(bus, addr); + fn op_LDY(&mut self, mem: &T, addr: Word) -> bool { + let val = self.readb(mem, addr); self.regs.y = val; self.set_flag_nz(val); true @@ -834,13 +814,13 @@ impl CPU { // A,C,Z,N = A/2 or M,C,Z,N = M/2 // Each of the bits in A or M is shift one place to the right. The bit // that was in bit 0 is shifted into the carry flag. Bit 7 is set to zero. - fn op_LSR(&mut self, bus: &mut T, addr: Addr) -> bool { + fn op_LSR(&mut self, mem: &mut T, addr: Addr) -> bool { // LSR works on memory or A. We can differenciate by the addr mode let addr_mode = &Instruction::decode_op(self.curr_op).addr_mode; let val = if *addr_mode == AddrMode::IMP { self.regs.a as Word } else { - self.readb(bus, addr) as Word + self.readb(mem, addr) as Word }; self.set_flag(CARRY, (val & 0b00000001) != 0); @@ -850,7 +830,7 @@ impl CPU { if *addr_mode == AddrMode::IMP { self.regs.a = shifted; } else { - self.writeb(bus, addr, shifted); + self.writeb(mem, addr, shifted); } false } @@ -867,31 +847,31 @@ impl CPU { // A,Z,N = A|M // An inclusive OR is performed, bit by bit, on the accumulator contents // using the contents of a byte of memory. - fn op_ORA(&mut self, bus: &T, addr: Addr) -> bool { - self.regs.a = self.regs.a | self.readb(bus, addr); + fn op_ORA(&mut self, mem: &T, addr: Addr) -> bool { + self.regs.a = self.regs.a | self.readb(mem, addr); self.set_flag_nz(self.regs.a); true } // PHA - Push Accumulator // Pushes a copy of the accumulator on to the stack. - fn op_PHA(&mut self, bus: &mut T) -> bool { - self.pushb_sp(bus, self.regs.a); + fn op_PHA(&mut self, mem: &mut T) -> bool { + self.pushb_sp(mem, self.regs.a); false } // PHP - Push Processor Status // Pushes a copy of the status flags on to the stack. - fn op_PHP(&mut self, bus: &mut T) -> bool { + fn op_PHP(&mut self, mem: &mut T) -> bool { let tmp = self.regs.flags | BREAK; - self.pushb_sp(bus, tmp); + self.pushb_sp(mem, tmp); self.set_flag(BREAK, false); false } // Read from stack into A - fn op_PLA(&mut self, bus: &T) -> bool { - self.regs.a = self.popb_sp(bus); + fn op_PLA(&mut self, mem: &T) -> bool { + self.regs.a = self.popb_sp(mem); self.set_flag_nz(self.regs.a); false } @@ -899,8 +879,8 @@ impl CPU { // PLP - Pull Processor Status // Pulls an 8 bit value from the stack and into the processor flags. The // flags will take on new states as determined by the value pulled. - fn op_PLP(&mut self, bus: &T) -> bool { - self.regs.flags = self.popb_sp(bus); + fn op_PLP(&mut self, mem: &T) -> bool { + self.regs.flags = self.popb_sp(mem); // Im not sure why this is set to false and stack value is not used // but that's how the nestest.log shows it.. @@ -912,12 +892,12 @@ impl CPU { // Move each of the bits in either A or M one place to the left. Bit 0 is // filled with the current value of the carry flag whilst the old bit 7 // becomes the new carry flag value. - fn op_ROL(&mut self, bus: &mut T, addr: Addr) -> bool { + fn op_ROL(&mut self, mem: &mut T, addr: Addr) -> bool { let addr_mode = &Instruction::decode_op(self.curr_op).addr_mode; let val = if *addr_mode == AddrMode::IMP { self.regs.a as Word } else { - self.readb(bus, addr) as Word + self.readb(mem, addr) as Word }; let shifted = (val << 1) as Byte | self.get_flag(CARRY); @@ -927,23 +907,23 @@ impl CPU { if *addr_mode == AddrMode::IMP { self.regs.a = shifted as Byte; } else { - self.writeb(bus, addr, shifted); + self.writeb(mem, addr, shifted); } false } // Unofficial: ROL and then AND - fn op_RLA(&mut self, bus: &mut T, addr: Addr) -> bool { - self.op_ROL(bus, addr); - self.op_AND(bus, addr); + fn op_RLA(&mut self, mem: &mut T, addr: Addr) -> bool { + self.op_ROL(mem, addr); + self.op_AND(mem, addr); false } // Unofficial: Performs ROR + ADC - fn op_RRA(&mut self, bus: &mut T, addr: Addr) -> bool { - self.op_ROR(bus, addr); - self.op_ADC(bus, addr); + fn op_RRA(&mut self, mem: &mut T, addr: Addr) -> bool { + self.op_ROR(mem, addr); + self.op_ADC(mem, addr); false } @@ -951,12 +931,12 @@ impl CPU { // Move each of the bits in either A or M one place to the right. Bit 7 is // filled with the current value of the carry flag whilst the old bit 0 // becomes the new carry flag value. - fn op_ROR(&mut self, bus: &mut T, addr: Addr) -> bool { + fn op_ROR(&mut self, mem: &mut T, addr: Addr) -> bool { let addr_mode = &Instruction::decode_op(self.curr_op).addr_mode; let val = if *addr_mode == AddrMode::IMP { self.regs.a as Word } else { - self.readb(bus, addr) as Word + self.readb(mem, addr) as Word }; let shifted = (val >> 1) as Byte | (self.get_flag(CARRY) << 7); @@ -967,7 +947,7 @@ impl CPU { if *addr_mode == AddrMode::IMP { self.regs.a = shifted; } else { - self.writeb(bus, addr, shifted); + self.writeb(mem, addr, shifted); } false } @@ -976,12 +956,12 @@ impl CPU { // The RTI instruction is used at the end of an interrupt processing // routine. It pulls the processor flags from the stack followed by the // program counter. - fn op_RTI(&mut self, bus: &T) -> bool { - self.regs.flags = self.popb_sp(bus); + fn op_RTI(&mut self, mem: &T) -> bool { + self.regs.flags = self.popb_sp(mem); self.regs.flags &= !BREAK; - let pc_lo = self.popb_sp(bus) as Word; - let pc_hi = self.popb_sp(bus) as Word; + let pc_lo = self.popb_sp(mem) as Word; + let pc_hi = self.popb_sp(mem) as Word; self.regs.pc = pc_hi << 8 | pc_lo; false } @@ -989,20 +969,20 @@ impl CPU { // RTS - Return from Subroutine // The RTS instruction is used at the end of a subroutine to return to the // calling routine. It pulls the program counter (minus one) from the stack. - fn op_RTS(&mut self, bus: &T) -> bool { + fn op_RTS(&mut self, mem: &T) -> bool { self.regs.sp += 1; - let lo = self.readb(bus, 0x0100 + self.regs.sp as Addr); + let lo = self.readb(mem, 0x0100 + self.regs.sp as Addr); self.regs.sp += 1; - let hi = self.readb(bus, 0x0100 + self.regs.sp as Addr); + let hi = self.readb(mem, 0x0100 + self.regs.sp as Addr); let addr = (hi as Addr) << 8 | lo as Addr; self.regs.pc = addr + 1; false } // Unofficial: Stores bitwise AND of A and X - fn op_SAX(&mut self, bus: &mut T, addr: Addr) -> bool { + fn op_SAX(&mut self, mem: &mut T, addr: Addr) -> bool { let val = self.regs.a & self.regs.x; - self.writeb(bus, addr, val); + self.writeb(mem, addr, val); false } @@ -1013,8 +993,8 @@ impl CPU { // accumulator together with the not of the carry bit. If overflow occurs // the carry bit is clear, this enables multiple byte subtraction to be // performed. - fn op_SBC(&mut self, bus: &T, addr: Addr) -> bool { - let val = self.readb(bus, addr) as Word; + fn op_SBC(&mut self, mem: &T, addr: Addr) -> bool { + let val = self.readb(mem, addr) as Word; // invert buttom 8 bits let val = val ^ LO; @@ -1057,34 +1037,34 @@ impl CPU { } // Unofficial: ASL + ORA - fn op_SLO(&mut self, bus: &mut T, addr: Word) -> bool { - self.op_ASL(bus, addr); - self.op_ORA(bus, addr); + fn op_SLO(&mut self, mem: &mut T, addr: Word) -> bool { + self.op_ASL(mem, addr); + self.op_ORA(mem, addr); false } // Unofficial: LSR + EOR - fn op_SRE(&mut self, bus: &mut T, addr: Word) -> bool { - self.op_LSR(bus, addr); - self.op_EOR(bus, addr); + fn op_SRE(&mut self, mem: &mut T, addr: Word) -> bool { + self.op_LSR(mem, addr); + self.op_EOR(mem, addr); false } // Push A reg to memory - fn op_STA(&mut self, bus: &mut T, addr: Word) -> bool { - self.writeb(bus, addr, self.regs.a); + fn op_STA(&mut self, mem: &mut T, addr: Word) -> bool { + self.writeb(mem, addr, self.regs.a); false } // Push X reg to memory - fn op_STX(&mut self, bus: &mut T, addr: Word) -> bool { - self.writeb(bus, addr, self.regs.x); + fn op_STX(&mut self, mem: &mut T, addr: Word) -> bool { + self.writeb(mem, addr, self.regs.x); false } // Push Y reg to memory - fn op_STY(&mut self, bus: &mut T, addr: Word) -> bool { - self.writeb(bus, addr, self.regs.y); + fn op_STY(&mut self, mem: &mut T, addr: Word) -> bool { + self.writeb(mem, addr, self.regs.y); false } diff --git a/src/nes/disasm.rs b/src/nes/disasm.rs index 9223359..42f61d9 100644 --- a/src/nes/disasm.rs +++ b/src/nes/disasm.rs @@ -1,8 +1,8 @@ +use crate::nes::*; use crate::nes::cpu::instructions::*; + use failure::Error; use std::fmt; -use crate::nes::bus::*; -use crate::nes::types::*; use std::fmt::Debug; // Disassemble code around the pc of the cpu @@ -13,11 +13,11 @@ pub struct Disasm { pub addresses: Vec } -impl BusDevice for Disasm {} +impl MemoryReader for Disasm {} impl Disasm { // Disassemble given code region - pub fn disassemble(mem: &Bus, start: Addr, stop: Addr) -> Result { + pub fn disassemble(mem: &T, start: Addr, stop: Addr) -> Result { let mut instructions = Vec::new(); let mut addresses = Vec::new(); let mut mem_iter = ((start as usize) .. (stop as usize)+1).map({|a| a as Addr}); diff --git a/src/nes/memory.rs b/src/nes/memory.rs new file mode 100644 index 0000000..ed99e46 --- /dev/null +++ b/src/nes/memory.rs @@ -0,0 +1,107 @@ +// Interface for devices that contain memory that can be accessed by CPU +use crate::nes::cartridge::Cartridge; +use crate::nes::types::*; + +const RAM_SIZE: usize = 0x0800; +const RAM_ADDR_RANGE: [Addr; 2] = [0x0000, 0x1fff]; +const RAM_PHYS_RANGE: [Addr; 2] = [0x0000, 0x07ff]; +const PPU_ADDR_RANGE: [Addr; 2] = [0x2000, 0x3fff]; +const PPU_PHYS_RANGE: [Addr; 2] = [0x2000, 0x2007]; +const CART_ADDR_RANGE: [Addr; 2] = [0x4020, 0xffff]; + +pub struct NESMemory { + ram: [Byte; RAM_SIZE], // 2kb + cartridge: Option, +} + +impl NESMemory { + pub fn new() -> Self { + NESMemory { + ram: [0; RAM_SIZE], + cartridge: None, + } + } + + pub fn insert_cartridge(&mut self, c: Cartridge) { + self.cartridge = Some(c); + } +} + +pub trait Memory { + fn readb(&self, addr: Addr) -> Byte; + fn writeb(&mut self, addr: Addr, data: Byte); + fn readw(&self, addr: Addr) -> Word { + let lo = self.readb(addr); + let hi = self.readb(addr+1); + (hi as Word) << 8 | lo as Word + } + fn writew(&mut self, addr: Addr, data: Word) { + self.writeb(addr, data as Byte); + self.writeb(addr + 1, (data >> 8) as Byte); + } +} + +impl Memory for NESMemory { + fn readb(&self, addr: Addr) -> Byte { + if let Some(cartridge) = &self.cartridge { + if CART_ADDR_RANGE[0] <= addr && addr <= CART_ADDR_RANGE[1] { + return cartridge.readb(addr) + } + } + + if RAM_ADDR_RANGE[0] <= addr && addr <= RAM_ADDR_RANGE[1] { + // Ram is 3x mirrored after 0x07ff + return self.ram[(addr & RAM_PHYS_RANGE[1]) as usize] + } + // if PPU_ADDR_RANGE[0] <= addr && addr <= PPU_ADDR_RANGE[1] { + // // PPU memory is mirrored after 0x2007 to 0x3fff + // return self.ram[(addr & PPU_PHYS_RANGE[1]) as usize] + // } + 0x0000 // generic response + } + + fn writeb(&mut self, addr: Addr, data: Byte) { + if let Some(cartridge) = &mut self.cartridge { + if CART_ADDR_RANGE[0] <= addr && addr <= CART_ADDR_RANGE[1] { + cartridge.writeb(addr, data) + } + } + if RAM_ADDR_RANGE[0] <= addr && addr <= RAM_ADDR_RANGE[1] { + // Ram is 3x mirrored after 07ff + self.ram[(addr & RAM_PHYS_RANGE[1]) as usize] = data + } + // if PPU_ADDR_RANGE[0] <= addr && addr <= PPU_ADDR_RANGE[1] { + // // PPU memory is mirrored after 0x2007 to 0x3fff + // self.ram[(addr & PPU_PHYS_RANGE[1]) as usize] = data + // } + } +} + +pub trait MemoryReader { + fn readb(&self, mem: &T, addr: Addr) -> Byte { + mem.readb(addr) + } + + fn readw(&self, mem: &T, addr: Addr) -> Word { + mem.readw(addr) + } + + fn writeb(&mut self, mem: &mut T, addr: Addr, data: Byte) { + mem.writeb(addr, data) + } +} + +// PPU interface to allow read/write of memory +pub trait PPUMemory { + fn readb_ppu(&self, addr: Addr) -> Byte; + fn writeb_ppu(&mut self, addr: Addr, data: Byte); + fn readw_ppu(&self, addr: Addr) -> Word { + let lo = self.readb_ppu(addr); + let hi = self.readb_ppu(addr+1); + (hi as Word) << 8 | lo as Word + } + fn writew_ppu(&mut self, addr: Addr, data: Word) { + self.writeb_ppu(addr, data as Byte); + self.writeb_ppu(addr + 1, (data >> 8) as Byte); + } +} \ No newline at end of file diff --git a/src/nes/ppu.rs b/src/nes/ppu.rs index 49a0383..5052447 100644 --- a/src/nes/ppu.rs +++ b/src/nes/ppu.rs @@ -1,5 +1,4 @@ -use crate::nes::bus::Memory; -use crate::nes::bus::Clockable; +use crate::nes::memory::Memory; use image::{ImageBuffer, Rgba}; use rand::Rng; @@ -18,10 +17,8 @@ impl PPU { canvas_main: ImageBuffer::new(256, 240), } } -} -impl Clockable for PPU { - fn clock(&mut self, _bus: &mut T) { + pub fn clock(&mut self, _mem: &mut T) { // random noise let mut rng = rand::thread_rng(); let x = rng.gen_range(0, 256); @@ -37,6 +34,3 @@ impl Clockable for PPU { self.canvas_main.put_pixel(x as u32, y as u32, px); } } - - -