nesrust/core/src/cpu/memory.rs
2025-02-01 17:02:40 -05:00

121 lines
3.4 KiB
Rust

use crate::mappers::Mapper;
use crate::{MemoryBus, Observable, Observer};
use simplelog::warn;
use std::cell::RefCell;
use std::rc::Weak;
const MEMORY_MAX_ADDR: u16 = 0xFFFF;
const PPU_MAX_ADDR: u16 = 0x4000;
const APU_MAX_ADDR: u16 = 0x4020;
const UNMAPPED_MAX_ADDR: u16 = 0x6000;
const CARTRIDGE_RAM_MAX_ADDR: u16 = 0x8000;
const RAM_SIZE: usize = 0x0800;
const RAM_MAX_ADDR: u16 = 0x2000;
pub struct CpuMemoryBus {
mapper: Option<Box<dyn Mapper>>,
ram: [u8; RAM_SIZE],
observers: Vec<Weak<RefCell<dyn Observer<u16, u8>>>>,
}
impl CpuMemoryBus {
pub fn new() -> Self {
let ram = [0; RAM_SIZE];
Self {
mapper: None,
ram,
observers: vec![],
}
}
/// Register a mapper in the memory bus, simulates plugging in a cartridge.
pub fn register_mapper(&mut self, mapper: Box<dyn Mapper>) {
self.mapper = Some(mapper);
}
/// Gets a word from memory.
///
/// # Arguments
/// * `addr` - The address of the word
pub fn get_word(&self, addr: u16) -> u16 {
let low = self.read_byte(addr) as u16;
let high = self.read_byte(addr + 1) as u16;
(high << 8) | low
}
fn notify_observers(&self, addr: u16, value: u8) {
for observer in self.observers.iter() {
match observer.upgrade() {
None => {}
Some(rc) => rc.borrow_mut().notify_updated(addr, value),
}
}
}
}
impl MemoryBus for CpuMemoryBus {
fn read_byte(&self, addr: u16) -> u8 {
assert!(addr < MEMORY_MAX_ADDR);
if addr < RAM_MAX_ADDR {
let ram_addr = (addr as usize) % RAM_SIZE;
self.ram[ram_addr]
} else if addr < PPU_MAX_ADDR {
let relative_addr = addr - RAM_MAX_ADDR;
let ppu_register = relative_addr % 8;
// todo!()
0
} else if addr < APU_MAX_ADDR {
// todo!()
0
} else if addr < UNMAPPED_MAX_ADDR {
assert!(false);
0
} else if addr < CARTRIDGE_RAM_MAX_ADDR {
todo!()
} else {
let prg_addr = addr - CARTRIDGE_RAM_MAX_ADDR;
if self.mapper.is_none() {
warn!(
"Tried to read CPU memory address {} before setting a mapper",
addr
);
return 0;
}
let mapper = self.mapper.as_ref().unwrap();
mapper.get_prg_byte(prg_addr)
}
}
fn write_byte(&mut self, addr: u16, value: u8) {
assert!(addr < MEMORY_MAX_ADDR);
if addr < RAM_MAX_ADDR {
let ram_addr = (addr as usize) % RAM_SIZE;
self.ram[ram_addr] = value;
} else if addr < PPU_MAX_ADDR {
let relative_addr = addr - RAM_MAX_ADDR;
let ppu_register = relative_addr % 8;
// todo!()
} else if addr < APU_MAX_ADDR {
} else if addr < UNMAPPED_MAX_ADDR {
assert!(false);
} else if addr < CARTRIDGE_RAM_MAX_ADDR {
assert!(false);
} else {
// Cannot write to ROM
assert!(false);
}
self.notify_observers(addr, value);
}
}
impl Observable<u16, u8> for CpuMemoryBus {
fn register_observer(&mut self, observer: Weak<RefCell<dyn Observer<u16, u8>>>) {
self.observers.push(observer);
}
}