From 462e1fe8eec753345a3cc80c5cb3651f95563855 Mon Sep 17 00:00:00 2001 From: tudnai Date: Tue, 1 Nov 2022 07:49:24 -0700 Subject: [PATCH] Debugger Active Run --- A2Mac/DebuggerWindowController.swift | 3 +- A2Mac/ViewController.swift | 6 ++- src/cpu/6502.c | 49 +++++++++++++++++++ src/cpu/6502.h | 17 +++++-- src/cpu/6502_C.h | 25 ++++++++++ src/cpu/6502_debugger.c | 40 +-------------- .../instructions/6502_instr_call_ret_jump.h | 2 + .../instructions/6502_instr_call_ret_jump.h | 2 + 8 files changed, 98 insertions(+), 46 deletions(-) diff --git a/A2Mac/DebuggerWindowController.swift b/A2Mac/DebuggerWindowController.swift index b325c2b..d275511 100644 --- a/A2Mac/DebuggerWindowController.swift +++ b/A2Mac/DebuggerWindowController.swift @@ -149,6 +149,7 @@ class DebuggerWindowController: NSWindowController, NSWindowDelegate { @IBAction func Step_In(_ sender: Any) { m6502_Step() + // TODO: This should be in Debugger! if let debugger = DebuggerViewController.shared { debugger.Update() @@ -173,7 +174,7 @@ class DebuggerWindowController: NSWindowController, NSWindowDelegate { sp = m6502.SP } - } while m6502.SP < 0xFF && m6502.SP <= sp + } while m6502.SP < 0xFE && m6502.SP <= sp // TODO: This should be in Debugger! if let debugger = DebuggerViewController.shared { diff --git a/A2Mac/ViewController.swift b/A2Mac/ViewController.swift index c2ca0f0..db54fc1 100644 --- a/A2Mac/ViewController.swift +++ b/A2Mac/ViewController.swift @@ -1289,9 +1289,13 @@ class ViewController: NSViewController { // run some code // cpuState = cpuState_executing // DispatchQueue.global(qos: .userInitiated).async { + if m6502.debug { + m6502_Debug() + } + else { m6502_Run() // cpuState = cpuState_running -// } + } // video rendering if ( frameCounter % video_fps_divider == 0 ) { diff --git a/src/cpu/6502.c b/src/cpu/6502.c index f35aadd..41170ee 100644 --- a/src/cpu/6502.c +++ b/src/cpu/6502.c @@ -271,6 +271,7 @@ INLINE int m6502_Step(void) { default: dbgPrintf("%04X: Unimplemented Instruction 0x%02X\n", m6502.PC -1, memread( m6502.PC -1 )); + m6502.interrupt = INV; return 2; } // switch fetch16 @@ -410,6 +411,54 @@ void m6502_Run() { spkr_update_disk_sfx(); } + +void m6502_Debug(void) { + m6502.clktime += m6502.clkfrm; + m6502.clkfrm = 0; + m6502.lastIO = 0; + m6502.interrupt = NO_INT; + + if( diskAccelerator_count ) { + if( --diskAccelerator_count <= 0 ) { + // make sure we only adjust clock once to get back to normal + diskAccelerator_count = 0; + clk_6502_per_frm = clk_6502_per_frm_set; + } + } + + for ( clk_6502_per_frm_max = clk_6502_per_frm; m6502.clkfrm < clk_6502_per_frm_max ; m6502.clkfrm += m6502_Step() ) { + switch (m6502.interrupt) { + case HALT: + return; + + case IRQ: + break; + + case NMI: + break; + + case INV: + break; + + case RET: + break; + + case HARDRESET: + hardReset(); + break; + + case SOFTRESET: + softReset(); + break; + + default: + break; + } + } + +} + + void read_rom( const char * bundlePath, const char * filename, uint8_t * rom, const uint16_t addr, const uint16_t size ) { char fullPath[256]; diff --git a/src/cpu/6502.h b/src/cpu/6502.h index 7ca5ae3..8d60c35 100644 --- a/src/cpu/6502.h +++ b/src/cpu/6502.h @@ -67,11 +67,14 @@ extern unsigned int clk_6502_per_frm_max; extern unsigned int clk_6502_per_frm_max_sound; -typedef enum { - NO_INT, - HALT, +typedef enum : uint8_t { + NO_INT = 0, + HALT, // HLT instruction + BREAK, // BRK instruction IRQ, NMI, + INV, // Invalid Opcode + RET, // RTS/RTI Used by Debugger Step_Over / Step_Out HARDRESET, SOFTRESET, } interrupt_t; @@ -142,8 +145,11 @@ typedef struct m6502_s { uint64_t lastIO; // Last time I/O accessed int ecoSpindown; // spindown counter for eco mode - debugLevel_t dbgLevel; // 34: 0: No Debug, 1: Disassembly Only, 2: Run till BRK, 3: StepByStep - + union { + uint8_t debug; + debugLevel_t dbgLevel; // 34: 0: No Debug, 1: Disassembly Only, 2: Run till BRK, 3: StepByStep + }; + union { unsigned int IF; // interrut flag interrupt_t interrupt; @@ -220,6 +226,7 @@ extern void rom_loadFile( const char * bundlePath, const char * filename ); extern void tst6502(void); extern void m6502_ColdReset( const char * bundlePath, const char * romFilePath ); extern void m6502_Run(void); +extern void m6502_Debug(void); INLINE int m6502_Step(void); extern void interrupt_IRQ(void); diff --git a/src/cpu/6502_C.h b/src/cpu/6502_C.h index 982bf29..84440a6 100644 --- a/src/cpu/6502_C.h +++ b/src/cpu/6502_C.h @@ -31,6 +31,31 @@ #ifndef _6502_C_h #define _6502_C_h +// http://6502.org/tutorials/interrupts.html +// +// 2.3 WAI: FASTER INTERRUPT SERVICE ON THE 65C02 +// +// WDC's 65C02 has a "wait" instruction, WAI. This allows a special case of ultra-fast IRQ interrupt service. +// +// In the earlier doorbell comparison, the guests, after ringing the doorbell, had to wait for you to put down what you were doing and get to the door, which introduced a small delay before they would see the door open. The comparison now is that you have already put your work down and gone to the door so you're right there ready to open it immediately upon hearing the bell. +// +// If the main part of the work can be paused until the next interrupt, you can set the interrupt-disable bit I-- yes, set it-- execute WAI, and have the very next instruction to be the beginning of the ISR. There will be no jumping through vectors; and since you know exactly where the program pointer will be when the interrupt hits, you will not necessarily need to save any registers your ISR uses. If you do, you can do it before the interrupt. +// +// The WAI guarantees that the processor will not be in the middle of executing another instruction when the IRQ line is pulled down, so we can eliminate that part of the latency. The other part of the latency, the 7-clock interrupt sequence, gets eliminated by the fact that we have used SEI to disable the normal IRQ operation, so the IRQ will only have the effect of re-starting the processor and making it continue on with the next instruction instead of taking the vector. And since we don't take the vector, we won't use RTI at the end either. +// +// Here's the idea. The LDA and STA instructions were selected only arbitrarily for the example. The xxx just represent the continuation of code execution after the interrupt service is finished. +// +// STA VIA1IER ; Pre-interrupt code finishes here. +// SEI ; Disable interrupts if not already done. +// WAI ; Put processor into pause mode. +// LDA VIA1PB ; First instruction of ISR goes here. +// . ; (Notice the code is straight-lined.) +// . ; Service the interrupt. +// . +// xxx ; End of ISR moves right into the next thing +// xxx ; for the computer to do, without using RTI. + + // 6502 instructions with additional addressing modes // ADC AND CMP EOR LDA ORA SBC STA - (zp) addressing mode diff --git a/src/cpu/6502_debugger.c b/src/cpu/6502_debugger.c index dd74528..3c0dd3c 100644 --- a/src/cpu/6502_debugger.c +++ b/src/cpu/6502_debugger.c @@ -88,47 +88,9 @@ INLINE int m6502_Disass_1_Instr(void) { default: dbgPrintf("%04X: Unimplemented Instruction 0x%02X\n", m6502.PC -1, _memread_dbg( m6502.PC -1 )); return 2; - } // switch fetch16 + } // switch fetch return 2; } -void m6502_Disass(void) { - - // init time -//#ifdef CLK_WAIT -// unsigned long long elpased = (unsigned long long)-1LL; -//#endif - - m6502.clktime += m6502.clkfrm; - m6502.clkfrm = 0; - m6502.lastIO = 0; - - if( diskAccelerator_count ) { - if( --diskAccelerator_count <= 0 ) { - // make sure we only adjust clock once to get back to normal - diskAccelerator_count = 0; - clk_6502_per_frm = clk_6502_per_frm_set; - } - } - -#ifdef SPEEDTEST - for ( inst_cnt = 0; inst_cnt < iterations ; inst_cnt++ ) -#elif defined( CLK_WAIT ) - // we clear the clkfrm from ViewController Update() - // we will also use this to pause the simulation if not finished by the end of the frame - for ( clk_6502_per_frm_max = clk_6502_per_frm; m6502.clkfrm < clk_6502_per_frm_max ; m6502.clkfrm += m6502_Disass_1_Instr() ) -#else - // this is for max speed only -- WARNING! It works only if simulation runs in a completely different thread from the Update() - for ( ; ; ) -#endif - { - } - // TODO: clkfrm is already increamented!!! -// printDisassembly(outdev); - -} - - - diff --git a/src/cpu/instructions/6502_instr_call_ret_jump.h b/src/cpu/instructions/6502_instr_call_ret_jump.h index 2c69242..5c26dba 100644 --- a/src/cpu/instructions/6502_instr_call_ret_jump.h +++ b/src/cpu/instructions/6502_instr_call_ret_jump.h @@ -110,6 +110,7 @@ INLINE void RTS() { #ifndef DEBUGGER m6502.PC = POP_addr() +1; + m6502.interrupt = RET; // disk accelerator would only work for a certain amount of time // currently it is 200ms simulated times @@ -137,6 +138,7 @@ INLINE void RTI() { setFlags( POP() ); // m6502.I = 0; m6502.PC = POP_addr(); + m6502.interrupt = RET; #endif } diff --git a/src/cpu/jit/instructions/6502_instr_call_ret_jump.h b/src/cpu/jit/instructions/6502_instr_call_ret_jump.h index 33ea854..9d6e289 100644 --- a/src/cpu/jit/instructions/6502_instr_call_ret_jump.h +++ b/src/cpu/jit/instructions/6502_instr_call_ret_jump.h @@ -114,6 +114,7 @@ INSTR void RTS(void) { #ifndef DEBUGGER m6502.PC = POP_addr() +1; + m6502.interrupt = RET; // disk accelerator would only work for a certain amount of time // currently it is 200ms simulated times @@ -141,6 +142,7 @@ INSTR void RTI(void) { setFlags( POP() ); // m6502.I = 0; m6502.PC = POP_addr(); + m6502.interrupt = RET; #endif }