interrupts work now!
This commit is contained in:
		
							parent
							
								
									7f8e00af23
								
							
						
					
					
						commit
						dcaeece7fa
					
				
							
								
								
									
										59
									
								
								src/cpu.rs
								
								
								
								
							
							
						
						
									
										59
									
								
								src/cpu.rs
								
								
								
								
							| 
						 | 
				
			
			@ -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!(
 | 
			
		||||
        //                 "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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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<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>) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -204,7 +204,7 @@ impl Screen {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
    pub fn draw(&mut self) {
 | 
			
		||||
        // self.controller.irq();
 | 
			
		||||
        self.controller.irq();
 | 
			
		||||
        self.renderer.render();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue