mirror of
https://github.com/FranLMSP/rmg-001.git
synced 2024-11-27 03:31:31 +00:00
Timer implement
This commit is contained in:
parent
abbd46ebed
commit
61db367f31
@ -7,6 +7,7 @@ use crate::utils::{
|
|||||||
use crate::rom::ROM;
|
use crate::rom::ROM;
|
||||||
use crate::ppu::{PPU, LCDStatus, LCDStatusModeFlag};
|
use crate::ppu::{PPU, LCDStatus, LCDStatusModeFlag};
|
||||||
use crate::cpu::{Interrupt};
|
use crate::cpu::{Interrupt};
|
||||||
|
use crate::timer::{TIMER_DIVIDER_REGISTER_ADDRESS};
|
||||||
|
|
||||||
pub struct AddressRange {
|
pub struct AddressRange {
|
||||||
begin: u16,
|
begin: u16,
|
||||||
@ -107,6 +108,8 @@ impl Bus {
|
|||||||
self.data[(WORK_RAM_1.begin() + (address - ECHO_RAM.begin())) as usize] = data; // Copy to the working RAM
|
self.data[(WORK_RAM_1.begin() + (address - ECHO_RAM.begin())) as usize] = data; // Copy to the working RAM
|
||||||
} else if VIDEO_RAM.in_range(address) {
|
} else if VIDEO_RAM.in_range(address) {
|
||||||
self.data[address as usize] = data;
|
self.data[address as usize] = data;
|
||||||
|
} else if address == TIMER_DIVIDER_REGISTER_ADDRESS {
|
||||||
|
self.data[address as usize] = 0x00;
|
||||||
} else {
|
} else {
|
||||||
self.data[address as usize] = data;
|
self.data[address as usize] = data;
|
||||||
}
|
}
|
||||||
|
@ -830,6 +830,12 @@ pub enum Opcode {
|
|||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct Cycles(pub usize);
|
pub struct Cycles(pub usize);
|
||||||
|
|
||||||
|
impl Cycles {
|
||||||
|
pub fn to_t(&self) -> usize {
|
||||||
|
self.0 * 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct CPU {
|
pub struct CPU {
|
||||||
registers: Registers,
|
registers: Registers,
|
||||||
cycles: Cycles,
|
cycles: Cycles,
|
||||||
|
@ -3,6 +3,7 @@ use std::{thread, time};
|
|||||||
use crate::cpu::{CPU, Cycles};
|
use crate::cpu::{CPU, Cycles};
|
||||||
use crate::ppu::PPU;
|
use crate::ppu::PPU;
|
||||||
use crate::bus::Bus;
|
use crate::bus::Bus;
|
||||||
|
use crate::timer::Timer;
|
||||||
|
|
||||||
pub struct Emulator {
|
pub struct Emulator {
|
||||||
cpu: CPU,
|
cpu: CPU,
|
||||||
@ -31,6 +32,7 @@ impl Emulator {
|
|||||||
while self.cpu.get_cycles().0 <= cpu_cycles.0 {
|
while self.cpu.get_cycles().0 <= cpu_cycles.0 {
|
||||||
self.cpu.run(&mut self.bus);
|
self.cpu.run(&mut self.bus);
|
||||||
self.ppu.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles());
|
self.ppu.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles());
|
||||||
|
Timer::do_cycles(&mut self.bus, self.cpu.get_last_op_cycles());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
pub mod utils;
|
pub mod utils;
|
||||||
pub mod cpu;
|
pub mod cpu;
|
||||||
pub mod ppu;
|
pub mod ppu;
|
||||||
|
pub mod timer;
|
||||||
pub mod rom;
|
pub mod rom;
|
||||||
pub mod bus;
|
pub mod bus;
|
||||||
pub mod emulator;
|
pub mod emulator;
|
||||||
|
11
src/ppu.rs
11
src/ppu.rs
@ -118,11 +118,6 @@ impl PPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let lyc_compare = PPU::get_lcd_y(bus) == bus.read(LCD_Y_COMPARE_ADDRESS);
|
|
||||||
PPU::set_lcd_status(bus, LCDStatus::LYCInterrupt, lyc_compare);
|
|
||||||
if lyc_compare {
|
|
||||||
bus.set_interrupt(Interrupt::LCDSTAT, true);
|
|
||||||
}
|
|
||||||
self.increment_cycles(Cycles(1));
|
self.increment_cycles(Cycles(1));
|
||||||
|
|
||||||
// Horizontal scan completed
|
// Horizontal scan completed
|
||||||
@ -131,6 +126,12 @@ impl PPU {
|
|||||||
|
|
||||||
PPU::set_lcd_y(bus, PPU::get_lcd_y(bus) + 1);
|
PPU::set_lcd_y(bus, PPU::get_lcd_y(bus) + 1);
|
||||||
|
|
||||||
|
let lyc_compare = PPU::get_lcd_y(bus) == bus.read(LCD_Y_COMPARE_ADDRESS);
|
||||||
|
if lyc_compare {
|
||||||
|
PPU::set_lcd_status(bus, LCDStatus::LYCInterrupt, lyc_compare);
|
||||||
|
bus.set_interrupt(Interrupt::LCDSTAT, true);
|
||||||
|
}
|
||||||
|
|
||||||
// Frame completed
|
// Frame completed
|
||||||
if PPU::get_lcd_y(bus) > 153 {
|
if PPU::get_lcd_y(bus) > 153 {
|
||||||
PPU::set_lcd_y(bus, 0);
|
PPU::set_lcd_y(bus, 0);
|
||||||
|
56
src/timer.rs
56
src/timer.rs
@ -1,11 +1,55 @@
|
|||||||
const DIVIDER_REGISTER_ADDRESS: u16 = 0xFF04;
|
use crate::cpu::{Interrupt, Cycles};
|
||||||
const TIMER_COUNTER_ADDRESS: u16 = 0xFF05;
|
use crate::bus::Bus;
|
||||||
const TIMER_MODULO_ADDRESS: u16 = 0xFF05;
|
use crate::utils::{
|
||||||
const TIMER_CONTROL_ADDRESS: u16 = 0xFF05;
|
BitIndex,
|
||||||
|
get_bit,
|
||||||
|
};
|
||||||
|
|
||||||
struct Timer;
|
pub const TIMER_DIVIDER_REGISTER_ADDRESS: u16 = 0xFF04;
|
||||||
|
pub const TIMER_COUNTER_ADDRESS: u16 = 0xFF05;
|
||||||
|
pub const TIMER_MODULO_ADDRESS: u16 = 0xFF06;
|
||||||
|
pub const TIMER_CONTROL_ADDRESS: u16 = 0xFF07;
|
||||||
|
|
||||||
|
pub struct Timer;
|
||||||
|
|
||||||
impl Timer {
|
impl Timer {
|
||||||
pub fn cycle() {
|
|
||||||
|
pub fn do_cycles(bus: &mut Bus, cycles: Cycles) {
|
||||||
|
let mut count = 0;
|
||||||
|
while count < cycles.to_t() {
|
||||||
|
Timer::cycle(bus);
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cycle(bus: &mut Bus) {
|
||||||
|
let div = bus.read(TIMER_DIVIDER_REGISTER_ADDRESS);
|
||||||
|
bus.write(TIMER_DIVIDER_REGISTER_ADDRESS, div.wrapping_add(1));
|
||||||
|
|
||||||
|
if Timer::is_timer_enabled(bus) {
|
||||||
|
let tima = bus.read(TIMER_COUNTER_ADDRESS);
|
||||||
|
let tima_increment = Timer::get_tima_increment(bus);
|
||||||
|
if tima.checked_add(tima_increment) == None {
|
||||||
|
bus.write(TIMER_COUNTER_ADDRESS, bus.read(TIMER_MODULO_ADDRESS));
|
||||||
|
bus.set_interrupt(Interrupt::Timer, true);
|
||||||
|
} else {
|
||||||
|
bus.write(TIMER_COUNTER_ADDRESS, tima.wrapping_add(tima_increment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_timer_enabled(bus: &Bus) -> bool {
|
||||||
|
get_bit(bus.read(TIMER_CONTROL_ADDRESS), BitIndex::I2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_tima_increment(bus: &Bus) -> u8 {
|
||||||
|
let clock_select = bus.read(TIMER_CONTROL_ADDRESS) & 0b0000_0011;
|
||||||
|
match clock_select {
|
||||||
|
0b00 => (4096 as u16 / 1026 as u16 / 4 as u16).to_be_bytes()[1],
|
||||||
|
0b01 => (4096 as u16 / 16 as u16 / 4 as u16).to_be_bytes()[1],
|
||||||
|
0b10 => (4096 as u16 / 64 as u16 / 4 as u16).to_be_bytes()[1],
|
||||||
|
0b11 => (4096 as u16 / 256 as u16 / 4 as u16).to_be_bytes()[1],
|
||||||
|
_ => 1,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user