Debugger Active Run

This commit is contained in:
tudnai 2022-11-01 07:49:24 -07:00
parent bd8403ee64
commit 462e1fe8ee
8 changed files with 98 additions and 46 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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