From dcaeece7faf404746f6555fcacfc2f059f53cec9 Mon Sep 17 00:00:00 2001 From: august kline Date: Thu, 4 Jul 2024 22:53:55 -0400 Subject: [PATCH] interrupts work now! --- src/cpu.rs | 59 +++++++++++++------------------------------ src/instructions.rs | 44 +++++++++++++++++++++++++++----- src/main.rs | 5 ++-- src/roms/keyboard.asm | 45 ++++++++++++++++++++------------- src/video.rs | 2 +- 5 files changed, 86 insertions(+), 69 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 96805da..890f607 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -27,8 +27,7 @@ pub struct CpuController(Sender); pub enum CpuControl { Irq, Nmi, - Stop, - Resume, + Toggle, Data, Cycle, } @@ -43,11 +42,8 @@ impl CpuController { pub fn nmi(&self) { self.0.send(CpuControl::Nmi); } - pub fn stop(&self) { - self.0.send(CpuControl::Stop); - } - pub fn resume(&self) { - self.0.send(CpuControl::Resume); + pub fn toggle(&self) { + self.0.send(CpuControl::Toggle); } pub fn cycle(&self) { self.0.send(CpuControl::Cycle); @@ -215,8 +211,9 @@ impl Cpu { match control { CpuControl::Nmi => self.nmi = true, CpuControl::Irq => self.irq = true, - CpuControl::Stop => self.stopped = true, - CpuControl::Resume => self.stopped = false, + CpuControl::Toggle => { + self.stopped = !self.stopped; + } CpuControl::Cycle => self.cycle = true, CpuControl::Data => {} // self // .state_tx @@ -239,9 +236,13 @@ impl Cpu { pub fn cycle(&mut self) { self.receive_control(); - if self.stopped { + + if self.stopped & !self.cycle { + // self.set_flag(StatusFlag::IrqDisable, true); return; } + self.cycle = false; + while self.pending_cycles != 0 { // roughly cycle-accurate timing sleep(Duration::from_nanos(500)); @@ -253,38 +254,12 @@ impl Cpu { let opcode = self.read(self.pc); let instruction = get_instruction(opcode); instruction.call(self); - // match instruction { - // Instruction::Valid(valid_instruction) => { - // // println!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.a, x = self.x, y = self.y, pc = self.pc, s = self.s, p = self.p, irq = self.irq, nmi = self.nmi); - // // println!( - // // "Instruction: {:?}, {:#04x}", - // // valid_instruction.opcode, opcode - // // ); - // // println!(""); - // self.pc += 1; - // match valid_instruction.opcode.call(self) { - // Ok(_) => { - // self.pending_cycles += valid_instruction.cycles as usize; - // } - // Err(_) => { - // println!("An IncompatibleAddrMode was used at address {:#06x} for instruction {:?}", self.pc, valid_instruction); - // } - // }; - // } - // Instruction::Invalid(invalid_instruction) => match invalid_instruction.opcode { - // 0x02 => { - // // println!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.a, x = self.x, y = self.y, pc = self.pc, s = self.s, p = self.p, irq = self.irq.try_recv().unwrap_or_default(), nmi = self.nmi); - // let _ = &self.memory.dump(); - // } - // _ => { - // println!( - // "An invalid instruction with opcode {:#04x} was called at address {:#06x}", - // invalid_instruction.opcode, self.pc - // ); - // } - // }, - // } - // self.cycle_count += 1; + // println!("a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", a = self.a, x = self.x, y = self.y, pc = self.pc, s = self.s, p = self.p, irq = self.irq, nmi = self.nmi); + // println!( + // "Instruction: {:?}, {:#04x}", + // valid_instruction.opcode, opcode + // ); + // println!(""); } pub fn stop(&mut self) { self.stopped = true; diff --git a/src/instructions.rs b/src/instructions.rs index 600b165..9578ba4 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -3,6 +3,7 @@ use core::panic; use termion::cursor::Goto; +use termion::{clear, color}; use crate::cpu::{Cpu, StatusFlag}; use crate::memory::{MemoryReader, MemoryWriter}; @@ -20,13 +21,39 @@ pub struct Instruction<'a> { impl Instruction<'_> { pub fn call(&self, cpu: &mut Cpu) { + print!("{}{}instruction: {:?}, a: {a:#04x}, x: {x:#04x}, y: {y:#04x}, pc: {pc:#06x}, sp: {s:#04x}, sr: {p:#010b}, irq: {irq:?}, nmi: {nmi:?}", Goto(0, 31),clear::UntilNewline, self.name, a = cpu.a, x = cpu.x, y = cpu.y, pc = cpu.pc, s = cpu.s, p = cpu.p, irq = cpu.irq, nmi = cpu.nmi); + // print!( + // "{}instruction: {:?}, pc: {:#04x}", + // Goto(0, 31), + // self.name, + // cpu.pc + // ); + print!( + "{}{:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {}{}{:02x}{}{} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x} {:02x}", + Goto(0, 32), + cpu.read(cpu.pc.wrapping_sub(8)), + cpu.read(cpu.pc.wrapping_sub(7)), + cpu.read(cpu.pc.wrapping_sub(6)), + cpu.read(cpu.pc.wrapping_sub(5)), + cpu.read(cpu.pc.wrapping_sub(4)), + cpu.read(cpu.pc.wrapping_sub(3)), + cpu.read(cpu.pc.wrapping_sub(2)), + cpu.read(cpu.pc.wrapping_sub(1)), + color::Bg(color::Rgb(0xFF, 0xCC, 0x00)), + color::Fg(color::Rgb(0x11, 0x05, 0x00)), + cpu.read(cpu.pc), + color::Fg(color::Rgb(0xFF, 0xCC, 0x00)), + color::Bg(color::Rgb(0x11, 0x05, 0x00)), + cpu.read(cpu.pc.wrapping_add(1)), + cpu.read(cpu.pc.wrapping_add(2)), + cpu.read(cpu.pc.wrapping_add(3)), + cpu.read(cpu.pc.wrapping_add(4)), + cpu.read(cpu.pc.wrapping_add(5)), + cpu.read(cpu.pc.wrapping_add(6)), + cpu.read(cpu.pc.wrapping_add(7)), + cpu.read(cpu.pc.wrapping_add(8)), + ); cpu.pc = cpu.pc.wrapping_add(1); // read instruction byte - // println!( - // "{}instruction: {:?}, pc: {:#04x}", - // Goto(0, 31), - // self.name, - // cpu.pc - // ); match self.instr_fn { // existence of instr_fn means this is a valid instruction Some(instr_fn) => { @@ -732,7 +759,10 @@ fn rti(cpu: &mut Cpu, _address: Option) { fn rts(cpu: &mut Cpu, _address: Option) { let return_address = cpu.pop_stack_word(); - cpu.pc = return_address + 3; // Go back to where we jsr'ed, skipping the operand + // cpu.pc = return_address + 3; // Go back to where we jsr'ed, skipping the operand + cpu.pc = return_address.wrapping_add(1); // we love an off by 2 error! + // TODO: figure out why + // this needs to be like this } fn sbc(cpu: &mut Cpu, address: Option) { diff --git a/src/main.rs b/src/main.rs index c173507..d2d8818 100644 --- a/src/main.rs +++ b/src/main.rs @@ -60,8 +60,9 @@ fn main() { Key::Char('q') => { break 'main; } - // Key::Char(' ') => cpu_controller.stop(), - // Key::Char('\n') => cpu_controller.resume(), + Key::Char(' ') => cpu_controller.toggle(), + Key::Char('\n') => cpu_controller.cycle(), + Key::Char('i') => cpu_controller.irq(), _ => keyboard.read_keys(key), } } diff --git a/src/roms/keyboard.asm b/src/roms/keyboard.asm index fac5f17..bef677a 100644 --- a/src/roms/keyboard.asm +++ b/src/roms/keyboard.asm @@ -10,30 +10,39 @@ reset: sei ldx #0; initialize data stack pointer -initdisplay: - lda #0 - ldy #0 +; initdisplay: +; lda #0 +; ldy #0 -cleardisplay: - sta $6000,y - sta $6100,y - sta $6200,y - sta $6300,y - sta $6400,y - sta $6500,y - sta $6600,y - sta $6700,y ; this goes slightly over but it's fine - iny - bne cleardisplay +; cleardisplay: +; sta $6000,y +; sta $6100,y +; sta $6200,y +; sta $6300,y +; sta $6400,y +; sta $6500,y +; sta $6600,y +; sta $6700,y ; this goes slightly over but it's fine +; iny +; bne cleardisplay cli main: - ; jsr read_keys + jsr test ; lda key_buffer - lda $4400 - sta $6000 + ; lda $4400 + ; sta $6000 + nop + nop + nop jmp main +test: + nop + nop + nop + rts + ; first, let's do the simplest case of just the letter a being pressed ; 1. check row 2 ($4402, where the a key is) for pressed keys ; 2. if any keys are pressed, check if the key is a (bit 0) @@ -104,6 +113,8 @@ fill: ; fills an area from (x1, y1) to (x2, y2) will character c, (n1: c n2: x1 jsr get_char_address irq: + lda $4400 + sta $6000 rts isr: ; interrupt service routine diff --git a/src/video.rs b/src/video.rs index 22d3a42..c80bc0c 100644 --- a/src/video.rs +++ b/src/video.rs @@ -204,7 +204,7 @@ impl Screen { } } pub fn draw(&mut self) { - // self.controller.irq(); + self.controller.irq(); self.renderer.render(); }