Compare commits

...

3 Commits

4 changed files with 57 additions and 91 deletions

View File

@ -123,14 +123,14 @@ impl Bus {
match self.cart.as_ref() { match self.cart.as_ref() {
Some(cart) => cart.read_byte(addr), Some(cart) => cart.read_byte(addr),
None => panic!("Tried to read from a non-existent cartridge"), None => 0xFF,
} }
} }
0x8000..=0x9FFF => self.ppu.read_byte(addr), // 8KB Video RAM 0x8000..=0x9FFF => self.ppu.read_byte(addr), // 8KB Video RAM
0xA000..=0xBFFF => match self.cart.as_ref() { 0xA000..=0xBFFF => match self.cart.as_ref() {
// 8KB External RAM // 8KB External RAM
Some(cart) => cart.read_byte(addr), Some(cart) => cart.read_byte(addr),
None => panic!("Tried to read from a non-existent cartridge"), None => 0xFF,
}, },
0xC000..=0xCFFF => self.work_ram.read_byte(addr), // 4KB Work RAM Bank 0 0xC000..=0xCFFF => self.work_ram.read_byte(addr), // 4KB Work RAM Bank 0
0xD000..=0xDFFF => self.var_ram.read_byte(addr), // 4KB Work RAM Bank 1 -> N 0xD000..=0xDFFF => self.var_ram.read_byte(addr), // 4KB Work RAM Bank 1 -> N
@ -176,7 +176,7 @@ impl BusIo for Bus {
match self.cart.as_ref() { match self.cart.as_ref() {
Some(cart) => cart.read_byte(addr), Some(cart) => cart.read_byte(addr),
None => panic!("Tried to read from a non-existent cartridge"), None => 0xFF,
} }
} }
0x8000..=0x9FFF => { 0x8000..=0x9FFF => {
@ -189,7 +189,7 @@ impl BusIo for Bus {
0xA000..=0xBFFF => match self.cart.as_ref() { 0xA000..=0xBFFF => match self.cart.as_ref() {
// 8KB External RAM // 8KB External RAM
Some(cart) => cart.read_byte(addr), Some(cart) => cart.read_byte(addr),
None => panic!("Tried to read from a non-existent cartridge"), None => 0xFF,
}, },
0xC000..=0xCFFF => self.work_ram.read_byte(addr), // 4KB Work RAM Bank 0 0xC000..=0xCFFF => self.work_ram.read_byte(addr), // 4KB Work RAM Bank 0
0xD000..=0xDFFF => self.var_ram.read_byte(addr), // 4KB Work RAM Bank 1 -> N 0xD000..=0xDFFF => self.var_ram.read_byte(addr), // 4KB Work RAM Bank 1 -> N
@ -279,9 +279,8 @@ impl BusIo for Bus {
0x0000..=0x7FFF => { 0x0000..=0x7FFF => {
// 16KB ROM bank 00 (ends at 0x3FFF) // 16KB ROM bank 00 (ends at 0x3FFF)
// and 16KB ROM Bank 01 -> NN (switchable via MB) // and 16KB ROM Bank 01 -> NN (switchable via MB)
match self.cart.as_mut() { if let Some(cart) = self.cart.as_mut() {
Some(cart) => cart.write_byte(addr, byte), cart.write_byte(addr, byte);
None => panic!("Tried to write into non-existent cartridge"),
} }
} }
0x8000..=0x9FFF => { 0x8000..=0x9FFF => {
@ -293,9 +292,8 @@ impl BusIo for Bus {
} }
0xA000..=0xBFFF => { 0xA000..=0xBFFF => {
// 8KB External RAM // 8KB External RAM
match self.cart.as_mut() { if let Some(cart) = self.cart.as_mut() {
Some(cart) => cart.write_byte(addr, byte), cart.write_byte(addr, byte);
None => panic!("Tried to write into non-existent cartridge"),
} }
} }
0xC000..=0xCFFF => self.work_ram.write_byte(addr, byte), // 4KB Work RAM Bank 0 0xC000..=0xCFFF => self.work_ram.write_byte(addr, byte), // 4KB Work RAM Bank 0

View File

@ -1,4 +1,5 @@
use crate::apu::gen::SampleProducer; use crate::apu::gen::SampleProducer;
use crate::bus::BOOT_SIZE;
use crate::cpu::Cpu; use crate::cpu::Cpu;
use crate::joypad::{self, Joypad}; use crate::joypad::{self, Joypad};
use crate::{Cycle, GB_HEIGHT, GB_WIDTH}; use crate::{Cycle, GB_HEIGHT, GB_WIDTH};
@ -6,7 +7,7 @@ use clap::crate_name;
use gilrs::Gilrs; use gilrs::Gilrs;
use std::fs::File; use std::fs::File;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::path::PathBuf; use std::path::{Path, PathBuf};
use std::time::Duration; use std::time::Duration;
use winit_input_helper::WinitInputHelper; use winit_input_helper::WinitInputHelper;
@ -39,21 +40,47 @@ pub struct Emulator {
timestamp: Cycle, timestamp: Cycle,
} }
impl Default for Emulator {
fn default() -> Self {
Self::new()
}
}
impl Emulator { impl Emulator {
fn new(cpu: Cpu) -> Self { pub fn new() -> Self {
Self { Self {
cpu, cpu: Cpu::with_boot(*include_bytes!("../bin/bootix_dmg.bin")),
timestamp: Default::default(), timestamp: Default::default(),
} }
} }
pub fn from_boot_rom<P: AsRef<Path>>(path: P) -> std::io::Result<Self> {
Ok(Self {
cpu: Cpu::with_boot(Self::read_boot(path)?),
timestamp: Default::default(),
})
}
fn read_boot<P: AsRef<Path>>(path: P) -> std::io::Result<[u8; BOOT_SIZE]> {
let mut buf = [0; BOOT_SIZE];
let mut file = File::open(path.as_ref())?;
file.read_exact(&mut buf)?;
Ok(buf)
}
fn step(&mut self) -> Cycle { fn step(&mut self) -> Cycle {
let cycles = self.cpu.step(); let cycles = self.cpu.step();
self.timestamp += cycles; self.timestamp += cycles;
cycles cycles
} }
fn load_cart(&mut self, rom: Vec<u8>) { pub fn read_game_rom<P: AsRef<Path>>(&mut self, path: P) -> std::io::Result<()> {
self.load_rom(std::fs::read(path.as_ref())?);
Ok(())
}
fn load_rom(&mut self, rom: Vec<u8>) {
self.cpu.bus_mut().load_cart(rom); self.cpu.bus_mut().load_cart(rom);
} }
@ -92,10 +119,11 @@ impl Emulator {
save_path.push(title); save_path.push(title);
save_path.set_extension("sav"); save_path.set_extension("sav");
if let Ok(mut file) = File::open(save_path) { if let Ok(mut file) = File::open(&save_path) {
tracing::info!("Load {:?}", save_path);
let mut memory = Vec::new(); let mut memory = Vec::new();
file.read_to_end(&mut memory)?; file.read_to_end(&mut memory)?;
cart.write_ext_ram(memory); cart.write_ext_ram(memory);
} }
} }
@ -115,67 +143,3 @@ impl Emulator {
} }
} }
} }
pub mod build {
use std::fs::File;
use std::io::{Read, Result};
use std::path::Path;
use tracing::info;
use crate::bus::BOOT_SIZE;
use crate::cpu::Cpu;
use super::Emulator;
#[derive(Debug, Default)]
pub struct EmulatorBuilder {
boot: Option<[u8; BOOT_SIZE]>,
cart: Option<Vec<u8>>,
}
impl EmulatorBuilder {
pub fn new() -> Self {
Default::default()
}
pub fn with_boot<P: AsRef<Path>>(mut self, path: P) -> Result<Self> {
let mut file = File::open(path.as_ref())?;
let mut buf = [0x00; BOOT_SIZE];
file.read_exact(&mut buf)?;
self.boot = Some(buf);
Ok(self)
}
pub fn with_cart<P: AsRef<Path>>(mut self, path: P) -> Result<Self> {
let mut file = File::open(path.as_ref())?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
self.cart = Some(buf);
Ok(self)
}
pub fn finish(mut self) -> Emulator {
let mut emu = Emulator::new(match self.boot {
Some(rom) => {
info!("User-provided Boot ROM");
Cpu::with_boot(rom)
}
None => {
info!("Built-in Boot ROM");
Cpu::with_boot(*include_bytes!("../bin/bootix_dmg.bin"))
}
});
if let Some(rom) = self.cart.take() {
emu.load_cart(rom)
}
emu
}
}
}

