WIP Interrupt handling

This commit is contained in:
2023-05-30 21:13:52 -05:00
parent 93cc597c10
commit ecaaaab4b4
3 changed files with 73 additions and 6 deletions

View File

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

View File

@@ -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) {

View File

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