feat: emulator now sucessfully runs boot rom
This commit is contained in:
parent
9143286e9c
commit
1da01a318d
|
@ -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),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -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> {
|
||||||
|
|
55
src/ppu.rs
55
src/ppu.rs
|
@ -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,
|
||||||
|
|
67
src/sound.rs
67
src/sound.rs
|
@ -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)]
|
||||||
|
|
Loading…
Reference in New Issue