interrupts work now!

This commit is contained in:
august kline 2024-07-04 22:53:55 -04:00
parent 7f8e00af23
commit dcaeece7fa
5 changed files with 86 additions and 69 deletions

View File

@ -27,8 +27,7 @@ pub struct CpuController(Sender<CpuControl>);
pub enum CpuControl { pub enum CpuControl {
Irq, Irq,
Nmi, Nmi,
Stop, Toggle,
Resume,
Data, Data,
Cycle, Cycle,
} }
@ -43,11 +42,8 @@ impl CpuController {
pub fn nmi(&self) { pub fn nmi(&self) {
self.0.send(CpuControl::Nmi); self.0.send(CpuControl::Nmi);
} }
pub fn stop(&self) { pub fn toggle(&self) {
self.0.send(CpuControl::Stop); self.0.send(CpuControl::Toggle);
}
pub fn resume(&self) {
self.0.send(CpuControl::Resume);
} }
pub fn cycle(&self) { pub fn cycle(&self) {
self.0.send(CpuControl::Cycle); self.0.send(CpuControl::Cycle);
@ -215,8 +211,9 @@ impl Cpu {
match control { match control {
CpuControl::Nmi => self.nmi = true, CpuControl::Nmi => self.nmi = true,
CpuControl::Irq => self.irq = true, CpuControl::Irq => self.irq = true,
CpuControl::Stop => self.stopped = true, CpuControl::Toggle => {
CpuControl::Resume => self.stopped = false, self.stopped = !self.stopped;
}
CpuControl::Cycle => self.cycle = true, CpuControl::Cycle => self.cycle = true,
CpuControl::Data => {} // self CpuControl::Data => {} // self
// .state_tx // .state_tx
@ -239,9 +236,13 @@ impl Cpu {
pub fn cycle(&mut self) { pub fn cycle(&mut self) {
self.receive_control(); self.receive_control();
if self.stopped {
if self.stopped & !self.cycle {
// self.set_flag(StatusFlag::IrqDisable, true);
return; return;
} }
self.cycle = false;
while self.pending_cycles != 0 { while self.pending_cycles != 0 {
// roughly cycle-accurate timing // roughly cycle-accurate timing
sleep(Duration::from_nanos(500)); sleep(Duration::from_nanos(500));
@ -253,38 +254,12 @@ impl Cpu {
let opcode = self.read(self.pc); let opcode = self.read(self.pc);
let instruction = get_instruction(opcode); let instruction = get_instruction(opcode);
instruction.call(self); instruction.call(self);
// match 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);
// 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!( // println!(
// "An invalid instruction with opcode {:#04x} was called at address {:#06x}", // "Instruction: {:?}, {:#04x}",
// invalid_instruction.opcode, self.pc // valid_instruction.opcode, opcode
// ); // );
// } // println!("");
// },
// }
// self.cycle_count += 1;
} }
pub fn stop(&mut self) { pub fn stop(&mut self) {
self.stopped = true; self.stopped = true;

View File

@ -3,6 +3,7 @@
use core::panic; use core::panic;
use termion::cursor::Goto; use termion::cursor::Goto;
use termion::{clear, color};
use crate::cpu::{Cpu, StatusFlag}; use crate::cpu::{Cpu, StatusFlag};
use crate::memory::{MemoryReader, MemoryWriter}; use crate::memory::{MemoryReader, MemoryWriter};
@ -20,13 +21,39 @@ pub struct Instruction<'a> {
impl Instruction<'_> { impl Instruction<'_> {
pub fn call(&self, cpu: &mut Cpu) { pub fn call(&self, cpu: &mut Cpu) {
cpu.pc = cpu.pc.wrapping_add(1); // read instruction byte 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);
// println!( // print!(
// "{}instruction: {:?}, pc: {:#04x}", // "{}instruction: {:?}, pc: {:#04x}",
// Goto(0, 31), // Goto(0, 31),
// self.name, // self.name,
// cpu.pc // 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
match self.instr_fn { match self.instr_fn {
// existence of instr_fn means this is a valid instruction // existence of instr_fn means this is a valid instruction
Some(instr_fn) => { Some(instr_fn) => {
@ -732,7 +759,10 @@ fn rti(cpu: &mut Cpu, _address: Option<u16>) {
fn rts(cpu: &mut Cpu, _address: Option<u16>) { fn rts(cpu: &mut Cpu, _address: Option<u16>) {
let return_address = cpu.pop_stack_word(); 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<u16>) { fn sbc(cpu: &mut Cpu, address: Option<u16>) {

View File

@ -60,8 +60,9 @@ fn main() {
Key::Char('q') => { Key::Char('q') => {
break 'main; break 'main;
} }
// Key::Char(' ') => cpu_controller.stop(), Key::Char(' ') => cpu_controller.toggle(),
// Key::Char('\n') => cpu_controller.resume(), Key::Char('\n') => cpu_controller.cycle(),
Key::Char('i') => cpu_controller.irq(),
_ => keyboard.read_keys(key), _ => keyboard.read_keys(key),
} }
} }

View File

@ -10,30 +10,39 @@ reset:
sei sei
ldx #0; initialize data stack pointer ldx #0; initialize data stack pointer
initdisplay: ; initdisplay:
lda #0 ; lda #0
ldy #0 ; ldy #0
cleardisplay: ; cleardisplay:
sta $6000,y ; sta $6000,y
sta $6100,y ; sta $6100,y
sta $6200,y ; sta $6200,y
sta $6300,y ; sta $6300,y
sta $6400,y ; sta $6400,y
sta $6500,y ; sta $6500,y
sta $6600,y ; sta $6600,y
sta $6700,y ; this goes slightly over but it's fine ; sta $6700,y ; this goes slightly over but it's fine
iny ; iny
bne cleardisplay ; bne cleardisplay
cli cli
main: main:
; jsr read_keys jsr test
; lda key_buffer ; lda key_buffer
lda $4400 ; lda $4400
sta $6000 ; sta $6000
nop
nop
nop
jmp main jmp main
test:
nop
nop
nop
rts
; first, let's do the simplest case of just the letter a being pressed ; 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 ; 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) ; 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 jsr get_char_address
irq: irq:
lda $4400
sta $6000
rts rts
isr: ; interrupt service routine isr: ; interrupt service routine

View File

@ -204,7 +204,7 @@ impl Screen {
} }
} }
pub fn draw(&mut self) { pub fn draw(&mut self) {
// self.controller.irq(); self.controller.irq();
self.renderer.render(); self.renderer.render();
} }