From 554edd62b08e8b568f40e39a620214009bc176c8 Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Sun, 27 Sep 2020 15:44:17 +0300 Subject: [PATCH] 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 --- core/src/dma.rs | 10 +++++++++- core/src/gba.rs | 21 +++++++++++++++++++-- core/src/gpu/mod.rs | 8 +++++++- core/src/interrupt.rs | 12 ++++++++++++ core/src/iodev.rs | 11 ++++++++++- core/src/timer.rs | 10 +++++++++- 6 files changed, 66 insertions(+), 6 deletions(-) diff --git a/core/src/dma.rs b/core/src/dma.rs index 43aedd5..2e29ac4 100644 --- a/core/src/dma.rs +++ b/core/src/dma.rs @@ -1,5 +1,5 @@ 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::sysbus::SysBus; use super::Bus; @@ -196,6 +196,14 @@ pub struct DmaController { 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 { pub fn new(interrupt_flags: SharedInterruptFlags) -> DmaController { DmaController { diff --git a/core/src/gba.rs b/core/src/gba.rs index 7201838..ece9b80 100644 --- a/core/src/gba.rs +++ b/core/src/gba.rs @@ -28,11 +28,13 @@ pub struct GameBoyAdvance { pub cycles_to_next_event: usize, overshoot_cycles: usize, + interrupt_flags: SharedInterruptFlags, } #[derive(Serialize, Deserialize)] struct SaveState { sysbus: Box, + interrupt_flags: u16, cpu: arm7tdmi::Core, } @@ -87,6 +89,7 @@ impl GameBoyAdvance { cycles_to_next_event: 1, overshoot_cycles: 0, + interrupt_flags: interrupt_flags, }; gba.sysbus.created(); @@ -102,9 +105,17 @@ impl GameBoyAdvance { ) -> bincode::Result { let decoded: Box = 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 { - cpu: decoded.cpu, - sysbus: decoded.sysbus, + cpu: arm7tdmi, + sysbus: sysbus, + + interrupt_flags: interrupts, video_device: video_device, audio_device: audio_device, @@ -120,6 +131,7 @@ impl GameBoyAdvance { let s = SaveState { cpu: self.cpu.clone(), sysbus: self.sysbus.clone(), + interrupt_flags: self.interrupt_flags.get().value(), }; bincode::serialize(&s) @@ -130,6 +142,11 @@ impl GameBoyAdvance { self.cpu = decoded.cpu; 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.sysbus.created(); diff --git a/core/src/gpu/mod.rs b/core/src/gpu/mod.rs index 97fed96..f2e07ae 100644 --- a/core/src/gpu/mod.rs +++ b/core/src/gpu/mod.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use super::bus::*; 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::*; use super::util::BoxedMemory; use super::VideoInterface; @@ -213,6 +213,12 @@ pub struct Gpu { pub(super) frame_buffer: Vec, } +impl InterruptConnect for Gpu { + fn connect_irq(&mut self, interrupt_flags: SharedInterruptFlags) { + self.interrupt_flags = interrupt_flags; + } +} + impl Gpu { pub fn new(interrupt_flags: SharedInterruptFlags) -> Gpu { Gpu { diff --git a/core/src/interrupt.rs b/core/src/interrupt.rs index 8ccbb90..45dcb55 100644 --- a/core/src/interrupt.rs +++ b/core/src/interrupt.rs @@ -3,6 +3,12 @@ use std::rc::Rc; 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)] #[allow(non_camel_case_types)] 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] pub fn signal_irq(interrupt_flags: &SharedInterruptFlags, i: Interrupt) { let _if = interrupt_flags.get(); diff --git a/core/src/iodev.rs b/core/src/iodev.rs index 7eba8d7..7d555a4 100644 --- a/core/src/iodev.rs +++ b/core/src/iodev.rs @@ -4,7 +4,7 @@ use super::bus::*; use super::dma::DmaController; use super::gpu::regs::WindowFlags; use super::gpu::*; -use super::interrupt::InterruptController; +use super::interrupt::{InterruptConnect, InterruptController, SharedInterruptFlags}; use super::keypad; use super::sound::SoundController; 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 { fn read_16(&self, addr: Addr) -> u16 { let io = self; diff --git a/core/src/timer.rs b/core/src/timer.rs index 2c980a7..df5eeb0 100644 --- a/core/src/timer.rs +++ b/core/src/timer.rs @@ -1,4 +1,4 @@ -use super::interrupt::{self, Interrupt, SharedInterruptFlags}; +use super::interrupt::{self, Interrupt, InterruptConnect, SharedInterruptFlags}; use super::iodev::consts::*; use super::sysbus::SysBus; @@ -78,6 +78,14 @@ pub struct Timers { 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 for Timers { type Output = Timer; fn index(&self, index: usize) -> &Self::Output {