diff --git a/src/main.rs b/src/main.rs index 3b0bb0e..be1c917 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,10 @@ mod processor; use clap::{ArgGroup, Parser}; use minifb::{Window, WindowOptions}; -use processor::CPU; +use processor::{ + memory::{Memory, ROM}, + CPU, +}; use std::{ fs, io::{self, stdout, Write}, @@ -61,153 +64,6 @@ struct Args { step_by: Option, } -type Address = u16; -type ROM = Vec; - -#[allow(dead_code)] -pub struct Memory { - bootrom: ROM, - bootrom_enabled: bool, - rom: ROM, - vram: [u8; 8192], - ram: [u8; 8192], - switchable_ram: [u8; 8192], - cpu_ram: [u8; 128], - oam: [u8; 160], - interrupts: u8, - ime: bool, - ime_scheduled: u8, - io: [u8; 76], - user_mode: bool, -} - -impl Memory { - fn init(bootrom: ROM, bootrom_enabled: bool, rom: ROM) -> Self { - Self { - bootrom, - bootrom_enabled, - rom, - vram: [0x0; 8192], - ram: [0x0; 8192], - switchable_ram: [0x0; 8192], - cpu_ram: [0x0; 128], - oam: [0x0; 160], - interrupts: 0x0, - ime: false, - ime_scheduled: 0x0, - io: [0xFF; 76], - user_mode: false, - } - } - - fn get(&self, address: Address) -> u8 { - match address { - 0x0..0x8000 => { - // rom access - // todo - switchable rom banks - if self.bootrom_enabled && ((address as usize) < self.bootrom.len()) { - return self.bootrom[address as usize]; - } else { - return self.rom[address as usize]; - } - } - 0x8000..0xA000 => { - return self.vram[(address - 0x8000) as usize]; - } - 0xA000..0xC000 => 0xFF, - 0xC000..0xE000 => { - return self.ram[(address - 0xC000) as usize]; - } - 0xE000..0xFE00 => { - return self.ram[(address - 0xE000) as usize]; - } - 0xFE00..0xFEA0 => { - return self.oam[(address - 0xFE00) as usize]; - } - 0xFEA0..0xFF00 => { - return 0x0; - } - 0xFF00..0xFF4C => { - if address == 0xFF00 { - return 0xFF; - } - return self.io[(address - 0xFF00) as usize]; - } - 0xFF4C..0xFF80 => { - // println!("empty space 2 read"); - return 0xFF; - } - 0xFF80..0xFFFF => { - return self.cpu_ram[(address - 0xFF80) as usize]; - } - 0xFFFF => { - return self.interrupts; - } - } - } - - fn set(&mut self, address: Address, data: u8) { - // verbose_println!("write addr: {:#X}, data: {:#X}", address, data); - - match address { - 0x0..0x8000 => { - // change this with MBC code... - // println!("tried to write {:#5X} at {:#X}", data, address); - } - 0x8000..0xA000 => { - self.vram[(address - 0x8000) as usize] = data; - } - 0xA000..0xC000 => { - // panic!("switchable write"); - // self.switchable_ram[(address - 0xA000) as usize] = data; - } - 0xC000..0xE000 => { - self.ram[(address - 0xC000) as usize] = data; - } - 0xE000..0xFE00 => { - self.ram[(address - 0xE000) as usize] = data; - } - 0xFE00..0xFEA0 => { - self.oam[(address - 0xFE00) as usize] = data; - } - 0xFEA0..0xFF00 => { - // println!("empty space write: {:#X} to addr {:#X}", data, address); - } - 0xFF04 => { - if self.user_mode { - self.io[0xFF04 - 0xFF00] = 0; - } else { - self.io[0xFF04 - 0xFF00] = data; - } - } - 0xFF00..0xFF04 | 0xFF05..0xFF4C => { - // verbose_print!("writing to addr {:#X}\r", address); - stdout().flush().unwrap(); - - if address == 0xFF02 && data == 0x81 { - print!("{}", self.get(0xFF01) as char); - stdout().flush().unwrap(); - } - self.io[(address - 0xFF00) as usize] = data; - } - 0xFF50 => { - self.bootrom_enabled = false; - } - 0xFF4C..0xFF50 | 0xFF51..0xFF80 => { - // println!("empty space 2 write: {:#X} to addr {:#X}", data, address); - } - 0xFF80..0xFFFF => { - self.cpu_ram[(address - 0xFF80) as usize] = data; - } - 0xFFFF => { - verbose_println!("interrupts set to {:#b}", data); - verbose_println!(" / {:#X}", data); - self.interrupts = data; - } - } - } -} - fn cpu_ram_init(cpu: &mut CPU) { cpu.memory.set(0xFF10, 0x80); cpu.memory.set(0xFF11, 0xBF); diff --git a/src/processor/memory.rs b/src/processor/memory.rs new file mode 100644 index 0000000..91d4230 --- /dev/null +++ b/src/processor/memory.rs @@ -0,0 +1,150 @@ +use std::io::{stdout, Write}; + +use crate::verbose_println; + +pub(crate) type Address = u16; +pub(crate) type ROM = Vec; + +#[allow(dead_code)] +pub struct Memory { + pub(super) bootrom: ROM, + pub(super) bootrom_enabled: bool, + pub(super) rom: ROM, + pub(super) vram: [u8; 8192], + pub(super) ram: [u8; 8192], + pub(super) switchable_ram: [u8; 8192], + pub(super) cpu_ram: [u8; 128], + pub(super) oam: [u8; 160], + pub(super) interrupts: u8, + pub(super) ime: bool, + pub(super) ime_scheduled: u8, + pub(super) io: [u8; 76], + pub(super) user_mode: bool, +} + +impl Memory { + pub fn init(bootrom: ROM, bootrom_enabled: bool, rom: ROM) -> Self { + Self { + bootrom, + bootrom_enabled, + rom, + vram: [0x0; 8192], + ram: [0x0; 8192], + switchable_ram: [0x0; 8192], + cpu_ram: [0x0; 128], + oam: [0x0; 160], + interrupts: 0x0, + ime: false, + ime_scheduled: 0x0, + io: [0xFF; 76], + user_mode: false, + } + } + + pub fn get(&self, address: Address) -> u8 { + match address { + 0x0..0x8000 => { + // rom access + // todo - switchable rom banks + if self.bootrom_enabled && ((address as usize) < self.bootrom.len()) { + return self.bootrom[address as usize]; + } else { + return self.rom[address as usize]; + } + } + 0x8000..0xA000 => { + return self.vram[(address - 0x8000) as usize]; + } + 0xA000..0xC000 => 0xFF, + 0xC000..0xE000 => { + return self.ram[(address - 0xC000) as usize]; + } + 0xE000..0xFE00 => { + return self.ram[(address - 0xE000) as usize]; + } + 0xFE00..0xFEA0 => { + return self.oam[(address - 0xFE00) as usize]; + } + 0xFEA0..0xFF00 => { + return 0x0; + } + 0xFF00..0xFF4C => { + if address == 0xFF00 { + return 0xFF; + } + return self.io[(address - 0xFF00) as usize]; + } + 0xFF4C..0xFF80 => { + // println!("empty space 2 read"); + return 0xFF; + } + 0xFF80..0xFFFF => { + return self.cpu_ram[(address - 0xFF80) as usize]; + } + 0xFFFF => { + return self.interrupts; + } + } + } + + pub fn set(&mut self, address: Address, data: u8) { + // verbose_println!("write addr: {:#X}, data: {:#X}", address, data); + + match address { + 0x0..0x8000 => { + // change this with MBC code... + // println!("tried to write {:#5X} at {:#X}", data, address); + } + 0x8000..0xA000 => { + self.vram[(address - 0x8000) as usize] = data; + } + 0xA000..0xC000 => { + // panic!("switchable write"); + // self.switchable_ram[(address - 0xA000) as usize] = data; + } + 0xC000..0xE000 => { + self.ram[(address - 0xC000) as usize] = data; + } + 0xE000..0xFE00 => { + self.ram[(address - 0xE000) as usize] = data; + } + 0xFE00..0xFEA0 => { + self.oam[(address - 0xFE00) as usize] = data; + } + 0xFEA0..0xFF00 => { + // println!("empty space write: {:#X} to addr {:#X}", data, address); + } + 0xFF04 => { + if self.user_mode { + self.io[0xFF04 - 0xFF00] = 0; + } else { + self.io[0xFF04 - 0xFF00] = data; + } + } + 0xFF00..0xFF04 | 0xFF05..0xFF4C => { + // verbose_print!("writing to addr {:#X}\r", address); + stdout().flush().unwrap(); + + if address == 0xFF02 && data == 0x81 { + print!("{}", self.get(0xFF01) as char); + stdout().flush().unwrap(); + } + self.io[(address - 0xFF00) as usize] = data; + } + 0xFF50 => { + self.bootrom_enabled = false; + } + 0xFF4C..0xFF50 | 0xFF51..0xFF80 => { + // println!("empty space 2 write: {:#X} to addr {:#X}", data, address); + } + 0xFF80..0xFFFF => { + self.cpu_ram[(address - 0xFF80) as usize] = data; + } + 0xFFFF => { + verbose_println!("interrupts set to {:#b}", data); + verbose_println!(" / {:#X}", data); + self.interrupts = data; + } + } + } +} diff --git a/src/processor/mod.rs b/src/processor/mod.rs index eed661c..50791d8 100644 --- a/src/processor/mod.rs +++ b/src/processor/mod.rs @@ -2,12 +2,14 @@ use std::{mem::transmute, time::Duration}; use minifb::Window; -use crate::{processor::instructions::instructions::set, verbose_println, Memory}; +use crate::{processor::instructions::instructions::set, verbose_println}; use self::gpu::GPU; +use self::memory::Memory; pub mod gpu; mod instructions; +pub mod memory; mod opcodes; #[derive(PartialEq)]