core: Properly set SharedInterruptFlags pointer for all interrupt generating devices when restoring state.

Serde doesn't like Rc that much :(

Fixes #142


Former-commit-id: e1e8a96b4867e351d103fb7d92d71b0434e8fc31
Former-commit-id: 28366bbb36b3e93b574f397b103a483844fd8131
This commit is contained in:
Michel Heily 2020-09-27 15:44:17 +03:00
parent 4050dcdf2f
commit 554edd62b0
6 changed files with 66 additions and 6 deletions

View file

@ -1,5 +1,5 @@
use super::cartridge::BackupMedia; use super::cartridge::BackupMedia;
use super::interrupt::{self, Interrupt, SharedInterruptFlags}; use super::interrupt::{self, Interrupt, InterruptConnect, SharedInterruptFlags};
use super::iodev::consts::{REG_FIFO_A, REG_FIFO_B}; use super::iodev::consts::{REG_FIFO_A, REG_FIFO_B};
use super::sysbus::SysBus; use super::sysbus::SysBus;
use super::Bus; use super::Bus;
@ -196,6 +196,14 @@ pub struct DmaController {
cycles: usize, cycles: usize,
} }
impl InterruptConnect for DmaController {
fn connect_irq(&mut self, interrupt_flags: SharedInterruptFlags) {
for channel in &mut self.channels {
channel.interrupt_flags = interrupt_flags.clone();
}
}
}
impl DmaController { impl DmaController {
pub fn new(interrupt_flags: SharedInterruptFlags) -> DmaController { pub fn new(interrupt_flags: SharedInterruptFlags) -> DmaController {
DmaController { DmaController {

View file

@ -28,11 +28,13 @@ pub struct GameBoyAdvance {
pub cycles_to_next_event: usize, pub cycles_to_next_event: usize,
overshoot_cycles: usize, overshoot_cycles: usize,
interrupt_flags: SharedInterruptFlags,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
struct SaveState { struct SaveState {
sysbus: Box<SysBus>, sysbus: Box<SysBus>,
interrupt_flags: u16,
cpu: arm7tdmi::Core, cpu: arm7tdmi::Core,
} }
@ -87,6 +89,7 @@ impl GameBoyAdvance {
cycles_to_next_event: 1, cycles_to_next_event: 1,
overshoot_cycles: 0, overshoot_cycles: 0,
interrupt_flags: interrupt_flags,
}; };
gba.sysbus.created(); gba.sysbus.created();
@ -102,9 +105,17 @@ impl GameBoyAdvance {
) -> bincode::Result<GameBoyAdvance> { ) -> bincode::Result<GameBoyAdvance> {
let decoded: Box<SaveState> = bincode::deserialize_from(savestate)?; let decoded: Box<SaveState> = bincode::deserialize_from(savestate)?;
let arm7tdmi = decoded.cpu;
let mut sysbus = decoded.sysbus;
let interrupts = Rc::new(Cell::new(IrqBitmask(decoded.interrupt_flags)));
sysbus.io.connect_irq(interrupts.clone());
Ok(GameBoyAdvance { Ok(GameBoyAdvance {
cpu: decoded.cpu, cpu: arm7tdmi,
sysbus: decoded.sysbus, sysbus: sysbus,
interrupt_flags: interrupts,
video_device: video_device, video_device: video_device,
audio_device: audio_device, audio_device: audio_device,
@ -120,6 +131,7 @@ impl GameBoyAdvance {
let s = SaveState { let s = SaveState {
cpu: self.cpu.clone(), cpu: self.cpu.clone(),
sysbus: self.sysbus.clone(), sysbus: self.sysbus.clone(),
interrupt_flags: self.interrupt_flags.get().value(),
}; };
bincode::serialize(&s) bincode::serialize(&s)
@ -130,6 +142,11 @@ impl GameBoyAdvance {
self.cpu = decoded.cpu; self.cpu = decoded.cpu;
self.sysbus = decoded.sysbus; self.sysbus = decoded.sysbus;
self.interrupt_flags = Rc::new(Cell::new(IrqBitmask(decoded.interrupt_flags)));
// Redistribute shared pointer for interrupts
self.sysbus.io.connect_irq(self.interrupt_flags.clone());
self.cycles_to_next_event = 1; self.cycles_to_next_event = 1;
self.sysbus.created(); self.sysbus.created();

View file

@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
use super::bus::*; use super::bus::*;
use super::dma::{DmaNotifer, TIMING_HBLANK, TIMING_VBLANK}; use super::dma::{DmaNotifer, TIMING_HBLANK, TIMING_VBLANK};
use super::interrupt::{self, Interrupt, SharedInterruptFlags}; use super::interrupt::{self, Interrupt, InterruptConnect, SharedInterruptFlags};
pub use super::sysbus::consts::*; pub use super::sysbus::consts::*;
use super::util::BoxedMemory; use super::util::BoxedMemory;
use super::VideoInterface; use super::VideoInterface;
@ -213,6 +213,12 @@ pub struct Gpu {
pub(super) frame_buffer: Vec<u32>, pub(super) frame_buffer: Vec<u32>,
} }
impl InterruptConnect for Gpu {
fn connect_irq(&mut self, interrupt_flags: SharedInterruptFlags) {
self.interrupt_flags = interrupt_flags;
}
}
impl Gpu { impl Gpu {
pub fn new(interrupt_flags: SharedInterruptFlags) -> Gpu { pub fn new(interrupt_flags: SharedInterruptFlags) -> Gpu {
Gpu { Gpu {

View file

@ -3,6 +3,12 @@ use std::rc::Rc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub trait InterruptConnect {
// Connect a SharedInterruptFlags to this interrupt source
fn connect_irq(&mut self, interrupt_flags: SharedInterruptFlags);
}
#[derive(Serialize, Deserialize, Debug, Primitive, Copy, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Primitive, Copy, Clone, PartialEq)]
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
pub enum Interrupt { pub enum Interrupt {
@ -52,6 +58,12 @@ impl InterruptController {
} }
} }
impl InterruptConnect for InterruptController {
fn connect_irq(&mut self, interrupt_flags: SharedInterruptFlags) {
self.interrupt_flags = interrupt_flags;
}
}
#[inline] #[inline]
pub fn signal_irq(interrupt_flags: &SharedInterruptFlags, i: Interrupt) { pub fn signal_irq(interrupt_flags: &SharedInterruptFlags, i: Interrupt) {
let _if = interrupt_flags.get(); let _if = interrupt_flags.get();

View file

@ -4,7 +4,7 @@ use super::bus::*;
use super::dma::DmaController; use super::dma::DmaController;
use super::gpu::regs::WindowFlags; use super::gpu::regs::WindowFlags;
use super::gpu::*; use super::gpu::*;
use super::interrupt::InterruptController; use super::interrupt::{InterruptConnect, InterruptController, SharedInterruptFlags};
use super::keypad; use super::keypad;
use super::sound::SoundController; use super::sound::SoundController;
use super::sysbus::SysBusPtr; use super::sysbus::SysBusPtr;
@ -68,6 +68,15 @@ impl IoDevices {
} }
} }
impl InterruptConnect for IoDevices {
fn connect_irq(&mut self, interrupt_flags: SharedInterruptFlags) {
self.intc.connect_irq(interrupt_flags.clone());
self.gpu.connect_irq(interrupt_flags.clone());
self.dmac.connect_irq(interrupt_flags.clone());
self.timers.connect_irq(interrupt_flags.clone());
}
}
impl Bus for IoDevices { impl Bus for IoDevices {
fn read_16(&self, addr: Addr) -> u16 { fn read_16(&self, addr: Addr) -> u16 {
let io = self; let io = self;

View file

@ -1,4 +1,4 @@
use super::interrupt::{self, Interrupt, SharedInterruptFlags}; use super::interrupt::{self, Interrupt, InterruptConnect, SharedInterruptFlags};
use super::iodev::consts::*; use super::iodev::consts::*;
use super::sysbus::SysBus; use super::sysbus::SysBus;
@ -78,6 +78,14 @@ pub struct Timers {
pub trace: bool, pub trace: bool,
} }
impl InterruptConnect for Timers {
fn connect_irq(&mut self, interrupt_flags: SharedInterruptFlags) {
for timer in &mut self.timers {
timer.interrupt_flags = interrupt_flags.clone();
}
}
}
impl std::ops::Index<usize> for Timers { impl std::ops::Index<usize> for Timers {
type Output = Timer; type Output = Timer;
fn index(&self, index: usize) -> &Self::Output { fn index(&self, index: usize) -> &Self::Output {