ROM insertion into system

This commit is contained in:
william 2025-01-25 12:30:30 -05:00
parent 8d5192ff43
commit d4715bbf62
9 changed files with 175 additions and 18 deletions

View File

@ -3,6 +3,7 @@ mod op;
mod operations;
use std::cell::RefCell;
use std::rc::Rc;
use crate::memory::MemoryBus;
use crate::Clock;
use bitflags::bitflags;
@ -15,7 +16,7 @@ pub struct Cpu {
registers: CpuRegisters,
/// The memory bus accessible by the CPU
memory_bus: RefCell<MemoryBus>,
memory_bus: Rc<RefCell<MemoryBus>>,
/// The number of cycles ran on the CPU
cycle: usize,
@ -133,7 +134,7 @@ pub trait CpuInternals {
}
impl Cpu {
pub fn new(memory_bus: RefCell<MemoryBus>) -> Self {
pub fn new(memory_bus: Rc<RefCell<MemoryBus>>) -> Self {
Cpu {
registers: CpuRegisters {
pc: 0x8000,

View File

@ -1,7 +1,8 @@
mod cpu;
mod mappers;
mod memory;
pub mod rom;
mod system;
mod rom;
pub mod system;
pub trait Clock {
/// Run a clock cycle

31
core/src/mappers/mod.rs Normal file
View File

@ -0,0 +1,31 @@
use crate::mappers::nrom::NRom;
use crate::rom::Rom;
mod nrom;
pub trait Mapper {
/// Gets a byte from the program ROM.
///
/// # Arguments
/// * addr - The address of the byte to read
fn get_prg_byte(&self, addr: u16) -> u8;
/// Gets a byte from the character ROM.
///
/// # Arguments
/// * addr - The address of the byte to read
fn get_chr_byte(&self, addr: u16) -> u8;
}
/// Gets a mapper for a ROM.
///
/// # Arguments
/// * rom - The ROM to get the mapper for
pub fn get_mapper(rom: Rom) -> Box<dyn Mapper> {
let instance = match rom.mapper {
0 => NRom::new(rom),
_ => unreachable!("Unsupported mapper {}", rom.mapper),
};
Box::new(instance)
}

39
core/src/mappers/nrom.rs Normal file
View File

@ -0,0 +1,39 @@
use simplelog::info;
use crate::mappers::Mapper;
use crate::rom::Rom;
const PRG_BANK_SIZE: usize = 0x4000;
const CHR_BANK_SIZE: usize = 0x2000;
pub struct NRom {
rom: Rom,
}
impl NRom {
/// Creates an instance of the NRom mapper.
///
/// # Arguments
/// * rom - The ROM
pub fn new(rom: Rom) -> Self {
info!("Using NRom mapper");
Self { rom }
}
}
impl Mapper for NRom {
fn get_prg_byte(&self, addr: u16) -> u8 {
let addr_usize = addr as usize;
if addr_usize < PRG_BANK_SIZE || self.rom.prg_rom_size > PRG_BANK_SIZE {
return self.rom.prg_rom[addr_usize];
}
self.rom.prg_rom[addr_usize - PRG_BANK_SIZE]
}
fn get_chr_byte(&self, addr: u16) -> u8 {
let addr_usize = addr as usize;
assert!(addr_usize < CHR_BANK_SIZE);
self.rom.chr_rom[addr_usize]
}
}

View File

@ -1,13 +1,28 @@
const MEMORY_SIZE: usize = 0x0800;
use simplelog::warn;
use crate::mappers::Mapper;
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 MemoryBus {
ram: [u8; MEMORY_SIZE],
mapper: Option<Box<dyn Mapper>>,
ram: [u8; RAM_SIZE],
}
impl MemoryBus {
pub fn new() -> Self {
let ram = [0; MEMORY_SIZE];
Self { ram }
let ram = [0; RAM_SIZE];
Self { mapper: None, ram }
}
/// 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 byte from memory.
@ -15,7 +30,32 @@ impl MemoryBus {
/// # Arguments
/// * `addr` - The address of the byte
pub fn get_byte(&self, addr: u16) -> u8 {
unimplemented!("MemoryBus::get_byte");
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!()
} else if addr < APU_MAX_ADDR {
todo!()
} 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 memory address {} before setting a mapper", addr);
return 0
}
let mapper = self.mapper.as_ref().unwrap();
mapper.get_prg_byte(prg_addr)
}
}
/// Gets a word from memory.

View File

@ -202,6 +202,18 @@ impl INesHeader {
})
}
fn get_mapper(&self) -> u16 {
let mapper_low = (self.flag_6 >> 4) as u16;
let mapper_mid = (self.flag_7 & 0xF0) as u16;
let mapper_high = (self.mapper_msb_submapper & 0x0F) as u16;
mapper_high << 8 | mapper_mid | mapper_low
}
fn get_sub_mapper(&self) -> u8 {
self.mapper_msb_submapper >> 4
}
fn parse(header: &[u8]) -> Self {
Self {
prg_rom_size_lsb: header[4],
@ -252,6 +264,8 @@ impl RomLoader for INesHeader {
let (chr_ram_size, chr_nvram_size) = ines_header.get_chr_ram_size();
let nametable_mirroring = ines_header.get_nametable_mirroring();
let cpu_timing = ines_header.get_cpu_timing()?;
let mapper = ines_header.get_mapper();
let sub_mapper = ines_header.get_sub_mapper();
let prg_rom = file_data[trainer_size..prg_rom_size]
.to_vec()
@ -272,6 +286,8 @@ impl RomLoader for INesHeader {
chr_rom,
nametable_mirroring,
cpu_timing,
mapper,
sub_mapper,
})
}
}

View File

@ -35,6 +35,13 @@ pub struct Rom {
/// The timing of the CPU, also the region of the ROM
pub cpu_timing: CpuTiming,
/// The number of the mapper
pub mapper: u16,
/// The number of the sub-mapper
/// Not supported for now
pub sub_mapper: u8
}
pub enum NametableMirroring {
@ -106,6 +113,7 @@ pub enum RomReadError {
InvalidHeader(String),
MissingHeader,
RomLengthMismatch(usize, usize),
UnsupportedMapper(u8)
}
impl Display for RomReadError {
@ -117,6 +125,7 @@ impl Display for RomReadError {
RomReadError::MissingHeader => write!(f, "File was too short to contain a header"),
RomReadError::RomLengthMismatch(required_length, actual_length) =>
write!(f, "ROM didn't contain enough data according to the header; required {} bytes but contained {} bytes", required_length, actual_length),
RomReadError::UnsupportedMapper(mapper) => write!(f, "Unsupported mapper: {}", mapper),
}
}
}

View File

@ -1,7 +1,10 @@
use std::cell::RefCell;
use std::rc::Rc;
use simplelog::info;
use crate::cpu::Cpu;
use crate::mappers::get_mapper;
use crate::memory::MemoryBus;
use crate::rom::{Rom, RomReadError};
pub struct System {
cpu: Cpu,
@ -11,11 +14,21 @@ pub struct System {
impl System {
pub fn new() -> Self {
let memory_bus = Rc::new(RefCell::new(MemoryBus::new()));
let cpu = Cpu::new(memory_bus);
let cpu = Cpu::new(Rc::clone(&memory_bus));
Self {
cpu,
memory_bus
}
}
pub fn insert_rom(&self, path: &str) -> Result<(), RomReadError> {
let rom = Rom::read(path)?;
let mapper = get_mapper(rom);
self.memory_bus.borrow_mut().register_mapper(mapper);
info!("Successfully inserted ROM into system");
Ok(())
}
}

View File

@ -1,12 +1,19 @@
use core::rom::Rom;
use core::system::System;
use simplelog::*;
fn main() {
CombinedLogger::init(vec![
TermLogger::new(LevelFilter::Debug, Config::default(), TerminalMode::Mixed, ColorChoice::Auto),
]).unwrap();
const ROM_PATH: &'static str = "./roms/dk.nes";
fn main() {
CombinedLogger::init(vec![TermLogger::new(
LevelFilter::Debug,
Config::default(),
TerminalMode::Mixed,
ColorChoice::Auto,
)])
.unwrap();
let mut system = System::new();
system.insert_rom(ROM_PATH).expect("Failed to insert ROM");
let path = "./roms/dk.nes";
let rom = Rom::read(path).expect("Failed to read ROM file");
print!("Do stuff");
}