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::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 {

View file

@ -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<SysBus>,
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<GameBoyAdvance> {
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 {
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();

View file

@ -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<u32>,
}
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 {

View file

@ -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();

View file

@ -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;

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::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<usize> for Timers {
type Output = Timer;
fn index(&self, index: usize) -> &Self::Output {