chore: change how bus components are clocked

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-06-09 19:41:10 -05:00
parent aa4a898a6b
commit 50efe12aec
5 changed files with 125 additions and 134 deletions

View File

@ -67,21 +67,17 @@ impl Bus {
self.cartridge.as_ref()?.title()
}
pub(crate) fn step(&mut self, cycles: Cycle) {
self.step_dma(cycles);
self.ppu.step(cycles);
self.timer.step(cycles);
self.sound.step(cycles);
pub(crate) fn clock(&mut self) {
self.ppu.clock();
self.timer.clock();
self.sound.clock();
self.clock_dma();
}
pub(crate) fn step_dma(&mut self, pending: Cycle) {
let pending_cycles: u32 = pending.into();
for _ in 0..pending_cycles {
if let Some((src_addr, dest_addr)) = self.ppu.dma.clock() {
let byte = self.oam_read_byte(src_addr);
self.oam_write_byte(dest_addr, byte);
}
fn clock_dma(&mut self) {
if let Some((src_addr, dest_addr)) = self.ppu.dma.clock() {
let byte = self.oam_read_byte(src_addr);
self.oam_write_byte(dest_addr, byte);
}
}

View File

@ -136,8 +136,10 @@ impl Cpu {
}
};
self.bus.step(cycles);
self.bus.step_dma(cycles);
let pending: u32 = cycles.into();
for _ in 0..pending {
self.bus.clock();
}
self.handle_interrupts();

View File

@ -66,124 +66,119 @@ impl BusIo for Ppu {
}
impl Ppu {
pub(crate) fn step(&mut self, cycles: Cycle) {
let start: u32 = self.cycle.into();
let end: u32 = cycles.into();
pub(crate) fn clock(&mut self) {
self.cycle += 1;
for _ in start..(start + end) {
self.cycle += 1;
match self.stat.mode() {
PpuMode::OamScan => {
if self.cycle >= 80.into() {
self.stat.set_mode(PpuMode::Drawing);
}
match self.stat.mode() {
PpuMode::OamScan => {
if self.cycle >= 80.into() {
self.stat.set_mode(PpuMode::Drawing);
self.scan_oam();
}
PpuMode::Drawing => {
if self.x_pos >= 160 {
if self.stat.hblank_int() {
// Enable HBlank LCDStat Interrupt
self.int.set_lcd_stat(true);
}
self.scan_oam();
// Done with rendering this frame,
// we can reset the ppu x_pos and fetcher state now
// Increment Window line counter if scanline had any window pixels on it
// only increment once per scanline though
if self.window_stat.should_draw() {
self.fetch.back.window_line.increment();
}
self.x_pos = 0;
self.fetch.hblank_reset();
self.window_stat.hblank_reset();
self.obj_buffer.clear();
self.fifo.back.clear();
self.fifo.obj.clear();
self.stat.set_mode(PpuMode::HBlank);
} else if self.ctrl.lcd_enabled() {
// Only Draw when the LCD Is Enabled
self.draw(self.cycle.into());
} else {
self.reset();
}
PpuMode::Drawing => {
if self.x_pos >= 160 {
if self.stat.hblank_int() {
// Enable HBlank LCDStat Interrupt
}
PpuMode::HBlank => {
// This mode will always end at 456 cycles
if self.cycle >= 456.into() {
self.cycle %= 456;
self.pos.line_y += 1;
// Update LY==LYC bit
let are_equal = self.pos.line_y == self.pos.ly_compare;
self.stat.set_coincidence(are_equal);
// Request LCD STAT interrupt if conditions met
if self.stat.coincidence_int() && are_equal {
self.int.set_lcd_stat(true);
}
let next_mode = if self.pos.line_y >= 144 {
// Request VBlank Interrupt
self.int.set_vblank(true);
// Reset Window Line Counter in Fetcher
self.fetch.vblank_reset();
// Reset WY=LY coincidence flag
self.window_stat.vblank_reset();
if self.stat.vblank_int() {
// Enable Vblank LCDStat Interrupt
self.int.set_lcd_stat(true);
}
// Done with rendering this frame,
// we can reset the ppu x_pos and fetcher state now
// Increment Window line counter if scanline had any window pixels on it
// only increment once per scanline though
if self.window_stat.should_draw() {
self.fetch.back.window_line.increment();
}
self.x_pos = 0;
self.fetch.hblank_reset();
self.window_stat.hblank_reset();
self.obj_buffer.clear();
self.fifo.back.clear();
self.fifo.obj.clear();
self.stat.set_mode(PpuMode::HBlank);
} else if self.ctrl.lcd_enabled() {
// Only Draw when the LCD Is Enabled
self.draw(self.cycle.into());
PpuMode::VBlank
} else {
self.reset();
}
}
PpuMode::HBlank => {
// This mode will always end at 456 cycles
if self.cycle >= 456.into() {
self.cycle %= 456;
self.pos.line_y += 1;
// Update LY==LYC bit
let are_equal = self.pos.line_y == self.pos.ly_compare;
self.stat.set_coincidence(are_equal);
// Request LCD STAT interrupt if conditions met
if self.stat.coincidence_int() && are_equal {
if self.stat.oam_int() {
// Enable OAM LCDStat Interrupt
self.int.set_lcd_stat(true);
}
let next_mode = if self.pos.line_y >= 144 {
// Request VBlank Interrupt
self.int.set_vblank(true);
self.scan_state.reset();
PpuMode::OamScan
};
// Reset Window Line Counter in Fetcher
self.fetch.vblank_reset();
// Reset WY=LY coincidence flag
self.window_stat.vblank_reset();
if self.stat.vblank_int() {
// Enable Vblank LCDStat Interrupt
self.int.set_lcd_stat(true);
}
PpuMode::VBlank
} else {
if self.stat.oam_int() {
// Enable OAM LCDStat Interrupt
self.int.set_lcd_stat(true);
}
self.scan_state.reset();
PpuMode::OamScan
};
self.stat.set_mode(next_mode);
}
self.stat.set_mode(next_mode);
}
PpuMode::VBlank => {
if self.cycle > 456.into() {
self.cycle %= 456;
self.pos.line_y += 1;
}
PpuMode::VBlank => {
if self.cycle > 456.into() {
self.cycle %= 456;
self.pos.line_y += 1;
// Update LY==LYC bit
let are_equal = self.pos.line_y == self.pos.ly_compare;
self.stat.set_coincidence(are_equal);
// Update LY==LYC bit
let are_equal = self.pos.line_y == self.pos.ly_compare;
self.stat.set_coincidence(are_equal);
// Request LCD STAT interrupt if conditions met
if self.stat.coincidence_int() && are_equal {
// Request LCD STAT interrupt if conditions met
if self.stat.coincidence_int() && are_equal {
self.int.set_lcd_stat(true);
}
if self.pos.line_y == 154 {
self.pos.line_y = 0;
if self.stat.oam_int() {
// Enable OAM LCDStat Interrupt
self.int.set_lcd_stat(true);
}
if self.pos.line_y == 154 {
self.pos.line_y = 0;
self.scan_state.reset();
if self.stat.oam_int() {
// Enable OAM LCDStat Interrupt
self.int.set_lcd_stat(true);
}
self.scan_state.reset();
self.stat.set_mode(PpuMode::OamScan);
}
self.stat.set_mode(PpuMode::OamScan);
}
}
}

View File

@ -7,7 +7,7 @@ pub(crate) struct Sound {
}
impl Sound {
pub(crate) fn step(&mut self, _cycles: Cycle) {
pub(crate) fn clock(&mut self) {
//
}
}

View File

@ -16,33 +16,31 @@ pub(crate) struct Timer {
}
impl Timer {
pub(crate) fn step(&mut self, cycles: Cycle) {
pub(crate) fn clock(&mut self) {
use TimerSpeed::*;
for _ in 0..cycles.into() {
self.divider = self.divider.wrapping_add(1);
self.divider = self.divider.wrapping_add(1);
// Get Bit Position
let bit = match self.ctrl.speed() {
Hz4096 => 9,
Hz262144 => 3,
Hz65536 => 5,
Hz16384 => 7,
};
// Get Bit Position
let bit = match self.ctrl.speed() {
Hz4096 => 9,
Hz262144 => 3,
Hz65536 => 5,
Hz16384 => 7,
};
let bit = (self.divider >> bit) as u8 & 0x01;
let timer_enable = self.ctrl.enabled() as u8;
let and_result = bit & timer_enable;
let bit = (self.divider >> bit) as u8 & 0x01;
let timer_enable = self.ctrl.enabled() as u8;
let and_result = bit & timer_enable;
if let Some(previous) = self.prev_and_result {
if previous == 0x01 && and_result == 0x00 {
// Falling Edge, increase TIMA Register
self.increment_tima();
}
if let Some(previous) = self.prev_and_result {
if previous == 0x01 && and_result == 0x00 {
// Falling Edge, increase TIMA Register
self.increment_tima();
}
self.prev_and_result = Some(and_result);
}
self.prev_and_result = Some(and_result);
}
fn increment_tima(&mut self) {