chore: remove Cycle struct and begin scheduler design

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

View File

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

View File

@ -1,14 +1,14 @@
use crate::cpu::Cpu as SM83;
use crate::instruction::cycle::Cycle;
use crate::joypad;
use crate::ppu::Ppu;
use crate::Cycle;
use anyhow::Result;
use gilrs::Gilrs;
use std::time::Duration;
use winit_input_helper::WinitInputHelper;
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
const DEFAULT_TITLE: &str = "DMG-01 Emulator";
@ -34,7 +34,7 @@ pub fn run(
input: &WinitInputHelper,
target: Cycle,
) -> Cycle {
let mut elapsed = Cycle::new(0);
let mut elapsed = 0;
if let Some(event) = gamepad.next_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 {
let mut elapsed = Cycle::new(0);
let mut elapsed = 0;
if let Some(event) = gamepad.next_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 instruction::cycle::Cycle;
pub type Cycle = u64;
pub const GB_WIDTH: usize = 160;
pub const GB_HEIGHT: usize = 144;

View File

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

View File

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

View File

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