Compare commits

...

2 Commits

Author SHA1 Message Date
4caac23f66 Frame limiter 2021-11-20 11:27:08 -05:00
46262dfefa Some more implementations for MBC3, still WIP 2021-11-20 10:54:13 -05:00
3 changed files with 72 additions and 18 deletions

View File

@ -1,9 +1,11 @@
use std::{thread, time};
use std::time::Instant; use std::time::Instant;
pub struct Frames { pub struct Frames {
count: usize, count: usize,
timer: Instant, timer: Instant,
time_start: u128, time_start: u128,
fps: u128,
} }
impl Frames { impl Frames {
@ -12,6 +14,7 @@ impl Frames {
count: 0, count: 0,
timer: Instant::now(), timer: Instant::now(),
time_start: 0, time_start: 0,
fps: 1000 / 63,
} }
} }
@ -34,4 +37,14 @@ impl Frames {
pub fn count(&self) -> usize { pub fn count(&self) -> usize {
self.count self.count
} }
pub fn limit(&mut self) {
let elapsed = self.elapsed_ms();
// println!("{}", elapsed);
if elapsed > self.fps {
// println!("Frame dropped");
return;
}
thread::sleep(time::Duration::from_millis((self.fps - elapsed).try_into().unwrap()));
}
} }

View File

