diff --git a/.gitignore b/.gitignore index 507b1e4..74d17a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /target /roms +/logs \ No newline at end of file diff --git a/core/src/cpu/disassembler.rs b/core/src/cpu/disassembler.rs index aef3cca..e96e7ce 100644 --- a/core/src/cpu/disassembler.rs +++ b/core/src/cpu/disassembler.rs @@ -1,7 +1,7 @@ use crate::cpu::op::AddressingMode::*; use crate::cpu::op::{AddressingMode, Instruction}; use crate::cpu::Cpu; -use simplelog::debug; +use simplelog::{trace}; impl Cpu { pub fn disassemble_next_instr(&self) { @@ -12,7 +12,7 @@ impl Cpu { let operation = instr.op().to_string(); let addr_mode = self.disassemble_addr_mode(instr.addr_mode(), registers.pc); - debug!( + trace!( "{:#04X} - ${:04X} {} {}\tA {:#04X}, X {:#04X}, Y {:#04X}, SP: {:#04X}, F: {:#04X}", op_code, registers.pc, @@ -27,7 +27,7 @@ impl Cpu { } fn disassemble_addr_mode(&self, addr_mode: AddressingMode, pc: u16) -> String { - let word_peek = self.memory_bus.borrow().get_word(pc); + let word_peek = self.memory_bus.borrow().get_word(pc + 1); let byte_peek = (word_peek & 0xFF) as u8; match addr_mode { @@ -40,10 +40,13 @@ impl Cpu { IND => format!("(${:04X})", word_peek), IDX => format!("(${:04X},x)", word_peek), IDY => format!("(${:04X}),y", word_peek), - REL => format!("#${:04X}", word_peek), + REL => format!( + "${:04X}", + (pc + 2).wrapping_add_signed(byte_peek as i8 as i16) + ), ACC => String::from('A'), IMP => String::from("I"), - IMM => format!("{:04X}", byte_peek), + IMM => format!("#${:02X}", byte_peek), } } } diff --git a/core/src/cpu/op.rs b/core/src/cpu/op.rs index 9e51654..279549a 100644 --- a/core/src/cpu/op.rs +++ b/core/src/cpu/op.rs @@ -260,16 +260,10 @@ impl Cpu { /// label - PC + byte fn operand_addr_rel(&mut self) -> u16 { + let offset = self.program_get_next_byte() as u8; let base_addr = self.registers.pc; - let offset = self.program_get_next_byte() as u16; - // The offset is signed - let positive_offset = offset & 0x7F; - if offset & 0x80 > 0 { - base_addr.wrapping_sub(positive_offset) - } else { - base_addr.wrapping_add(positive_offset) - } + base_addr.wrapping_add_signed(offset as i8 as i16) } } diff --git a/core/src/lib.rs b/core/src/lib.rs index 28753dc..2661ec5 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -8,4 +8,4 @@ mod ppu; pub trait Clock { /// Run a clock cycle fn cycle(&mut self); -} +} \ No newline at end of file diff --git a/core/src/memory.rs b/core/src/memory.rs index 436f626..9d51576 100644 --- a/core/src/memory.rs +++ b/core/src/memory.rs @@ -1,5 +1,7 @@ -use simplelog::warn; +use std::cell::RefCell; use crate::mappers::Mapper; +use simplelog::warn; +use std::rc::{Weak}; const MEMORY_MAX_ADDR: u16 = 0xFFFF; const PPU_MAX_ADDR: u16 = 0x4000; @@ -12,12 +14,18 @@ const RAM_MAX_ADDR: u16 = 0x2000; pub struct MemoryBus { mapper: Option>, ram: [u8; RAM_SIZE], + + observers: Vec>>, } impl MemoryBus { pub fn new() -> Self { let ram = [0; RAM_SIZE]; - Self { mapper: None, ram } + Self { + mapper: None, + ram, + observers: vec![], + } } /// Register a mapper in the memory bus, simulates plugging in a cartridge. @@ -51,8 +59,11 @@ impl MemoryBus { let prg_addr = addr - CARTRIDGE_RAM_MAX_ADDR; if self.mapper.is_none() { - warn!("Tried to read memory address {} before setting a mapper", addr); - return 0 + warn!( + "Tried to read memory address {} before setting a mapper", + addr + ); + return 0; } let mapper = self.mapper.as_ref().unwrap(); @@ -94,5 +105,29 @@ impl MemoryBus { // Cannot write to ROM assert!(false); } + + // Notify the observers + for observer in self.observers.iter() { + match observer.upgrade() { + None => {} + Some(rc) => rc.borrow_mut().notify_mem_byte_updated(addr, value) + } + } + } + + pub fn register_observer(&mut self, observer: Weak>) { + self.observers.push(observer); } } + +// pub type MemoryObserver = impl Fn(u16, u8) -> (); + +// A memory observer. Will be notified when a byte was modified in memory. +pub trait MemoryObserver { + /// Called when a byte was updated in the memory bus. + /// + /// # Arguments + /// * addr - The address of the byte + /// * value - The updated value + fn notify_mem_byte_updated(&mut self, addr: u16, value: u8); +} diff --git a/core/src/ppu/mod.rs b/core/src/ppu/mod.rs index 283cbac..b16290d 100644 --- a/core/src/ppu/mod.rs +++ b/core/src/ppu/mod.rs @@ -1,7 +1,8 @@ -use crate::memory::MemoryBus; +use crate::memory::{MemoryBus, MemoryObserver}; use crate::Clock; use std::cell::RefCell; use std::rc::Rc; +use simplelog::info; pub struct Ppu { memory_bus: Rc>, @@ -9,7 +10,17 @@ pub struct Ppu { impl Ppu { pub fn new(memory_bus: Rc>) -> Self { - Self { memory_bus } + Self { memory_bus: memory_bus.clone() } + } + + fn set_register(&self, addr: u16, value: u8) { + + } +} + +impl MemoryObserver for Ppu { + fn notify_mem_byte_updated(&mut self, addr: u16, value: u8) { + info!("MemChange: {:#04x} -> {:#02x}", addr, value); } } diff --git a/core/src/system.rs b/core/src/system.rs index 15a64d8..3b9c093 100644 --- a/core/src/system.rs +++ b/core/src/system.rs @@ -19,15 +19,18 @@ const REFRESH_RATE: usize = 60; // 60 Hz pub struct System { cpu: Cpu, memory_bus: Rc>, - ppu: Ppu + ppu: Rc> } impl System { pub fn new() -> Self { let memory_bus = Rc::new(RefCell::new(MemoryBus::new())); let cpu = Cpu::new(Rc::clone(&memory_bus)); - let ppu = Ppu::new(Rc::clone(&memory_bus)); - + let ppu = Rc::new(RefCell::new(Ppu::new(Rc::clone(&memory_bus)))); + + let weak_ppu = Rc::downgrade(&ppu); + memory_bus.borrow_mut().register_observer(weak_ppu); + Self { cpu, memory_bus, ppu } } @@ -49,7 +52,7 @@ impl Clock for System { self.cpu.cycle(); for _ppu_cycle in 0usize..PPU_CYCLE_PER_REFRESH { - self.ppu.cycle(); + self.ppu.borrow_mut().cycle(); } } } diff --git a/ui/src/main.rs b/ui/src/main.rs index 35a0560..6590dd5 100644 --- a/ui/src/main.rs +++ b/ui/src/main.rs @@ -1,18 +1,26 @@ -use std::thread::sleep; -use std::time::Duration; use core::system::System; use core::Clock; use simplelog::*; +use std::fs::File; +use std::thread::sleep; +use std::time::Duration; const ROM_PATH: &'static str = "./roms/dk.nes"; fn main() { - CombinedLogger::init(vec![TermLogger::new( - LevelFilter::Debug, - Config::default(), - TerminalMode::Mixed, - ColorChoice::Auto, - )]) + CombinedLogger::init(vec![ + TermLogger::new( + LevelFilter::Info, + Config::default(), + TerminalMode::Mixed, + ColorChoice::Auto, + ), + WriteLogger::new( + LevelFilter::Debug, + Config::default(), + File::create("./logs/latest.log").unwrap(), + ), + ]) .unwrap(); let mut system = System::new();