remove Cycle struct and begin scheduler design
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-09-12 04:55:14 -03:00
parent 10ac579c40
commit 7e5ab99329
8 changed files with 226 additions and 305 deletions

View File

@ -1,10 +1,10 @@
use crate::apu::Apu; use crate::apu::Apu;
use crate::bus::{Bus, BusIo}; use crate::bus::{Bus, BusIo};
use crate::instruction::cycle::Cycle;
use crate::instruction::Instruction; use crate::instruction::Instruction;
use crate::interrupt::{InterruptEnable, InterruptFlag}; use crate::interrupt::{InterruptEnable, InterruptFlag};
use crate::joypad::Joypad; use crate::joypad::Joypad;
use crate::ppu::Ppu; use crate::ppu::Ppu;
use crate::Cycle;
use bitfield::bitfield; use bitfield::bitfield;
use std::fmt::{Display, Formatter, Result as FmtResult}; use std::fmt::{Display, Formatter, Result as FmtResult};
@ -133,7 +133,7 @@ impl Cpu {
self.bus.clock(); self.bus.clock();
let elapsed = match kind { let elapsed = match kind {
ImeEnabled | NonePending => Cycle::new(4), ImeEnabled | NonePending => 4,
SomePending => todo!("Implement HALT bug"), SomePending => todo!("Implement HALT bug"),
}; };
@ -146,11 +146,11 @@ impl Cpu {
self.handle_ei(); self.handle_ei();
// For use in Blargg's Test ROMs // For use in Blargg's Test ROMs
// if self.read_byte(0xFF02) == 0x81 { if self.read_byte(0xFF02) == 0x81 {
// let c = self.read_byte(0xFF01) as char; let c = self.read_byte(0xFF01) as char;
// self.write_byte(0xFF02, 0x00); self.write_byte(0xFF02, 0x00);
// eprint!("{}", c); eprint!("{}", c);
// } }
elapsed elapsed
} }

View File