@ -43,6 +43,7 @@ pub fn create_window<T>(width: u32, height: u32, title: String, event_loop: &Eve
pub fn start_eventloop() { pub fn start_eventloop() {
let mut emulator = Emulator::new(); let mut emulator = Emulator::new();
let mut frames = Frames::new(); let mut frames = Frames::new();
let mut frame_limit = Frames::new();
env_logger::init(); env_logger::init();
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
@ -80,16 +81,16 @@ pub fn start_eventloop() {
*control_flow = ControlFlow::Exit *control_flow = ControlFlow::Exit
}, },
Event::MainEventsCleared => { Event::MainEventsCleared => {
frame_limit.reset_timer();
emulator.run(Cycles(70224), pixels.get_frame()); emulator.run(Cycles(70224), pixels.get_frame());
frames.increment(); frames.increment();
window.request_redraw();
if frames.elapsed_ms() >= 1000 { if frames.elapsed_ms() >= 1000 {
window.set_title(&format!("rmg-001 (FPS: {})", frames.count())); window.set_title(&format!("rmg-001 (FPS: {})", frames.count()));
frames.reset_count(); frames.reset_count();
frames.reset_timer(); frames.reset_timer();
} }
frame_limit.limit();
// thread::sleep(time::Duration::from_millis(1));
window.request_redraw();
}, },
Event::RedrawRequested(_) => { Event::RedrawRequested(_) => {
if pixels if pixels

View File

@ -568,6 +568,9 @@ pub struct MBC3 {
rom_bank: u16, rom_bank: u16,
ram_bank: u8, ram_bank: u8,
ram_timer_enable: bool, ram_timer_enable: bool,
map_rtc: bool,
prev_rtc_latch: u8,
rtc_register: u8,
} }
impl MBC3 { impl MBC3 {
@ -586,17 +589,24 @@ impl MBC3 {
rom_bank: 1, rom_bank: 1,
ram_bank: 0, ram_bank: 0,
ram_timer_enable: false, ram_timer_enable: false,
map_rtc: false,
prev_rtc_latch: 0,
rtc_register: 0x08,
} }
} }
fn switch_rom_bank(&mut self, bank: u16) { fn switch_rom_bank(&mut self, bank: u16) {
self.rom_bank = bank; self.rom_bank = bank & 0b01111111;
if self.rom_bank > self.info.rom_banks.saturating_sub(1) { if self.rom_bank > self.info.rom_banks.saturating_sub(1) {
self.rom_bank = self.info.rom_banks.saturating_sub(1); self.rom_bank = self.info.rom_banks.saturating_sub(1);
} else if self.rom_bank == 0 { } else if self.rom_bank == 0 {
self.rom_bank = 1; self.rom_bank = 1;
} }
} }
fn get_ram_address(&self, address: u16) -> usize {
(0x2000 * self.ram_bank as usize) + (address as usize - 0xA000)
}
} }
impl ROM for MBC3 { impl ROM for MBC3 {
@ -604,25 +614,32 @@ impl ROM for MBC3 {
if BANK_ZERO.contains(&address) { if BANK_ZERO.contains(&address) {
return self.data[address as usize]; return self.data[address as usize];
} else if BANK_SWITCHABLE.contains(&address) { } else if BANK_SWITCHABLE.contains(&address) {
return self.data[((self.rom_bank as usize * 0x4000) + (address as usize & 0x3FFF)) as usize]; return self.data[((self.rom_bank as usize * 0x4000) + (address as usize - 0x4000)) as usize];
} else if EXTERNAL_RAM.contains(&address) { } else if EXTERNAL_RAM.contains(&address) {
if !self.info.has_ram || !self.ram_timer_enable { if self.map_rtc {
if !self.ram_timer_enable {
return 0xFF; return 0xFF;
} }
return match self.ram.get((address - EXTERNAL_RAM.min().unwrap() + (0x2000 * self.ram_bank as u16)) as usize) { return 0xFF;
} else {
if !self.ram_timer_enable {
return 0xFF;
}
let address = self.get_ram_address(address);
return match self.ram.get(address) {
Some(data) => *data, Some(data) => *data,
None => 0xFF, None => 0xFF,
}; };
} }
return 0xFF; }
unreachable!("Invalid ROM read: {}", address);
} }
fn write(&mut self, address: u16, data: u8) { fn write(&mut self, address: u16, data: u8) {
if address >= 0xA000 && address <= 0xBFFF { if address <= 0x1FFF {
} else if address <= 0x1FFF {
match data { match data {
0x0A => self.ram_timer_enable = true, 0x0A => self.ram_timer_enable = true,
0x00 => self.ram_timer_enable = true, 0x00 => self.ram_timer_enable = false,
_ => {}, _ => {},
} }
} else if address >= 0x2000 && address <= 0x3FFF { } else if address >= 0x2000 && address <= 0x3FFF {
@ -630,11 +647,29 @@ impl ROM for MBC3 {
} else if address >= 0x4000 && address <= 0x5FFF { } else if address >= 0x4000 && address <= 0x5FFF {
if data <= 0x03 { if data <= 0x03 {
self.ram_bank = data; self.ram_bank = data;
} else if data >= 0x08 && data <= 0x0C && self.info.has_timer { self.map_rtc = false;
} else if data >= 0x08 && data <= 0x0C {
self.rtc_register = data;
self.map_rtc = true;
} }
} else if address >= 0x6000 && address <= 0x7FFF { } else if address >= 0x6000 && address <= 0x7FFF {
if self.prev_rtc_latch == 0 && data == 1 {
// latch
}
self.prev_rtc_latch = data;
} else if address >= 0xA000 && address <= 0xBFFF {
if !self.ram_timer_enable {
return;
} }
if self.map_rtc {
} else {
let address = self.get_ram_address(address);
if let Some(elem) = self.ram.get_mut(address) {
*elem = data;
}
}
}
} }
fn ram_mut(&mut self) -> &mut Vec<u8> { fn ram_mut(&mut self) -> &mut Vec<u8> {
@ -677,6 +712,10 @@ impl MBC5 {
ram_enable: false, ram_enable: false,
} }
} }
fn get_ram_address(&self, address: u16) -> usize {
(0x2000 * self.ram_bank as usize) + (address as usize - 0xA000)
}
} }
impl ROM for MBC5 { impl ROM for MBC5 {
@ -692,7 +731,7 @@ impl ROM for MBC5 {
if !self.info.has_ram || !self.ram_enable { if !self.info.has_ram || !self.ram_enable {
return 0xFF; return 0xFF;
} }
return match self.ram.get(((self.ram_bank as usize * 0x2000) + (address as usize - 0x2000)) as usize) { return match self.ram.get(self.get_ram_address(address)) {
Some(data) => *data, Some(data) => *data,
None => 0xFF, None => 0xFF,
}; };
@ -713,7 +752,8 @@ impl ROM for MBC5 {
if !self.ram_enable || !self.info.has_ram { if !self.ram_enable || !self.info.has_ram {
return; return;
} }
if let Some(elem) = self.ram.get_mut(((self.ram_bank as usize * 0x2000) + (address as usize % 0x2000)) as usize) { let address = self.get_ram_address(address);
if let Some(elem) = self.ram.get_mut(address) {
*elem = data; *elem = data;
} }
} }