Implement proper clock management
For some reason, sleep causes some issues in release in the egl crate. Maybe some timing issue ? In debug, the program is way slower than it should be
This commit is contained in:
parent
dec36156df
commit
af35cfc712
12
src/bus.rs
12
src/bus.rs
@ -14,6 +14,7 @@ pub struct Bus<M: Mapper> {
|
|||||||
ppu: Ppu<M>,
|
ppu: Ppu<M>,
|
||||||
apu: Ram<0x1F>,//TODO
|
apu: Ram<0x1F>,//TODO
|
||||||
cartridge: Rc<RefCell<M>>,
|
cartridge: Rc<RefCell<M>>,
|
||||||
|
tick_counter: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Mapper> fmt::Debug for Bus<M> {
|
impl<M: Mapper> fmt::Debug for Bus<M> {
|
||||||
@ -119,11 +120,20 @@ impl<M: Mapper> Bus<M> {
|
|||||||
ppu: Ppu::new(mapper.clone(), screen, pattern_table),
|
ppu: Ppu::new(mapper.clone(), screen, pattern_table),
|
||||||
apu: Ram::<0x1F>::new(),
|
apu: Ram::<0x1F>::new(),
|
||||||
cartridge: mapper,
|
cartridge: mapper,
|
||||||
|
tick_counter: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self) {
|
pub fn tick(&mut self) {
|
||||||
self.ppu.tick();
|
|
||||||
|
if self.tick_counter >= 3 {
|
||||||
|
self.tick_counter = 0;
|
||||||
|
self.ppu.tick();
|
||||||
|
} else {
|
||||||
|
self.tick_counter += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
18
src/cpu.rs
18
src/cpu.rs
@ -151,6 +151,7 @@ pub struct Cpu<M: Mapper> {
|
|||||||
s: u8,
|
s: u8,
|
||||||
p: StatusReg,
|
p: StatusReg,
|
||||||
bus: Bus<M>,
|
bus: Bus<M>,
|
||||||
|
tick_counter: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Mapper> fmt::Debug for Cpu<M> {
|
impl<M: Mapper> fmt::Debug for Cpu<M> {
|
||||||
@ -189,16 +190,23 @@ impl<M: Mapper> Cpu<M> {
|
|||||||
s: 0xFD,
|
s: 0xFD,
|
||||||
p: StatusReg::from_bits(0x34).unwrap(),
|
p: StatusReg::from_bits(0x34).unwrap(),
|
||||||
bus,
|
bus,
|
||||||
|
tick_counter: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self) {
|
pub fn tick(&mut self) {
|
||||||
|
|
||||||
self.execute();
|
if self.tick_counter >= 11 {
|
||||||
self.bus.tick();
|
self.tick_counter = 0;
|
||||||
}
|
self.execute();
|
||||||
|
} else {
|
||||||
|
self.tick_counter += 1;
|
||||||
|
}
|
||||||
|
|
||||||
fn execute(&mut self) {
|
self.bus.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn execute(&mut self) {
|
||||||
|
|
||||||
let opcode = self.read_pc_addr();
|
let opcode = self.read_pc_addr();
|
||||||
// if self.pc-1 > 0x36D0 && self.pc-1 < 0x36D8 {
|
// if self.pc-1 > 0x36D0 && self.pc-1 < 0x36D8 {
|
||||||
|
|||||||
34
src/main.rs
34
src/main.rs
@ -25,6 +25,12 @@ use canvas::{
|
|||||||
};
|
};
|
||||||
use utils::DisplayBuffer;
|
use utils::DisplayBuffer;
|
||||||
|
|
||||||
|
///Nanoseconds for 12 periods of the master clock (21.478 MHz). The frequency is divided by 12 since
|
||||||
|
///this is the CPU clock. All faster peripherals (i.e. the PPU, will be run whithout timing
|
||||||
|
///considerations whithing these 12 periods. This shouldn't affect the system's behavior while
|
||||||
|
///improving the clock's precision
|
||||||
|
const MASTER_CLOCK_PERIOD_NS: u128 = 559;
|
||||||
|
|
||||||
struct EmulatorState {
|
struct EmulatorState {
|
||||||
pub screen: Rc<RefCell<DisplayBuffer>>,
|
pub screen: Rc<RefCell<DisplayBuffer>>,
|
||||||
pub screen_sprite: TextureSprite,
|
pub screen_sprite: TextureSprite,
|
||||||
@ -95,15 +101,31 @@ impl Application<EmulatorState> for NesEmulator {
|
|||||||
|
|
||||||
fn tick(state: &mut EmulatorState, canvas: &mut Canvas) -> Result<(), &'static str> {
|
fn tick(state: &mut EmulatorState, canvas: &mut Canvas) -> Result<(), &'static str> {
|
||||||
|
|
||||||
let frame_time = state.start.elapsed().as_secs_f32();
|
//save frame start for frame time computation
|
||||||
state.start = Instant::now();
|
let frame_start = state.start;
|
||||||
canvas.clear();
|
|
||||||
state.cpu.tick();
|
|
||||||
|
|
||||||
if state.screen.borrow_mut().is_ready {
|
//tick the system for 1 frame
|
||||||
state.screen.borrow_mut().is_ready = false;
|
while state.screen.borrow_mut().is_ready == false {
|
||||||
|
|
||||||
|
let tick_period = state.start.elapsed().as_nanos();
|
||||||
|
//this should never fail as id frame_period doesn't fit in a u64, then the substraction
|
||||||
|
//saturated and the resulting 0 now fits
|
||||||
|
let delta = MASTER_CLOCK_PERIOD_NS.saturating_sub(tick_period) as u64;
|
||||||
|
std::thread::sleep(std::time::Duration::from_nanos(delta));
|
||||||
|
state.start = Instant::now();
|
||||||
|
|
||||||
|
for _ in 0..12 {
|
||||||
|
//TODO the cpu is ticked 12 times since MASTER_CLOCK_PERIOD_NS corresponds to 12
|
||||||
|
//clock periods. Further division is done in the function
|
||||||
|
state.cpu.tick();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
state.screen.borrow_mut().is_ready = false;
|
||||||
|
|
||||||
|
//draw frame
|
||||||
|
let frame_time = frame_start.elapsed().as_secs_f32();
|
||||||
|
|
||||||
|
canvas.clear();
|
||||||
canvas.draw(&mut state.screen_sprite);
|
canvas.draw(&mut state.screen_sprite);
|
||||||
canvas.draw(&mut state.pattern_sprite);
|
canvas.draw(&mut state.pattern_sprite);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user