chore: change how bus components are clocked
This commit is contained in:
parent
aa4a898a6b
commit
50efe12aec
22
src/bus.rs
22
src/bus.rs
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
191
src/ppu.rs
191
src/ppu.rs
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ pub(crate) struct Sound {
|
|||
}
|
||||
|
||||
impl Sound {
|
||||
pub(crate) fn step(&mut self, _cycles: Cycle) {
|
||||
pub(crate) fn clock(&mut self) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
|
38
src/timer.rs
38
src/timer.rs
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue