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:
parent
4050dcdf2f
commit
554edd62b0
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Reference in a new issue