Compare commits
	
		
			3 Commits
		
	
	
		
			e19a540650
			...
			080c1e7518
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 080c1e7518 | |||
| 765f9d8288 | |||
| 8780c4a59b | 
							
								
								
									
										18
									
								
								src/bus.rs
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/bus.rs
									
									
									
									
									
								
							@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										104
									
								
								src/emu.rs
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								src/emu.rs
									
									
									
									
									
								
							@@ -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
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								src/main.rs
									
									
									
									
									
								
							@@ -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();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user