mirror of
https://github.com/FranLMSP/snes.git
synced 2026-01-01 07:21:35 -05:00
WIP Interrupt handling
This commit is contained in:
@@ -353,6 +353,13 @@ impl CPU {
|
||||
self.cycles += 6;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_return_interrupt(&mut self) {
|
||||
self.cycles += 6;
|
||||
if !self.registers.emulation_mode {
|
||||
self.cycles += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn increment_cycles_set_flag(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 2;
|
||||
}
|
||||
|
||||
@@ -508,7 +508,7 @@ impl CPU {
|
||||
self.increment_cycles_jmp(addressing_mode);
|
||||
}
|
||||
|
||||
fn do_push(&mut self, bus: &mut Bus, bytes: &[u8]) {
|
||||
pub fn do_push(&mut self, bus: &mut Bus, bytes: &[u8]) {
|
||||
for byte in bytes {
|
||||
let address = self.registers.sp as u32;
|
||||
bus.write(address, *byte);
|
||||
@@ -578,12 +578,12 @@ impl CPU {
|
||||
self.increment_cycles_phd();
|
||||
}
|
||||
|
||||
fn phk(&mut self, bus: &mut Bus) {
|
||||
pub fn phk(&mut self, bus: &mut Bus) {
|
||||
self.do_push(bus, &[self.registers.pbr]);
|
||||
self.increment_cycles_phk();
|
||||
}
|
||||
|
||||
fn php(&mut self, bus: &mut Bus) {
|
||||
pub fn php(&mut self, bus: &mut Bus) {
|
||||
self.do_push(bus, &[self.registers.p]);
|
||||
self.increment_cycles_php();
|
||||
}
|
||||
@@ -1067,10 +1067,13 @@ impl CPU {
|
||||
}
|
||||
|
||||
fn rti(&mut self, bus: &Bus) {
|
||||
self.registers.p = self.do_pull(bus, 1)[0];
|
||||
let pc_bytes = self.do_pull(bus, 2);
|
||||
self.registers.pc = (pc_bytes[0] as u16) | ((pc_bytes[1] as u16) << 8);
|
||||
self.registers.pbr = self.do_pull(bus, 1)[0];
|
||||
self.registers.p = self.do_pull(bus, 1)[0];
|
||||
if !self.registers.emulation_mode {
|
||||
self.registers.pbr = self.do_pull(bus, 1)[0];
|
||||
}
|
||||
self.increment_cycles_return_interrupt();
|
||||
}
|
||||
|
||||
fn trb(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
|
||||
@@ -1,12 +1,69 @@
|
||||
use super::cpu::CPU;
|
||||
use crate::cpu::bus::Bus;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Vector {
|
||||
Reset,
|
||||
COP,
|
||||
Break,
|
||||
Abort,
|
||||
NMI,
|
||||
VBlank,
|
||||
IRQ,
|
||||
HVTimer,
|
||||
}
|
||||
|
||||
impl Vector {
|
||||
pub fn get_base_address(&self) -> u32 {
|
||||
match self {
|
||||
Self::COP => 0x00FFE4,
|
||||
Self::Break => 0x00FFE6,
|
||||
Self::Abort => 0x00FFE8,
|
||||
Self::NMI | Self::VBlank => 0x00FFEA,
|
||||
Self::Reset => 0x00FFFC,
|
||||
Self::IRQ | Self::HVTimer => 0x00FFEE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CPU {
|
||||
fn get_vector(base_address: u32, bus: &Bus) -> u16 {
|
||||
(bus.read(base_address) as u16) | ((bus.read(base_address + 1) as u16) << 8)
|
||||
}
|
||||
|
||||
pub fn reset_vector(&mut self, bus: &Bus) {
|
||||
let reset_vector = (bus.read(0x00FFFC) as u16) | ((bus.read(0x00FFFD) as u16) << 8);
|
||||
let base_address = Vector::Reset.get_base_address();
|
||||
let reset_vector = CPU::get_vector(base_address, bus);
|
||||
self.registers.pc = reset_vector;
|
||||
self.is_stopped = false;
|
||||
}
|
||||
|
||||
fn get_vector_from_interrupts(&self) -> Option<Vector> {
|
||||
if self.registers.get_irq_disable_flag() {
|
||||
return None;
|
||||
}
|
||||
Some(Vector::Reset)
|
||||
}
|
||||
|
||||
fn push_emulation_interrupt(&mut self, bus: &mut Bus) {
|
||||
if ! self.registers.emulation_mode {
|
||||
self.phk(bus);
|
||||
}
|
||||
self.do_push(bus, &[
|
||||
(self.registers.pc >> 8) as u8,
|
||||
self.registers.pc as u8,
|
||||
]);
|
||||
self.php(bus);
|
||||
}
|
||||
|
||||
pub fn handle_interrupts(&mut self, bus: &mut Bus) {
|
||||
self.push_emulation_interrupt(bus);
|
||||
if let Some(vector) = self.get_vector_from_interrupts() {
|
||||
let effective_vector = vector.get_base_address();
|
||||
self.registers.pc = effective_vector as u16;
|
||||
self.registers.pbr = (effective_vector >> 16) as u8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user