oam dma lockout
This commit is contained in:
parent
828da3e01f
commit
e805f32380
|
@ -5,13 +5,12 @@ use self::{
|
||||||
apu::ApuSaveState,
|
apu::ApuSaveState,
|
||||||
gpu::{Colour, GpuSaveState},
|
gpu::{Colour, GpuSaveState},
|
||||||
serial::SerialSaveState,
|
serial::SerialSaveState,
|
||||||
Apu, Gpu, Joypad, Serial, Timer,
|
Apu, Gpu, Joypad, OamDma, Serial, Timer,
|
||||||
},
|
},
|
||||||
rom::RomSaveState,
|
rom::RomSaveState,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
connect::{AudioOutput, CameraWrapperRef, JoypadState, PocketCamera, Renderer, SerialTarget},
|
connect::{AudioOutput, CameraWrapperRef, JoypadState, PocketCamera, Renderer, SerialTarget},
|
||||||
processor::SplitRegister,
|
|
||||||
Cpu,
|
Cpu,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,7 +34,8 @@ where
|
||||||
pub(super) interrupts: Interrupts,
|
pub(super) interrupts: Interrupts,
|
||||||
pub(super) ime: bool,
|
pub(super) ime: bool,
|
||||||
pub(super) ime_scheduled: u8,
|
pub(super) ime_scheduled: u8,
|
||||||
dma_addr: u8,
|
pub(super) user_mode: bool,
|
||||||
|
dma: OamDma,
|
||||||
joypad: Joypad,
|
joypad: Joypad,
|
||||||
gpu: Gpu<ColourFormat, R>,
|
gpu: Gpu<ColourFormat, R>,
|
||||||
apu: Apu,
|
apu: Apu,
|
||||||
|
@ -59,7 +59,8 @@ where
|
||||||
pub(super) interrupts: Interrupts,
|
pub(super) interrupts: Interrupts,
|
||||||
pub(super) ime: bool,
|
pub(super) ime: bool,
|
||||||
pub(super) ime_scheduled: u8,
|
pub(super) ime_scheduled: u8,
|
||||||
dma_addr: u8,
|
pub(super) user_mode: bool,
|
||||||
|
dma: OamDma,
|
||||||
joypad: Joypad,
|
joypad: Joypad,
|
||||||
gpu: GpuSaveState<ColourFormat, R>,
|
gpu: GpuSaveState<ColourFormat, R>,
|
||||||
apu: ApuSaveState,
|
apu: ApuSaveState,
|
||||||
|
@ -81,7 +82,8 @@ where
|
||||||
interrupts: memory.interrupts,
|
interrupts: memory.interrupts,
|
||||||
ime: memory.ime,
|
ime: memory.ime,
|
||||||
ime_scheduled: memory.ime_scheduled,
|
ime_scheduled: memory.ime_scheduled,
|
||||||
dma_addr: memory.dma_addr,
|
user_mode: memory.user_mode,
|
||||||
|
dma: memory.dma,
|
||||||
joypad: memory.joypad,
|
joypad: memory.joypad,
|
||||||
gpu: GpuSaveState::create(&memory.gpu),
|
gpu: GpuSaveState::create(&memory.gpu),
|
||||||
apu: ApuSaveState::create(&memory.apu),
|
apu: ApuSaveState::create(&memory.apu),
|
||||||
|
@ -114,7 +116,8 @@ where
|
||||||
interrupts: Interrupts::default(),
|
interrupts: Interrupts::default(),
|
||||||
ime: false,
|
ime: false,
|
||||||
ime_scheduled: 0x0,
|
ime_scheduled: 0x0,
|
||||||
dma_addr: 0xFF,
|
user_mode: false,
|
||||||
|
dma: OamDma::default(),
|
||||||
joypad: Joypad::default(),
|
joypad: Joypad::default(),
|
||||||
gpu: Gpu::new(window, tile_window),
|
gpu: Gpu::new(window, tile_window),
|
||||||
apu: Apu::new(output),
|
apu: Apu::new(output),
|
||||||
|
@ -129,6 +132,17 @@ where
|
||||||
T: Into<Address>,
|
T: Into<Address>,
|
||||||
{
|
{
|
||||||
let address: Address = address.into();
|
let address: Address = address.into();
|
||||||
|
if self.dma.is_active() && self.user_mode {
|
||||||
|
if let Address::Hram(_) = address {
|
||||||
|
} else if let Address::Io(IoAddress::Video(v)) = address {
|
||||||
|
if v.inner() == 0xFF46 {
|
||||||
|
} else {
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
match address {
|
match address {
|
||||||
Address::Rom(address) => {
|
Address::Rom(address) => {
|
||||||
// rom access
|
// rom access
|
||||||
|
@ -139,12 +153,12 @@ where
|
||||||
self.rom.get(address)
|
self.rom.get(address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Address::Vram(address) => self.gpu.vram.get(address),
|
Address::Vram(address) => self.gpu.get_vram(address),
|
||||||
Address::CartRam(address) => self.rom.get_ram(address),
|
Address::CartRam(address) => self.rom.get_ram(address),
|
||||||
Address::WorkRam(address) => self.ram[address.get_local() as usize],
|
Address::WorkRam(address) => self.ram[address.get_local() as usize],
|
||||||
Address::BankedWorkRam(address) => self.ram[(address.get_local() + 0x1000) as usize],
|
Address::BankedWorkRam(address) => self.ram[(address.get_local() + 0x1000) as usize],
|
||||||
Address::MirroredRam(address) => self.ram[address.get_local() as usize],
|
Address::MirroredRam(address) => self.ram[address.get_local() as usize],
|
||||||
Address::Oam(address) => self.gpu.oam.get(address),
|
Address::Oam(address) => self.gpu.get_oam(address),
|
||||||
Address::Prohibited(_) => 0xFF,
|
Address::Prohibited(_) => 0xFF,
|
||||||
Address::Io(address) => self.get_io(address),
|
Address::Io(address) => self.get_io(address),
|
||||||
Address::Hram(address) => self.cpu_ram[address.get_local() as usize],
|
Address::Hram(address) => self.cpu_ram[address.get_local() as usize],
|
||||||
|
@ -157,6 +171,17 @@ where
|
||||||
T: Into<Address>,
|
T: Into<Address>,
|
||||||
{
|
{
|
||||||
let address: Address = address.into();
|
let address: Address = address.into();
|
||||||
|
if self.dma.is_active() && self.user_mode {
|
||||||
|
if let Address::Hram(_) = address {
|
||||||
|
} else if let Address::Io(IoAddress::Video(v)) = address {
|
||||||
|
if v.inner() == 0xFF46 {
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
match address {
|
match address {
|
||||||
Address::Rom(address) => {
|
Address::Rom(address) => {
|
||||||
self.rom.set(address, data);
|
self.rom.set(address, data);
|
||||||
|
@ -165,14 +190,14 @@ where
|
||||||
self.gpu.window.set_rumble(self.rom.is_rumbling())
|
self.gpu.window.set_rumble(self.rom.is_rumbling())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Address::Vram(address) => self.gpu.vram.set(address, data),
|
Address::Vram(address) => self.gpu.set_vram(address, data),
|
||||||
Address::CartRam(address) => self.rom.set_ram(address, data),
|
Address::CartRam(address) => self.rom.set_ram(address, data),
|
||||||
Address::WorkRam(address) => self.ram[address.get_local() as usize] = data,
|
Address::WorkRam(address) => self.ram[address.get_local() as usize] = data,
|
||||||
Address::BankedWorkRam(address) => {
|
Address::BankedWorkRam(address) => {
|
||||||
self.ram[(address.get_local() + 0x1000) as usize] = data
|
self.ram[(address.get_local() + 0x1000) as usize] = data
|
||||||
}
|
}
|
||||||
Address::MirroredRam(address) => self.ram[address.get_local() as usize] = data,
|
Address::MirroredRam(address) => self.ram[address.get_local() as usize] = data,
|
||||||
Address::Oam(address) => self.gpu.oam.set(address, data),
|
Address::Oam(address) => self.gpu.set_oam(address, data),
|
||||||
Address::Prohibited(_) => {}
|
Address::Prohibited(_) => {}
|
||||||
Address::Io(address) => {
|
Address::Io(address) => {
|
||||||
if address.inner() == 0xFF50 {
|
if address.inner() == 0xFF50 {
|
||||||
|
@ -210,13 +235,13 @@ where
|
||||||
0xFF43 => self.gpu.get_scx(),
|
0xFF43 => self.gpu.get_scx(),
|
||||||
0xFF44 => self.gpu.get_ly(),
|
0xFF44 => self.gpu.get_ly(),
|
||||||
0xFF45 => self.gpu.get_lyc(),
|
0xFF45 => self.gpu.get_lyc(),
|
||||||
0xFF46 => self.dma_addr,
|
0xFF46 => self.dma.get_register(),
|
||||||
0xFF47 => self.gpu.get_bg_palette(),
|
0xFF47 => self.gpu.get_bg_palette(),
|
||||||
0xFF48 => self.gpu.get_obj_palette_0(),
|
0xFF48 => self.gpu.get_obj_palette_0(),
|
||||||
0xFF49 => self.gpu.get_obj_palette_1(),
|
0xFF49 => self.gpu.get_obj_palette_1(),
|
||||||
0xFF4A => self.gpu.get_wy(),
|
0xFF4A => self.gpu.get_wy(),
|
||||||
0xFF4B => self.gpu.get_wx(),
|
0xFF4B => self.gpu.get_wx(),
|
||||||
_ => unreachable!(),
|
0x0..0xFF40 | 0xFF4C..=0xFFFF => unreachable!(),
|
||||||
},
|
},
|
||||||
IoAddress::Unused(_) => 0xFF,
|
IoAddress::Unused(_) => 0xFF,
|
||||||
}
|
}
|
||||||
|
@ -245,25 +270,17 @@ where
|
||||||
0xFF41 => self.gpu.update_lcd_status(data),
|
0xFF41 => self.gpu.update_lcd_status(data),
|
||||||
0xFF42 => self.gpu.update_scy(data),
|
0xFF42 => self.gpu.update_scy(data),
|
||||||
0xFF43 => self.gpu.update_scx(data),
|
0xFF43 => self.gpu.update_scx(data),
|
||||||
|
0xFF44 => {}
|
||||||
0xFF45 => self.gpu.update_lyc(data),
|
0xFF45 => self.gpu.update_lyc(data),
|
||||||
0xFF46 => {
|
0xFF46 => {
|
||||||
if data > 0xDF {
|
self.dma.set_register(data);
|
||||||
panic!("dma transfer out of bounds: {data:#X}");
|
|
||||||
}
|
|
||||||
self.dma_addr = data;
|
|
||||||
let mut addr: u16 = 0x0;
|
|
||||||
addr.set_high(data);
|
|
||||||
for l in 0x0..0xA0 {
|
|
||||||
addr.set_low(l);
|
|
||||||
self.gpu.oam.data[l as usize] = self.get(addr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
0xFF47 => self.gpu.update_bg_palette(data),
|
0xFF47 => self.gpu.update_bg_palette(data),
|
||||||
0xFF48 => self.gpu.update_obj_palette_0(data),
|
0xFF48 => self.gpu.update_obj_palette_0(data),
|
||||||
0xFF49 => self.gpu.update_obj_palette_1(data),
|
0xFF49 => self.gpu.update_obj_palette_1(data),
|
||||||
0xFF4A => self.gpu.update_wy(data),
|
0xFF4A => self.gpu.update_wy(data),
|
||||||
0xFF4B => self.gpu.update_wx(data),
|
0xFF4B => self.gpu.update_wx(data),
|
||||||
_ => unreachable!(),
|
0x0..0xFF40 | 0xFF4C..=0xFFFF => unreachable!(),
|
||||||
},
|
},
|
||||||
IoAddress::Unused(_) => {}
|
IoAddress::Unused(_) => {}
|
||||||
}
|
}
|
||||||
|
@ -327,7 +344,8 @@ where
|
||||||
interrupts: state.interrupts,
|
interrupts: state.interrupts,
|
||||||
ime: state.ime,
|
ime: state.ime,
|
||||||
ime_scheduled: state.ime_scheduled,
|
ime_scheduled: state.ime_scheduled,
|
||||||
dma_addr: state.dma_addr,
|
user_mode: state.user_mode,
|
||||||
|
dma: state.dma,
|
||||||
joypad: state.joypad,
|
joypad: state.joypad,
|
||||||
gpu: Gpu::from_save_state(state.gpu, window, None),
|
gpu: Gpu::from_save_state(state.gpu, window, None),
|
||||||
apu: Apu::from_save_state(state.apu, output),
|
apu: Apu::from_save_state(state.apu, output),
|
||||||
|
@ -347,6 +365,8 @@ where
|
||||||
pub fn increment_timers(&mut self, machine_cycles: u8) {
|
pub fn increment_timers(&mut self, machine_cycles: u8) {
|
||||||
let steps = (machine_cycles as usize) * 4;
|
let steps = (machine_cycles as usize) * 4;
|
||||||
|
|
||||||
|
self.memory.oam_tick(steps);
|
||||||
|
|
||||||
self.memory.camera.lock().unwrap().tick(steps);
|
self.memory.camera.lock().unwrap().tick(steps);
|
||||||
|
|
||||||
let timer_return = self.memory.timers.tick(steps);
|
let timer_return = self.memory.timers.tick(steps);
|
||||||
|
|
|
@ -5,7 +5,7 @@ pub(crate) enum AddressError {
|
||||||
OutOfBounds,
|
OutOfBounds,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub(crate) struct BoundedAddress<const MIN: u16, const MAX: u16>(u16);
|
pub(crate) struct BoundedAddress<const MIN: u16, const MAX: u16>(u16);
|
||||||
|
|
||||||
impl<const MIN: u16, const MAX: u16> Add<u16> for BoundedAddress<MIN, MAX> {
|
impl<const MIN: u16, const MAX: u16> Add<u16> for BoundedAddress<MIN, MAX> {
|
||||||
|
|
|
@ -255,7 +255,7 @@ impl Apu {
|
||||||
0xFF13 | 0xFF18 | 0xFF1B | 0xFF1D | 0xFF20 => 0xFF,
|
0xFF13 | 0xFF18 | 0xFF1B | 0xFF1D | 0xFF20 => 0xFF,
|
||||||
// not registers
|
// not registers
|
||||||
0xFF15 | 0xFF1F => 0xFF,
|
0xFF15 | 0xFF1F => 0xFF,
|
||||||
_ => unreachable!(),
|
0x0..0xFF10 | 0xFF27..=0xFFFF => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,6 +266,7 @@ impl Apu {
|
||||||
0xFF12 => self.channels.one.update_volume_and_envelope(data),
|
0xFF12 => self.channels.one.update_volume_and_envelope(data),
|
||||||
0xFF13 => self.channels.one.update_wavelength_low(data),
|
0xFF13 => self.channels.one.update_wavelength_low(data),
|
||||||
0xFF14 => self.channels.one.update_wavelength_high_and_control(data),
|
0xFF14 => self.channels.one.update_wavelength_high_and_control(data),
|
||||||
|
0xFF15 => {}
|
||||||
0xFF16 => self.channels.two.update_length_timer_and_duty_cycle(data),
|
0xFF16 => self.channels.two.update_length_timer_and_duty_cycle(data),
|
||||||
0xFF17 => self.channels.two.update_volume_and_envelope(data),
|
0xFF17 => self.channels.two.update_volume_and_envelope(data),
|
||||||
0xFF18 => self.channels.two.update_wavelength_low(data),
|
0xFF18 => self.channels.two.update_wavelength_low(data),
|
||||||
|
@ -275,6 +276,7 @@ impl Apu {
|
||||||
0xFF1C => self.channels.three.update_volume(data),
|
0xFF1C => self.channels.three.update_volume(data),
|
||||||
0xFF1D => self.channels.three.update_wavelength_low(data),
|
0xFF1D => self.channels.three.update_wavelength_low(data),
|
||||||
0xFF1E => self.channels.three.update_wavelength_high_and_control(data),
|
0xFF1E => self.channels.three.update_wavelength_high_and_control(data),
|
||||||
|
0xFF1F => {}
|
||||||
0xFF20 => self.channels.four.update_length_timer(data),
|
0xFF20 => self.channels.four.update_length_timer(data),
|
||||||
0xFF21 => self.channels.four.update_volume_and_envelope(data),
|
0xFF21 => self.channels.four.update_volume_and_envelope(data),
|
||||||
0xFF22 => self.channels.four.update_frequency_and_randomness(data),
|
0xFF22 => self.channels.four.update_frequency_and_randomness(data),
|
||||||
|
@ -306,7 +308,7 @@ impl Apu {
|
||||||
}
|
}
|
||||||
self.apu_enable = (1 << 7) == (data & 0b10000000);
|
self.apu_enable = (1 << 7) == (data & 0b10000000);
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
0x0..0xFF10 | 0xFF27..=0xFFFF => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,10 @@ use self::{
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
connect::Renderer,
|
connect::Renderer,
|
||||||
processor::SplitRegister,
|
processor::{
|
||||||
|
memory::addresses::{OamAddress, VramAddress},
|
||||||
|
SplitRegister,
|
||||||
|
},
|
||||||
util::{clear_bit, get_bit},
|
util::{clear_bit, get_bit},
|
||||||
HEIGHT, WIDTH,
|
HEIGHT, WIDTH,
|
||||||
};
|
};
|
||||||
|
@ -247,6 +250,34 @@ where
|
||||||
interrupts
|
interrupts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_vram(&self, address: VramAddress) -> u8 {
|
||||||
|
if self.stat.mode != DrawMode::Mode3 {
|
||||||
|
self.vram.get(address)
|
||||||
|
} else {
|
||||||
|
0xFF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_vram(&mut self, address: VramAddress, data: u8) {
|
||||||
|
if self.stat.mode != DrawMode::Mode3 {
|
||||||
|
self.vram.set(address, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_oam(&self, address: OamAddress) -> u8 {
|
||||||
|
if self.stat.mode == DrawMode::VBlank || self.stat.mode == DrawMode::HBlank {
|
||||||
|
self.oam.get(address)
|
||||||
|
} else {
|
||||||
|
0xFF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_oam(&mut self, address: OamAddress, data: u8) {
|
||||||
|
if self.stat.mode == DrawMode::VBlank || self.stat.mode == DrawMode::HBlank {
|
||||||
|
self.oam.set(address, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn enter_hblank(&mut self) {
|
fn enter_hblank(&mut self) {
|
||||||
self.stat.mode = DrawMode::HBlank;
|
self.stat.mode = DrawMode::HBlank;
|
||||||
self.render_scanline(self.scanline);
|
self.render_scanline(self.scanline);
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
pub(crate) mod apu;
|
pub(crate) mod apu;
|
||||||
pub(crate) mod gpu;
|
pub(crate) mod gpu;
|
||||||
pub(crate) mod joypad;
|
pub(crate) mod joypad;
|
||||||
|
mod oam_dma;
|
||||||
pub(crate) mod serial;
|
pub(crate) mod serial;
|
||||||
mod timer;
|
mod timer;
|
||||||
pub use apu::Apu;
|
pub use apu::Apu;
|
||||||
pub use gpu::Gpu;
|
pub use gpu::Gpu;
|
||||||
pub use joypad::Joypad;
|
pub use joypad::Joypad;
|
||||||
|
pub use oam_dma::OamDma;
|
||||||
pub use serial::Serial;
|
pub use serial::Serial;
|
||||||
pub use timer::Timer;
|
pub use timer::Timer;
|
||||||
|
|
67
lib/src/processor/memory/mmio/oam_dma.rs
Normal file
67
lib/src/processor/memory/mmio/oam_dma.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use super::gpu::Colour;
|
||||||
|
use crate::{
|
||||||
|
connect::{PocketCamera, Renderer},
|
||||||
|
processor::{memory::Memory, SplitRegister},
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
|
pub struct OamDma {
|
||||||
|
addr: u8,
|
||||||
|
progress: Option<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for OamDma {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
addr: 0xFF,
|
||||||
|
progress: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OamDma {
|
||||||
|
pub(crate) fn get_register(&self) -> u8 {
|
||||||
|
self.addr
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_register(&mut self, data: u8) {
|
||||||
|
self.progress = Some(0);
|
||||||
|
self.addr = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_active(&self) -> bool {
|
||||||
|
self.progress.is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<ColourFormat, R, C> Memory<ColourFormat, R, C>
|
||||||
|
where
|
||||||
|
ColourFormat: From<Colour> + Clone,
|
||||||
|
R: Renderer<ColourFormat>,
|
||||||
|
C: PocketCamera + Send + 'static,
|
||||||
|
{
|
||||||
|
pub(crate) fn oam_tick(&mut self, steps: usize) {
|
||||||
|
for _ in 0..steps {
|
||||||
|
self.dma.progress = if let Some(mut progress) = self.dma.progress {
|
||||||
|
let mut addr: u16 = 0x0;
|
||||||
|
addr.set_high(self.dma.addr);
|
||||||
|
addr.set_low(progress);
|
||||||
|
let val = if self.dma.addr > 0xDF {
|
||||||
|
0xFF
|
||||||
|
} else {
|
||||||
|
self.get(addr)
|
||||||
|
};
|
||||||
|
self.gpu.oam.data[progress as usize] = val;
|
||||||
|
progress += 1;
|
||||||
|
if progress == 0xA0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(progress)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -104,7 +104,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
self.last_instruction_addr = self.reg.pc;
|
self.last_instruction_addr = self.reg.pc;
|
||||||
|
|
||||||
|
self.memory.user_mode = true;
|
||||||
let opcode = self.next_opcode();
|
let opcode = self.next_opcode();
|
||||||
|
|
||||||
if self.should_halt_bug {
|
if self.should_halt_bug {
|
||||||
self.reg.pc = self.reg.pc.wrapping_sub(0x1);
|
self.reg.pc = self.reg.pc.wrapping_sub(0x1);
|
||||||
self.should_halt_bug = false;
|
self.should_halt_bug = false;
|
||||||
|
@ -116,7 +119,10 @@ where
|
||||||
opcode,
|
opcode,
|
||||||
self.last_instruction_addr
|
self.last_instruction_addr
|
||||||
);
|
);
|
||||||
self.run_and_increment_timers(opcode);
|
|
||||||
|
let cycles = self.run_opcode(opcode);
|
||||||
|
self.memory.user_mode = false;
|
||||||
|
self.increment_timers(cycles);
|
||||||
|
|
||||||
let interrupt_cycles = self.handle_interrupts();
|
let interrupt_cycles = self.handle_interrupts();
|
||||||
self.increment_timers(interrupt_cycles);
|
self.increment_timers(interrupt_cycles);
|
||||||
|
@ -128,11 +134,6 @@ where
|
||||||
opcode
|
opcode
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_and_increment_timers(&mut self, opcode: u8) {
|
|
||||||
let cycles = self.run_opcode(opcode);
|
|
||||||
self.increment_timers(cycles);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn halt(&mut self) {
|
fn halt(&mut self) {
|
||||||
if !self.memory.ime && self.memory.interrupts.is_interrupt_queued() {
|
if !self.memory.ime && self.memory.interrupts.is_interrupt_queued() {
|
||||||
// halt bug
|
// halt bug
|
||||||
|
|
Loading…
Reference in a new issue