Memory observer

This commit is contained in:
william 2025-01-31 21:33:41 -05:00
parent ea6a4e1680
commit eb7e842a81
8 changed files with 87 additions and 32 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
/target
/roms
/logs

View File

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

View File

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

View File

@ -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<Box<dyn Mapper>>,
ram: [u8; RAM_SIZE],
observers: Vec<Weak<RefCell<dyn MemoryObserver>>>,
}
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<RefCell<dyn MemoryObserver>>) {
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);
}

View File

@ -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<RefCell<MemoryBus>>,
@ -9,7 +10,17 @@ pub struct Ppu {
impl Ppu {
pub fn new(memory_bus: Rc<RefCell<MemoryBus>>) -> 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);
}
}

View File

@ -19,14 +19,17 @@ const REFRESH_RATE: usize = 60; // 60 Hz
pub struct System {
cpu: Cpu,
memory_bus: Rc<RefCell<MemoryBus>>,
ppu: Ppu
ppu: Rc<RefCell<Ppu>>
}
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();
}
}
}

View File

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