feat: emulator now sucessfully runs boot rom

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-01-19 00:30:10 -06:00
parent 9143286e9c
commit 1da01a318d
4 changed files with 119 additions and 23 deletions

View File

@ -112,6 +112,7 @@ impl Bus {
0xFF0F => self.interrupt.flag.into(), 0xFF0F => self.interrupt.flag.into(),
0xFF11 => self.sound.ch1.sound_duty.into(), 0xFF11 => self.sound.ch1.sound_duty.into(),
0xFF12 => self.sound.ch1.vol_envelope.into(), 0xFF12 => self.sound.ch1.vol_envelope.into(),
0xFF14 => self.sound.ch1.freq.get_hi(),
0xFF24 => self.sound.control.channel.into(), 0xFF24 => self.sound.control.channel.into(),
0xFF25 => self.sound.control.select.into(), 0xFF25 => self.sound.control.select.into(),
0xFF26 => self.sound.control.status.into(), 0xFF26 => self.sound.control.status.into(),
@ -180,6 +181,8 @@ impl Bus {
0xFF0F => self.interrupt.flag = byte.into(), 0xFF0F => self.interrupt.flag = byte.into(),
0xFF11 => self.sound.ch1.sound_duty = byte.into(), 0xFF11 => self.sound.ch1.sound_duty = byte.into(),
0xFF12 => self.sound.ch1.vol_envelope = byte.into(), 0xFF12 => self.sound.ch1.vol_envelope = byte.into(),
0xFF13 => self.sound.ch1.freq.set_lo(byte),
0xFF14 => self.sound.ch1.freq.set_hi(byte),
0xFF24 => self.sound.control.channel = byte.into(), 0xFF24 => self.sound.control.channel = byte.into(),
0xFF25 => self.sound.control.select = byte.into(), 0xFF25 => self.sound.control.select = byte.into(),
0xFF26 => self.sound.control.status = byte.into(), // FIXME: Should we control which bytes are written to here? 0xFF26 => self.sound.control.status = byte.into(), // FIXME: Should we control which bytes are written to here?
@ -189,6 +192,12 @@ impl Bus {
0xFF43 => self.ppu.pos.scroll_x = byte, 0xFF43 => self.ppu.pos.scroll_x = byte,
0xFF44 => self.ppu.pos.line_y = byte, 0xFF44 => self.ppu.pos.line_y = byte,
0xFF47 => self.ppu.monochrome.bg_palette = byte.into(), 0xFF47 => self.ppu.monochrome.bg_palette = byte.into(),
0xFF50 => {
// Disable Boot ROM
if byte != 0 {
self.boot = None;
}
}
_ => unimplemented!("Unable to write to {:#06X} in I/O Registers", addr), _ => unimplemented!("Unable to write to {:#06X} in I/O Registers", addr),
}; };
} }

View File

