Rework the interrupt system a little bit and allow toggling debug output

This commit is contained in:
Ry 2022-09-20 00:24:38 -07:00
parent 42f26a48e7
commit 6fb6d07431
3 changed files with 80 additions and 48 deletions

View File

@ -3,9 +3,9 @@
// TODO: in the instruction match statement, all of the register ones have `let result` inside the if statement // 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) // 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)] #[derive(Copy, Clone)]
pub struct Flag { pub struct Flag {
@ -59,10 +59,18 @@ pub struct Cpu {
pub halted: bool, pub halted: bool,
pub bus: Bus, pub bus: Bus,
pub next_interrupt: Option<u8>,
pub next_soft_interrupt: Option<u8>,
pub next_exception: Option<u8>,
pub next_exception_operand: Option<u32>,
pub debug: bool,
debug_toggle_receiver: Receiver<()>,
} }
impl Cpu { impl Cpu {
pub fn new(bus: Bus) -> Self { pub fn new(bus: Bus, debug_toggle_receiver: Receiver<()>) -> Self {
Cpu { Cpu {
instruction_pointer: 0xF0000000, instruction_pointer: 0xF0000000,
stack_pointer: 0x00000000, stack_pointer: 0x00000000,
@ -72,6 +80,12 @@ impl Cpu {
flag: Flag { swap_sp: false, interrupt: false, carry: false, zero: false }, flag: Flag { swap_sp: false, interrupt: false, carry: false, zero: false },
halted: false, halted: false,
bus, 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 { fn check_condition(&self, condition: Condition) -> bool {
@ -225,39 +239,24 @@ impl Cpu {
None => None, None => None,
} }
} }
pub fn interrupt(&mut self, interrupt: Interrupt) { pub fn exception_to_vector(&mut self, exception: Exception) -> (Option<u8>, Option<u32>) {
if DEBUG { println!("interrupt(): enabled: {}", self.flag.interrupt); } match exception {
let is_exception = if let Interrupt::Exception(_) = interrupt { true } else { false }; Exception::DivideByZero => {
if self.flag.interrupt || is_exception { (Some(0), None)
match interrupt { }
Interrupt::Request(vector) => { Exception::InvalidOpcode(opcode) => {
self.handle_interrupt(vector as u16); (Some(1), Some(opcode))
} }
Interrupt::Exception(exception) => { Exception::PageFaultRead(virtual_address) => {
match exception { (Some(2), Some(virtual_address))
Exception::DivideByZero => { }
let vector: u16 = 0; Exception::PageFaultWrite(virtual_address) => {
self.handle_exception(vector, None); (Some(3), Some(virtual_address))
}
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));
}
}
}
} }
} }
} }
fn handle_interrupt(&mut self, vector: u16) { fn handle_interrupt(&mut self, vector: u8) {
if DEBUG { println!("interrupt!!! vector: {:#04X}", vector); } if self.debug { println!("interrupt!!! vector: {:#04X}", vector); }
let address_of_pointer = vector as u32 * 4; let address_of_pointer = vector as u32 * 4;
let old_mmu_state = *self.bus.memory.mmu_enabled(); 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.flag.interrupt = false; // prevent interrupts while already servicing an interrupt
self.instruction_pointer = address; self.instruction_pointer = address;
} }
fn handle_exception(&mut self, vector: u16, operand: Option<u32>) { fn handle_exception(&mut self, vector: u8, operand: Option<u32>) {
if DEBUG { println!("exception!!! vector: {:#04X}, operand: {:?}", vector, operand); } if self.debug { println!("exception!!! vector: {:#04X}, operand: {:?}", vector, operand); }
let address_of_pointer = (256 + vector) as u32 * 4; let address_of_pointer = (256 + vector as u32) * 4;
let old_mmu_state = *self.bus.memory.mmu_enabled(); let old_mmu_state = *self.bus.memory.mmu_enabled();
*self.bus.memory.mmu_enabled() = false; *self.bus.memory.mmu_enabled() = false;
@ -320,6 +319,24 @@ impl Cpu {
} }
// execute instruction from memory at the current instruction pointer // execute instruction from memory at the current instruction pointer
pub fn execute_memory_instruction(&mut self) { 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); let opcode_maybe = self.bus.memory.read_16(self.instruction_pointer);
if opcode_maybe == None { if opcode_maybe == None {
return; return;
@ -327,11 +344,14 @@ impl Cpu {
let opcode = opcode_maybe.unwrap(); let opcode = opcode_maybe.unwrap();
if let Some(instruction) = Instruction::from_half(opcode) { 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); let next_instruction_pointer = self.execute_instruction(instruction);
if let Some(next) = next_instruction_pointer { if let Some(next) = next_instruction_pointer {
self.instruction_pointer = next; self.instruction_pointer = next;
} }
if let Ok(_) = self.debug_toggle_receiver.try_recv() {
self.debug = !self.debug;
}
} else { } else {
let size = ((opcode & 0b1100000000000000) >> 14) as u8; let size = ((opcode & 0b1100000000000000) >> 14) as u8;
let instruction = ((opcode & 0b0011111100000000) >> 8) 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 (source_value, instruction_pointer_offset) = self.read_source(source)?;
let should_run = self.check_condition(condition); let should_run = self.check_condition(condition);
if should_run { if should_run {
self.instruction_pointer += instruction_pointer_offset; self.next_soft_interrupt = Some(source_value as u8);
self.handle_interrupt(source_value as u16); Some(self.instruction_pointer + instruction_pointer_offset)
Some(self.instruction_pointer)
} else { } else {
Some(self.instruction_pointer + instruction_pointer_offset) Some(self.instruction_pointer + instruction_pointer_offset)
} }

View File

@ -1,20 +1,23 @@
// keyboard.rs // keyboard.rs
use crate::warn; use crate::warn;
use ringbuf::{Consumer, Producer, RingBuffer}; use ringbuf::{Consumer, Producer, RingBuffer};
use std::sync::mpsc::Sender;
use winit::event::{ElementState, VirtualKeyCode}; use winit::event::{ElementState, VirtualKeyCode};
pub struct Keyboard { pub struct Keyboard {
consumer: Consumer<u8>, consumer: Consumer<u8>,
producer: Producer<u8>, producer: Producer<u8>,
debug_toggle_sender: Sender<()>,
} }
impl Keyboard { impl Keyboard {
pub fn new() -> Self { pub fn new(debug_toggle_sender: Sender<()>) -> Self {
let buffer = RingBuffer::<u8>::new(32); let buffer = RingBuffer::<u8>::new(32);
let (producer, consumer) = buffer.split(); let (producer, consumer) = buffer.split();
Keyboard { consumer, producer } Keyboard { consumer, producer, debug_toggle_sender }
} }
fn keycode_to_scancode(&self, keycode: VirtualKeyCode) -> u8 { fn keycode_to_scancode(&self, keycode: VirtualKeyCode) -> u8 {
@ -105,6 +108,10 @@ impl Keyboard {
if state == ElementState::Released && scancode != 0x00 { if state == ElementState::Released && scancode != 0x00 {
scancode |= 0x80; // "break" scancode 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!")); self.producer.push(scancode).unwrap_or_else(|_| warn("keyboard buffer full!"));
} }

View File

@ -76,8 +76,10 @@ fn main() {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
let (debug_toggle_sender, debug_toggle_receiver) = mpsc::channel::<()>();
let mut display = Display::new(); 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 mouse = Arc::new(Mutex::new(Mouse::new()));
let audio_channel_0 = Arc::new(Mutex::new(AudioChannel::new(0))); 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; 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); 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 event_loop = EventLoop::new();
let mut input = WinitInputHelper::new(); let mut input = WinitInputHelper::new();
@ -160,10 +162,12 @@ fn main() {
loop { loop {
while !cpu.halted { while !cpu.halted {
if let Ok(exception) = exception_receiver.try_recv() { 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 { } else {
if let Ok(interrupt) = interrupt_receiver.try_recv() { 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(); cpu.execute_memory_instruction();
@ -182,8 +186,10 @@ fn main() {
break; break;
} }
if let Ok(interrupt) = interrupt_receiver.recv() { if let Ok(interrupt) = interrupt_receiver.recv() {
cpu.halted = false; if let Interrupt::Request(vector) = interrupt {
cpu.interrupt(interrupt); cpu.next_interrupt = Some(vector);
cpu.halted = false;
}
} else { } else {
// sender is closed, break // sender is closed, break
break; break;