2019-07-06 23:33:54 +01:00
|
|
|
/// Struct containing everything
|
|
|
|
///
|
2019-08-02 22:18:59 +01:00
|
|
|
use std::cell::RefCell;
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
2019-08-05 07:44:27 +01:00
|
|
|
use super::arm7tdmi::{exception::Exception, Core, DecodedInstruction};
|
2019-07-06 13:53:36 +01:00
|
|
|
use super::cartridge::Cartridge;
|
2019-07-20 12:44:49 +01:00
|
|
|
use super::gpu::*;
|
2019-07-15 05:35:09 +01:00
|
|
|
use super::interrupt::*;
|
2019-08-02 22:18:59 +01:00
|
|
|
use super::ioregs::IoRegs;
|
2019-07-06 13:53:36 +01:00
|
|
|
use super::sysbus::SysBus;
|
2019-08-05 07:44:27 +01:00
|
|
|
use super::timer::Timers;
|
2019-08-02 22:18:59 +01:00
|
|
|
use super::GBAResult;
|
2019-08-05 07:44:27 +01:00
|
|
|
use super::SyncedIoDevice;
|
2019-07-20 21:02:18 +01:00
|
|
|
use crate::backend::*;
|
2019-07-06 13:53:36 +01:00
|
|
|
|
2019-08-02 22:18:59 +01:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct IoDevices {
|
|
|
|
pub intc: InterruptController,
|
|
|
|
pub gpu: Gpu,
|
2019-08-05 07:44:27 +01:00
|
|
|
pub timers: Timers,
|
2019-08-02 22:18:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl IoDevices {
|
|
|
|
pub fn new() -> IoDevices {
|
|
|
|
IoDevices {
|
|
|
|
intc: InterruptController::new(),
|
|
|
|
gpu: Gpu::new(),
|
2019-08-05 07:44:27 +01:00
|
|
|
timers: Timers::new(),
|
2019-08-02 22:18:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-07-28 23:28:22 +01:00
|
|
|
|
2019-07-06 13:53:36 +01:00
|
|
|
pub struct GameBoyAdvance {
|
2019-07-20 21:02:18 +01:00
|
|
|
backend: Box<EmulatorBackend>,
|
2019-07-06 13:53:36 +01:00
|
|
|
pub cpu: Core,
|
|
|
|
pub sysbus: SysBus,
|
|
|
|
|
2019-08-02 22:18:59 +01:00
|
|
|
pub io: Rc<RefCell<IoDevices>>,
|
2019-07-06 13:53:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl GameBoyAdvance {
|
2019-07-20 21:02:18 +01:00
|
|
|
pub fn new(
|
|
|
|
cpu: Core,
|
|
|
|
bios_rom: Vec<u8>,
|
|
|
|
gamepak: Cartridge,
|
|
|
|
backend: Box<EmulatorBackend>,
|
|
|
|
) -> GameBoyAdvance {
|
2019-08-02 22:18:59 +01:00
|
|
|
let io = Rc::new(RefCell::new(IoDevices::new()));
|
|
|
|
|
|
|
|
let ioregs = IoRegs::new(io.clone());
|
2019-08-05 07:44:27 +01:00
|
|
|
let sysbus = SysBus::new(io.clone(), bios_rom, gamepak, ioregs);
|
2019-07-06 13:53:36 +01:00
|
|
|
|
|
|
|
GameBoyAdvance {
|
2019-07-20 21:02:18 +01:00
|
|
|
backend: backend,
|
2019-07-06 13:53:36 +01:00
|
|
|
cpu: cpu,
|
|
|
|
sysbus: sysbus,
|
|
|
|
|
2019-08-02 22:18:59 +01:00
|
|
|
io: io.clone(),
|
2019-07-06 13:53:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-11 16:17:28 +01:00
|
|
|
pub fn frame(&mut self) {
|
2019-07-20 21:02:18 +01:00
|
|
|
self.update_key_state();
|
2019-08-02 22:18:59 +01:00
|
|
|
while self.io.borrow().gpu.state != GpuState::VBlank {
|
|
|
|
let cycles = self.emulate_cpu();
|
|
|
|
self.emulate_peripherals(cycles);
|
2019-07-15 05:35:09 +01:00
|
|
|
}
|
2019-08-02 22:18:59 +01:00
|
|
|
self.backend.render(self.io.borrow().gpu.render());
|
|
|
|
while self.io.borrow().gpu.state == GpuState::VBlank {
|
|
|
|
let cycles = self.emulate_cpu();
|
|
|
|
self.emulate_peripherals(cycles);
|
2019-07-30 22:52:46 +01:00
|
|
|
}
|
2019-07-20 21:02:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fn update_key_state(&mut self) {
|
2019-08-02 22:18:59 +01:00
|
|
|
self.sysbus.ioregs.keyinput = self.backend.get_key_state();
|
2019-07-15 05:35:09 +01:00
|
|
|
}
|
|
|
|
|
2019-08-02 22:18:59 +01:00
|
|
|
pub fn emulate_cpu(&mut self) -> usize {
|
2019-07-15 05:35:09 +01:00
|
|
|
let previous_cycles = self.cpu.cycles;
|
|
|
|
self.cpu.step(&mut self.sysbus).unwrap();
|
2019-08-02 22:18:59 +01:00
|
|
|
self.cpu.cycles - previous_cycles
|
2019-07-15 05:35:09 +01:00
|
|
|
}
|
|
|
|
|
2019-08-02 22:18:59 +01:00
|
|
|
pub fn emulate_peripherals(&mut self, cycles: usize) {
|
2019-08-05 07:44:27 +01:00
|
|
|
let mut irqs = IrqBitmask(0);
|
2019-08-02 22:18:59 +01:00
|
|
|
let mut io = self.io.borrow_mut();
|
2019-08-05 07:44:27 +01:00
|
|
|
|
|
|
|
io.timers.step(cycles, &mut self.sysbus, &mut irqs);
|
|
|
|
io.gpu.step(cycles, &mut self.sysbus, &mut irqs);
|
|
|
|
|
|
|
|
if !self.cpu.cpsr.irq_disabled() {
|
|
|
|
io.intc.request_irqs(irqs);
|
|
|
|
if io.intc.irq_pending() {
|
|
|
|
self.cpu.exception(Exception::Irq);
|
|
|
|
}
|
2019-07-28 23:28:22 +01:00
|
|
|
}
|
2019-07-11 16:17:28 +01:00
|
|
|
}
|
|
|
|
|
2019-07-06 13:53:36 +01:00
|
|
|
pub fn step(&mut self) -> GBAResult<DecodedInstruction> {
|
|
|
|
let previous_cycles = self.cpu.cycles;
|
2019-07-11 16:17:28 +01:00
|
|
|
let executed_insn = self.cpu.step_one(&mut self.sysbus)?;
|
2019-08-02 22:18:59 +01:00
|
|
|
let cycles = self.cpu.cycles - previous_cycles;
|
2019-07-11 16:17:28 +01:00
|
|
|
|
2019-08-02 22:18:59 +01:00
|
|
|
self.emulate_peripherals(cycles);
|
2019-07-06 13:53:36 +01:00
|
|
|
|
2019-08-02 22:18:59 +01:00
|
|
|
if self.io.borrow().gpu.state == GpuState::HBlank {
|
|
|
|
self.backend.render(self.io.borrow().gpu.render());
|
2019-07-28 23:28:22 +01:00
|
|
|
}
|
2019-07-06 13:53:36 +01:00
|
|
|
|
2019-07-11 16:17:28 +01:00
|
|
|
Ok(executed_insn)
|
2019-07-06 13:53:36 +01:00
|
|
|
}
|
|
|
|
}
|