chore: change how bus components are clocked
This commit is contained in:
		
							
								
								
									
										22
									
								
								src/bus.rs
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/bus.rs
									
									
									
									
									
								
							| @@ -67,21 +67,17 @@ impl Bus { | |||||||
|         self.cartridge.as_ref()?.title() |         self.cartridge.as_ref()?.title() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub(crate) fn step(&mut self, cycles: Cycle) { |     pub(crate) fn clock(&mut self) { | ||||||
|         self.step_dma(cycles); |         self.ppu.clock(); | ||||||
|         self.ppu.step(cycles); |         self.timer.clock(); | ||||||
|         self.timer.step(cycles); |         self.sound.clock(); | ||||||
|         self.sound.step(cycles); |         self.clock_dma(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     pub(crate) fn step_dma(&mut self, pending: Cycle) { |     fn clock_dma(&mut self) { | ||||||
|         let pending_cycles: u32 = pending.into(); |         if let Some((src_addr, dest_addr)) = self.ppu.dma.clock() { | ||||||
|  |             let byte = self.oam_read_byte(src_addr); | ||||||
|         for _ in 0..pending_cycles { |             self.oam_write_byte(dest_addr, byte); | ||||||
|             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); |         let pending: u32 = cycles.into(); | ||||||
|         self.bus.step_dma(cycles); |         for _ in 0..pending { | ||||||
|  |             self.bus.clock(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         self.handle_interrupts(); |         self.handle_interrupts(); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										191
									
								
								src/ppu.rs
									
									
									
									
									
								
							
							
						
						
									
										191
									
								
								src/ppu.rs
									
									
									
									
									
								
							| @@ -66,124 +66,119 @@ impl BusIo for Ppu { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl Ppu { | impl Ppu { | ||||||
|     pub(crate) fn step(&mut self, cycles: Cycle) { |     pub(crate) fn clock(&mut self) { | ||||||
|         let start: u32 = self.cycle.into(); |         self.cycle += 1; | ||||||
|         let end: u32 = cycles.into(); |  | ||||||
|  |  | ||||||
|         for _ in start..(start + end) { |         match self.stat.mode() { | ||||||
|             self.cycle += 1; |             PpuMode::OamScan => { | ||||||
|  |                 if self.cycle >= 80.into() { | ||||||
|  |                     self.stat.set_mode(PpuMode::Drawing); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|             match self.stat.mode() { |                 self.scan_oam(); | ||||||
|                 PpuMode::OamScan => { |             } | ||||||
|                     if self.cycle >= 80.into() { |             PpuMode::Drawing => { | ||||||
|                         self.stat.set_mode(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 { |             PpuMode::HBlank => { | ||||||
|                         if self.stat.hblank_int() { |                 // This mode will always end at 456 cycles | ||||||
|                             // Enable HBlank LCDStat Interrupt |  | ||||||
|  |                 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); |                             self.int.set_lcd_stat(true); | ||||||
|                         } |                         } | ||||||
|  |  | ||||||
|                         // Done with rendering this frame, |                         PpuMode::VBlank | ||||||
|                         // 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 { |                     } else { | ||||||
|                         self.reset(); |                         if self.stat.oam_int() { | ||||||
|                     } |                             // Enable OAM 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); |                             self.int.set_lcd_stat(true); | ||||||
|                         } |                         } | ||||||
|  |  | ||||||
|                         let next_mode = if self.pos.line_y >= 144 { |                         self.scan_state.reset(); | ||||||
|                             // Request VBlank Interrupt |                         PpuMode::OamScan | ||||||
|                             self.int.set_vblank(true); |                     }; | ||||||
|  |  | ||||||
|                             // Reset Window Line Counter in Fetcher |                     self.stat.set_mode(next_mode); | ||||||
|                             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); |  | ||||||
|                     } |  | ||||||
|                 } |                 } | ||||||
|                 PpuMode::VBlank => { |             } | ||||||
|                     if self.cycle > 456.into() { |             PpuMode::VBlank => { | ||||||
|                         self.cycle %= 456; |                 if self.cycle > 456.into() { | ||||||
|                         self.pos.line_y += 1; |                     self.cycle %= 456; | ||||||
|  |                     self.pos.line_y += 1; | ||||||
|  |  | ||||||
|                         // Update LY==LYC bit |                     // Update LY==LYC bit | ||||||
|                         let are_equal = self.pos.line_y == self.pos.ly_compare; |                     let are_equal = self.pos.line_y == self.pos.ly_compare; | ||||||
|                         self.stat.set_coincidence(are_equal); |                     self.stat.set_coincidence(are_equal); | ||||||
|  |  | ||||||
|                         // Request LCD STAT interrupt if conditions met |                     // Request LCD STAT interrupt if conditions met | ||||||
|                         if self.stat.coincidence_int() && are_equal { |                     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); |                             self.int.set_lcd_stat(true); | ||||||
|                         } |                         } | ||||||
|  |  | ||||||
|                         if self.pos.line_y == 154 { |                         self.scan_state.reset(); | ||||||
|                             self.pos.line_y = 0; |  | ||||||
|  |  | ||||||
|                             if self.stat.oam_int() { |                         self.stat.set_mode(PpuMode::OamScan); | ||||||
|                                 // Enable OAM LCDStat Interrupt |  | ||||||
|                                 self.int.set_lcd_stat(true); |  | ||||||
|                             } |  | ||||||
|  |  | ||||||
|                             self.scan_state.reset(); |  | ||||||
|  |  | ||||||
|                             self.stat.set_mode(PpuMode::OamScan); |  | ||||||
|                         } |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ pub(crate) struct Sound { | |||||||
| } | } | ||||||
|  |  | ||||||
| impl 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 { | impl Timer { | ||||||
|     pub(crate) fn step(&mut self, cycles: Cycle) { |     pub(crate) fn clock(&mut self) { | ||||||
|         use TimerSpeed::*; |         use TimerSpeed::*; | ||||||
|  |  | ||||||
|         for _ in 0..cycles.into() { |         self.divider = self.divider.wrapping_add(1); | ||||||
|             self.divider = self.divider.wrapping_add(1); |  | ||||||
|  |  | ||||||
|             // Get Bit Position |         // Get Bit Position | ||||||
|             let bit = match self.ctrl.speed() { |         let bit = match self.ctrl.speed() { | ||||||
|                 Hz4096 => 9, |             Hz4096 => 9, | ||||||
|                 Hz262144 => 3, |             Hz262144 => 3, | ||||||
|                 Hz65536 => 5, |             Hz65536 => 5, | ||||||
|                 Hz16384 => 7, |             Hz16384 => 7, | ||||||
|             }; |         }; | ||||||
|  |  | ||||||
|             let bit = (self.divider >> bit) as u8 & 0x01; |         let bit = (self.divider >> bit) as u8 & 0x01; | ||||||
|             let timer_enable = self.ctrl.enabled() as u8; |         let timer_enable = self.ctrl.enabled() as u8; | ||||||
|             let and_result = bit & timer_enable; |         let and_result = bit & timer_enable; | ||||||
|  |  | ||||||
|             if let Some(previous) = self.prev_and_result { |         if let Some(previous) = self.prev_and_result { | ||||||
|                 if previous == 0x01 && and_result == 0x00 { |             if previous == 0x01 && and_result == 0x00 { | ||||||
|                     // Falling Edge, increase TIMA Register |                 // Falling Edge, increase TIMA Register | ||||||
|                     self.increment_tima(); |                 self.increment_tima(); | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             self.prev_and_result = Some(and_result); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         self.prev_and_result = Some(and_result); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fn increment_tima(&mut self) { |     fn increment_tima(&mut self) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user