From 6fb6d074312b1d689ce478f07eb11375b5cd2468 Mon Sep 17 00:00:00 2001 From: Ry Date: Tue, 20 Sep 2022 00:24:38 -0700 Subject: [PATCH] Rework the interrupt system a little bit and allow toggling debug output --- src/cpu.rs | 99 +++++++++++++++++++++++++++++-------------------- src/keyboard.rs | 11 +++++- src/main.rs | 18 ++++++--- 3 files changed, 80 insertions(+), 48 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 1a84529..daffcf5 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -3,9 +3,9 @@ // TODO: in the instruction match statement, all of the register ones have `let result` inside the if statement // move this up to match all of the other ones (or move all of the other ones down, which would probably be better anyways) -use crate::Bus; +use std::sync::mpsc::Receiver; -const DEBUG: bool = false; +use crate::Bus; #[derive(Copy, Clone)] pub struct Flag { @@ -59,10 +59,18 @@ pub struct Cpu { pub halted: bool, pub bus: Bus, + + pub next_interrupt: Option, + pub next_soft_interrupt: Option, + pub next_exception: Option, + pub next_exception_operand: Option, + + pub debug: bool, + debug_toggle_receiver: Receiver<()>, } impl Cpu { - pub fn new(bus: Bus) -> Self { + pub fn new(bus: Bus, debug_toggle_receiver: Receiver<()>) -> Self { Cpu { instruction_pointer: 0xF0000000, stack_pointer: 0x00000000, @@ -72,6 +80,12 @@ impl Cpu { flag: Flag { swap_sp: false, interrupt: false, carry: false, zero: false }, halted: false, bus, + next_interrupt: None, + next_soft_interrupt: None, + next_exception: None, + next_exception_operand: None, + debug: false, + debug_toggle_receiver, } } fn check_condition(&self, condition: Condition) -> bool { @@ -225,39 +239,24 @@ impl Cpu { None => None, } } - pub fn interrupt(&mut self, interrupt: Interrupt) { - if DEBUG { println!("interrupt(): enabled: {}", self.flag.interrupt); } - let is_exception = if let Interrupt::Exception(_) = interrupt { true } else { false }; - if self.flag.interrupt || is_exception { - match interrupt { - Interrupt::Request(vector) => { - self.handle_interrupt(vector as u16); - } - Interrupt::Exception(exception) => { - match exception { - Exception::DivideByZero => { - let vector: u16 = 0; - self.handle_exception(vector, None); - } - Exception::InvalidOpcode(opcode) => { - let vector: u16 = 1; - self.handle_exception(vector, Some(opcode)); - } - Exception::PageFaultRead(virtual_address) => { - let vector: u16 = 2; - self.handle_exception(vector, Some(virtual_address)); - } - Exception::PageFaultWrite(virtual_address) => { - let vector: u16 = 3; - self.handle_exception(vector, Some(virtual_address)); - } - } - } + pub fn exception_to_vector(&mut self, exception: Exception) -> (Option, Option) { + match exception { + Exception::DivideByZero => { + (Some(0), None) + } + Exception::InvalidOpcode(opcode) => { + (Some(1), Some(opcode)) + } + Exception::PageFaultRead(virtual_address) => { + (Some(2), Some(virtual_address)) + } + Exception::PageFaultWrite(virtual_address) => { + (Some(3), Some(virtual_address)) } } } - fn handle_interrupt(&mut self, vector: u16) { - if DEBUG { println!("interrupt!!! vector: {:#04X}", vector); } + fn handle_interrupt(&mut self, vector: u8) { + if self.debug { println!("interrupt!!! vector: {:#04X}", vector); } let address_of_pointer = vector as u32 * 4; let old_mmu_state = *self.bus.memory.mmu_enabled(); @@ -285,9 +284,9 @@ impl Cpu { self.flag.interrupt = false; // prevent interrupts while already servicing an interrupt self.instruction_pointer = address; } - fn handle_exception(&mut self, vector: u16, operand: Option) { - if DEBUG { println!("exception!!! vector: {:#04X}, operand: {:?}", vector, operand); } - let address_of_pointer = (256 + vector) as u32 * 4; + fn handle_exception(&mut self, vector: u8, operand: Option) { + if self.debug { println!("exception!!! vector: {:#04X}, operand: {:?}", vector, operand); } + let address_of_pointer = (256 + vector as u32) * 4; let old_mmu_state = *self.bus.memory.mmu_enabled(); *self.bus.memory.mmu_enabled() = false; @@ -320,6 +319,24 @@ impl Cpu { } // execute instruction from memory at the current instruction pointer pub fn execute_memory_instruction(&mut self) { + if let Some(vector) = self.next_exception { + self.handle_exception(vector, self.next_exception_operand); + self.next_exception = None; + self.next_exception_operand = None; + } + if let Some(vector) = self.next_soft_interrupt { + if self.flag.interrupt { + self.handle_interrupt(vector); + self.next_soft_interrupt = None; + } + } + if let Some(vector) = self.next_interrupt { + if self.flag.interrupt { + self.handle_interrupt(vector); + self.next_interrupt = None; + } + } + let opcode_maybe = self.bus.memory.read_16(self.instruction_pointer); if opcode_maybe == None { return; @@ -327,11 +344,14 @@ impl Cpu { let opcode = opcode_maybe.unwrap(); if let Some(instruction) = Instruction::from_half(opcode) { - if DEBUG { println!("{:#010X}: {:?}", self.instruction_pointer, instruction); } + if self.debug { println!("{:#010X}: {:?}", self.instruction_pointer, instruction); } let next_instruction_pointer = self.execute_instruction(instruction); if let Some(next) = next_instruction_pointer { self.instruction_pointer = next; } + if let Ok(_) = self.debug_toggle_receiver.try_recv() { + self.debug = !self.debug; + } } else { let size = ((opcode & 0b1100000000000000) >> 14) as u8; let instruction = ((opcode & 0b0011111100000000) >> 8) as u8; @@ -2658,9 +2678,8 @@ impl Cpu { let (source_value, instruction_pointer_offset) = self.read_source(source)?; let should_run = self.check_condition(condition); if should_run { - self.instruction_pointer += instruction_pointer_offset; - self.handle_interrupt(source_value as u16); - Some(self.instruction_pointer) + self.next_soft_interrupt = Some(source_value as u8); + Some(self.instruction_pointer + instruction_pointer_offset) } else { Some(self.instruction_pointer + instruction_pointer_offset) } diff --git a/src/keyboard.rs b/src/keyboard.rs index 57926ae..2e30f87 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -1,20 +1,23 @@ // keyboard.rs + use crate::warn; use ringbuf::{Consumer, Producer, RingBuffer}; +use std::sync::mpsc::Sender; use winit::event::{ElementState, VirtualKeyCode}; pub struct Keyboard { consumer: Consumer, producer: Producer, + debug_toggle_sender: Sender<()>, } impl Keyboard { - pub fn new() -> Self { + pub fn new(debug_toggle_sender: Sender<()>) -> Self { let buffer = RingBuffer::::new(32); let (producer, consumer) = buffer.split(); - Keyboard { consumer, producer } + Keyboard { consumer, producer, debug_toggle_sender } } fn keycode_to_scancode(&self, keycode: VirtualKeyCode) -> u8 { @@ -105,6 +108,10 @@ impl Keyboard { if state == ElementState::Released && scancode != 0x00 { scancode |= 0x80; // "break" scancode } + if scancode == 0x57 { + self.debug_toggle_sender.send(()).unwrap(); + return; + } self.producer.push(scancode).unwrap_or_else(|_| warn("keyboard buffer full!")); } diff --git a/src/main.rs b/src/main.rs index 647b556..4f09199 100644 --- a/src/main.rs +++ b/src/main.rs @@ -76,8 +76,10 @@ fn main() { let args: Vec = env::args().collect(); + let (debug_toggle_sender, debug_toggle_receiver) = mpsc::channel::<()>(); + let mut display = Display::new(); - let keyboard = Arc::new(Mutex::new(Keyboard::new())); + let keyboard = Arc::new(Mutex::new(Keyboard::new(debug_toggle_sender))); let mouse = Arc::new(Mutex::new(Mouse::new())); let audio_channel_0 = Arc::new(Mutex::new(AudioChannel::new(0))); @@ -122,7 +124,7 @@ fn main() { let rom_top_address = rom_bottom_address + rom_size - 1; println!("ROM: {:.2} KiB mapped at physical {:#010X}-{:#010X}", rom_size / 1024, rom_bottom_address, rom_top_address); - let mut cpu = Cpu::new(bus); + let mut cpu = Cpu::new(bus, debug_toggle_receiver); let event_loop = EventLoop::new(); let mut input = WinitInputHelper::new(); @@ -160,10 +162,12 @@ fn main() { loop { while !cpu.halted { if let Ok(exception) = exception_receiver.try_recv() { - cpu.interrupt(Interrupt::Exception(exception)); + (cpu.next_exception, cpu.next_exception_operand) = cpu.exception_to_vector(exception); } else { if let Ok(interrupt) = interrupt_receiver.try_recv() { - cpu.interrupt(interrupt); + if let Interrupt::Request(vector) = interrupt { + cpu.next_interrupt = Some(vector); + } } } cpu.execute_memory_instruction(); @@ -182,8 +186,10 @@ fn main() { break; } if let Ok(interrupt) = interrupt_receiver.recv() { - cpu.halted = false; - cpu.interrupt(interrupt); + if let Interrupt::Request(vector) = interrupt { + cpu.next_interrupt = Some(vector); + cpu.halted = false; + } } else { // sender is closed, break break;