121 lines
3.4 KiB
Rust
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);
|
|
}
|
|
}
|