View File

@ -2,8 +2,7 @@ use std::convert::TryInto;
use anyhow::Result; use anyhow::Result;
use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg}; use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
use gb::emu::build::EmulatorBuilder; use gb::emu::{Emulator, CYCLES_IN_FRAME};
use gb::emu::CYCLES_IN_FRAME;
use gb::{Cycle, GB_HEIGHT, GB_WIDTH}; use gb::{Cycle, GB_HEIGHT, GB_WIDTH};
use gilrs::Gilrs; use gilrs::Gilrs;
use pixels::{PixelsBuilder, SurfaceTexture}; use pixels::{PixelsBuilder, SurfaceTexture};
@ -30,7 +29,6 @@ fn main() -> Result<()> {
Arg::with_name("rom") Arg::with_name("rom")
.value_name("ROM_FILE") .value_name("ROM_FILE")
.takes_value(true) .takes_value(true)
.required(true)
.index(1) .index(1)
.help("Path to the Game ROM"), .help("Path to the Game ROM"),
) )
@ -53,17 +51,23 @@ fn main() -> Result<()> {
.with_env_filter(EnvFilter::from_default_env()) .with_env_filter(EnvFilter::from_default_env())
.init(); .init();
let mut emu_build = let mut emu = match m.value_of("boot") {
EmulatorBuilder::new().with_cart(m.value_of("rom").expect("ROM path provided"))?; Some(path) => {
tracing::info!("User-provided boot ROM");
Emulator::from_boot_rom(path)?
}
None => {
tracing::info!("Built-in boot ROM");
Emulator::new()
}
};
if let Some(path) = m.value_of("boot") { if let Some(path) = m.value_of("rom") {
emu_build = emu_build.with_boot(path)?; tracing::info!("User-provided cartridge ROM");
emu.read_game_rom(path)?;
} }
let mut emu = emu_build.finish();
// Load Save file if it exists // Load Save file if it exists
info!("Attempt to load .sav");
emu.try_load_sav().expect("Load save if exists"); emu.try_load_sav().expect("Load save if exists");
let rom_title = emu.title(); let rom_title = emu.title();

View File

@ -369,7 +369,7 @@ impl Ppu {
} }
} }
ToFifoA => { ToFifoA => {
if let Ok(_) = self.fetch.send_to_fifo(&mut self.fifo) { if self.fetch.send_to_fifo(&mut self.fifo).is_ok() {
self.fetch.x_pos += 1; self.fetch.x_pos += 1;
self.fetch.back.state = ToFifoB; self.fetch.back.state = ToFifoB;
} }