@ -1,14 +1,14 @@
use crate::cpu::Cpu as SM83; use crate::cpu::Cpu as SM83;
use crate::instruction::cycle::Cycle;
use crate::joypad; use crate::joypad;
use crate::ppu::Ppu; use crate::ppu::Ppu;
use crate::Cycle;
use anyhow::Result; use anyhow::Result;
use gilrs::Gilrs; use gilrs::Gilrs;
use std::time::Duration; use std::time::Duration;
use winit_input_helper::WinitInputHelper; use winit_input_helper::WinitInputHelper;
pub const SM83_CYCLE_TIME: Duration = Duration::from_nanos(1_000_000_000 / SM83_CLOCK_SPEED); pub const SM83_CYCLE_TIME: Duration = Duration::from_nanos(1_000_000_000 / SM83_CLOCK_SPEED);
pub const CYCLES_IN_FRAME: Cycle = Cycle::new(456 * 154); // 456 Cycles times 154 scanlines pub const CYCLES_IN_FRAME: Cycle = 456 * 154; // 456 Cycles times 154 scanlines
pub(crate) const SM83_CLOCK_SPEED: u64 = 0x40_0000; // Hz which is 4.194304Mhz pub(crate) const SM83_CLOCK_SPEED: u64 = 0x40_0000; // Hz which is 4.194304Mhz
const DEFAULT_TITLE: &str = "DMG-01 Emulator"; const DEFAULT_TITLE: &str = "DMG-01 Emulator";
@ -34,7 +34,7 @@ pub fn run(
input: &WinitInputHelper, input: &WinitInputHelper,
target: Cycle, target: Cycle,
) -> Cycle { ) -> Cycle {
let mut elapsed = Cycle::new(0); let mut elapsed = 0;
if let Some(event) = gamepad.next_event() { if let Some(event) = gamepad.next_event() {
joypad::handle_gamepad_input(game_boy.joypad_mut(), event); joypad::handle_gamepad_input(game_boy.joypad_mut(), event);
@ -49,7 +49,7 @@ pub fn run(
} }
pub fn run_frame(game_boy: &mut SM83, gamepad: &mut Gilrs, input: &WinitInputHelper) -> Cycle { pub fn run_frame(game_boy: &mut SM83, gamepad: &mut Gilrs, input: &WinitInputHelper) -> Cycle {
let mut elapsed = Cycle::new(0); let mut elapsed = 0;
if let Some(event) = gamepad.next_event() { if let Some(event) = gamepad.next_event() {
joypad::handle_gamepad_input(game_boy.joypad_mut(), event); joypad::handle_gamepad_input(game_boy.joypad_mut(), event);

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
pub use apu::gen::AudioSPSC; pub use apu::gen::AudioSPSC;
pub use instruction::cycle::Cycle; pub type Cycle = u64;
pub const GB_WIDTH: usize = 160; pub const GB_WIDTH: usize = 160;
pub const GB_HEIGHT: usize = 144; pub const GB_HEIGHT: usize = 144;

View File

@ -11,7 +11,7 @@ use winit::window::{Window, WindowBuilder};
use winit_input_helper::WinitInputHelper; use winit_input_helper::WinitInputHelper;
const WINDOW_SCALE: usize = 3; const WINDOW_SCALE: usize = 3;
const AUDIO_ENABLED: bool = true; const AUDIO_ENABLED: bool = false;
fn main() -> Result<()> { fn main() -> Result<()> {
let app = App::new(crate_name!()) let app = App::new(crate_name!())

View File

@ -1,5 +1,5 @@
use crate::bus::BusIo; use crate::bus::BusIo;
use crate::instruction::cycle::Cycle; use crate::Cycle;
use crate::GB_HEIGHT; use crate::GB_HEIGHT;
use crate::GB_WIDTH; use crate::GB_WIDTH;
use dma::DirectMemoryAccess; use dma::DirectMemoryAccess;
@ -79,7 +79,7 @@ impl Ppu {
match self.stat.mode() { match self.stat.mode() {
PpuMode::OamScan => { PpuMode::OamScan => {
if self.cycle >= 80.into() { if self.cycle >= 80 {
self.stat.set_mode(PpuMode::Drawing); self.stat.set_mode(PpuMode::Drawing);
} }
@ -88,7 +88,7 @@ impl Ppu {
PpuMode::Drawing => { PpuMode::Drawing => {
if self.ctrl.lcd_enabled() { if self.ctrl.lcd_enabled() {
// Only Draw when the LCD Is Enabled // Only Draw when the LCD Is Enabled
self.draw(self.cycle.into()); self.draw(self.cycle);
} else { } else {
self.reset(); self.reset();
} }
@ -125,7 +125,7 @@ impl Ppu {
PpuMode::HBlank => { PpuMode::HBlank => {
// This mode will always end at 456 cycles // This mode will always end at 456 cycles
if self.cycle >= 456.into() { if self.cycle >= 456 {
self.cycle %= 456; self.cycle %= 456;
self.pos.line_y += 1; self.pos.line_y += 1;
@ -167,7 +167,7 @@ impl Ppu {
} }
} }
PpuMode::VBlank => { PpuMode::VBlank => {
if self.cycle > 456.into() { if self.cycle > 456 {
self.cycle %= 456; self.cycle %= 456;
self.pos.line_y += 1; self.pos.line_y += 1;
@ -228,7 +228,7 @@ impl Ppu {
self.scan_state.next(); self.scan_state.next();
} }
fn draw(&mut self, _cycle: u32) { fn draw(&mut self, _cycle: Cycle) {
use FetcherState::*; use FetcherState::*;
let mut iter = self.obj_buffer.iter_mut(); let mut iter = self.obj_buffer.iter_mut();
@ -470,7 +470,7 @@ impl Default for Ppu {
fn default() -> Self { fn default() -> Self {
Self { Self {
vram: Box::new([0u8; VRAM_SIZE]), vram: Box::new([0u8; VRAM_SIZE]),
cycle: Cycle::new(0), cycle: Default::default(),
frame_buf: Box::new([0; GB_WIDTH * GB_HEIGHT * 4]), frame_buf: Box::new([0; GB_WIDTH * GB_HEIGHT * 4]),
int: Default::default(), int: Default::default(),
ctrl: Default::default(), ctrl: Default::default(),

View File

@ -1,4 +1,4 @@
use crate::instruction::cycle::Cycle; use crate::Cycle;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub(crate) struct DirectMemoryAccess { pub(crate) struct DirectMemoryAccess {
@ -56,7 +56,7 @@ impl DirectMemoryAccess {
} }
fn reset(&mut self) { fn reset(&mut self) {
self.cycle = Cycle::new(0); self.cycle = 0;
self.state = DmaState::Disabled; self.state = DmaState::Disabled;
self.start.0 = None; self.start.0 = None;
} }

79
src/scheduler.rs Normal file
View File

@ -0,0 +1,79 @@
use crate::Cycle;
use std::collections::BinaryHeap;
#[derive(Debug)]
pub(crate) struct Scheduler {
timestamp: Cycle,
queue: BinaryHeap<Event>,
}
impl Scheduler {
pub(crate) fn init() -> Self {
let mut scheduler = Self {
timestamp: Default::default(),
queue: Default::default(),
};
scheduler.push(Event {
kind: EventKind::TimestampOverflow,
timestamp: Cycle::MAX,
cb: |_delay| panic!("Reached Cycle::MAX"),
});
scheduler
}
pub(crate) fn push(&mut self, event: Event) {
self.queue.push(event);
}
pub(crate) fn step(&mut self, cycles: Cycle) {
self.timestamp += cycles;
loop {
let should_pop = match self.queue.peek() {
Some(event) => self.timestamp >= event.timestamp,
None => false,
};
if !should_pop {
break;
}
let event = self.queue.pop().expect("Pop Event from Scheduler Queue");
(event.cb)(self.timestamp - event.timestamp);
}
}
}
#[derive(Debug)]
pub(crate) struct Event {
kind: EventKind,
cb: fn(Cycle),
pub(crate) timestamp: Cycle,
}
impl Eq for Event {}
impl PartialEq for Event {
fn eq(&self, other: &Self) -> bool {
self.kind == other.kind && self.timestamp == other.timestamp
}
}
impl PartialOrd for Event {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Event {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.timestamp.cmp(&other.timestamp)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum EventKind {
TimestampOverflow,
}