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 {
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!("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!(
// "An invalid instruction with opcode {:#04x} was called at address {:#06x}",
// invalid_instruction.opcode, self.pc
// "Instruction: {:?}, {:#04x}",
// valid_instruction.opcode, opcode
// );
// }
// },
// }
// self.cycle_count += 1;
// println!("");
}
pub fn stop(&mut self) {
self.stopped = true;

View File

@ -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) {
cpu.pc = cpu.pc.wrapping_add(1); // read instruction byte
// println!(
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
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<u16>) {
fn rts(cpu: &mut Cpu, _address: Option<u16>) {
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>) {

View File

@ -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),
}
}

View File

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

View File

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