@ -54,17 +54,6 @@ fn main() -> Result<()> {
// window.request_redraw(); // window.request_redraw();
} }
}); });
// loop {
// let pc = game_boy.register_pair(gb::cpu::RegisterPair::PC);
// let opcode = game_boy.fetch();
// let instruction = game_boy.decode(opcode);
// let _cycles = game_boy.execute(instruction);
// let ppu = game_boy.get_ppu();
// ppu.step();
// }
} }
pub fn create_window(event_loop: &EventLoop<()>) -> Result<Window> { pub fn create_window(event_loop: &EventLoop<()>) -> Result<Window> {

View File

@ -1,5 +1,7 @@
use crate::instruction::Cycles; use crate::instruction::Cycles;
const GB_WIDTH: usize = 160;
const GB_HEIGHT: usize = 144;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PPU { pub struct PPU {
pub lcd_control: LCDControl, pub lcd_control: LCDControl,
@ -7,32 +9,60 @@ pub struct PPU {
pub pos: ScreenPosition, pub pos: ScreenPosition,
pub vram: Box<[u8]>, pub vram: Box<[u8]>,
pub oam: Box<[u8]>, pub oam: Box<[u8]>,
frame_buf: [u8; GB_WIDTH * GB_HEIGHT * 4],
pub stat: LCDStatus, pub stat: LCDStatus,
cycles: Cycles, cycles: Cycles,
mode: PPUMode, mode: Mode,
} }
impl PPU { impl PPU {
pub fn step(&mut self, cycles: Cycles) { pub fn step(&mut self, cycles: Cycles) {
self.cycles += cycles; self.cycles += cycles;
// let smth: u32 = self.cycles.into();
// println!("Mode: {:?} | Cycles: {}", self.mode, smth);
match self.mode { match self.mode {
PPUMode::OAMScan => { Mode::OAMScan => {
if self.cycles >= 80.into() { if self.cycles >= 80.into() {
self.cycles = cycles % 80; self.cycles %= 80;
self.mode = Mode::Draw;
}
}
Mode::Draw => {
if self.cycles >= 172.into() {
// 172 -> 129 Cycles
// self.cycles %= 172;
self.mode = Mode::HBlank;
}
}
Mode::HBlank => {
// The 80 comes from the 80 cycles we made disappear in OAMScan above.
if self.cycles >= (456 - 80).into() {
self.cycles %= 456 - 80;
self.pos.line_y += 1;
if self.pos.line_y >= 144 {
self.mode = Mode::VBlank;
}
}
}
Mode::VBlank => {
if self.cycles >= 456.into() {
self.cycles %= 456;
self.pos.line_y += 1;
if self.pos.line_y == 154 {
self.mode = Mode::OAMScan;
self.pos.line_y = 0;
}
} }
} }
PPUMode::Draw => {}
PPUMode::HBlank => {}
PPUMode::VBlank => {}
} }
} }
pub fn draw(&self, frame: &mut [u8]) { pub fn draw(&self, frame: &mut [u8]) {
for (_i, pixel) in frame.chunks_exact_mut(4).enumerate() { frame.copy_from_slice(&self.frame_buf);
let rgba: [u8; 4] = [0xFF, 0xFF, 0xFF, 0xFF];
pixel.copy_from_slice(&rgba);
}
} }
} }
@ -46,13 +76,14 @@ impl Default for PPU {
vram: vec![0; 8192].into_boxed_slice(), vram: vec![0; 8192].into_boxed_slice(),
oam: vec![0; 160].into_boxed_slice(), oam: vec![0; 160].into_boxed_slice(),
cycles: 0.into(), cycles: 0.into(),
mode: PPUMode::OAMScan, frame_buf: [0; GB_WIDTH * GB_HEIGHT * 4],
mode: Mode::OAMScan,
} }
} }
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
enum PPUMode { enum Mode {
OAMScan, OAMScan,
Draw, Draw,
HBlank, HBlank,

View File

@ -19,6 +19,72 @@ pub struct SoundControl {
pub status: SoundStatus, pub status: SoundStatus,
} }
#[derive(Debug, Clone, Copy, Default)]
pub struct Frequency {
initial: bool,
freq_type: FrequencyType,
lo: u8, // Bottom 8 bits
hi: u8, // Top 3 bits (11 bits total)
}
#[derive(Debug, Clone, Copy)]
enum FrequencyType {
Counter,
Consequtive,
}
impl From<u8> for FrequencyType {
fn from(byte: u8) -> Self {
match byte {
0b00 => Self::Counter,
0b01 => Self::Consequtive,
_ => unreachable!("{} is not a valid number for FreuquencyType"),
}
}
}
impl From<FrequencyType> for u8 {
fn from(freq_type: FrequencyType) -> Self {
match freq_type {
FrequencyType::Counter => 0b00,
FrequencyType::Consequtive => 0b01,
}
}
}
impl Default for FrequencyType {
fn default() -> Self {
Self::Counter
}
}
impl Frequency {
fn get_11bit_freq(&self) -> u16 {
(self.hi as u16) << 8 | self.lo as u16
}
pub fn set_lo(&mut self, byte: u8) {
self.lo = byte;
}
pub fn get_lo(&self) -> u8 {
self.lo
}
pub fn set_hi(&mut self, byte: u8) {
*self = Self {
initial: byte >> 7 == 0x01,
freq_type: ((byte >> 6) & 0x01).into(),
lo: self.lo,
hi: byte & 0x07,
};
}
pub fn get_hi(&self) -> u8 {
(self.initial as u8) << 7 | (self.freq_type as u8) << 6 | self.hi
}
}
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]
pub struct SoundStatus { pub struct SoundStatus {
pub all_enabled: bool, // You can actually write to this one. pub all_enabled: bool, // You can actually write to this one.
@ -54,6 +120,7 @@ impl From<SoundStatus> for u8 {
pub struct Channel1 { pub struct Channel1 {
pub sound_duty: SoundDuty, pub sound_duty: SoundDuty,
pub vol_envelope: VolumeEnvelope, pub vol_envelope: VolumeEnvelope,
pub freq: Frequency,
} }
#[derive(Debug, Clone, Copy, Default)] #[derive(Debug, Clone, Copy, Default)]