-
Notifications
You must be signed in to change notification settings - Fork 17
SingleStep
Here's the idea:
- The CPU state of the program being debugged is on the stack. The (stacked) PC points to the next instruction to be executed.
- The CPU executes a register write that will trigger an NMI in 2 instructions time
- The CPU executes a RTI (return from interrupt) to pull the full CPU state off the stack ie resume the program under debug. This is the 1st instruction (although it takes multiple cycles it is a single instruction - it is uninterruptable).
- The CPU executes 1 instruction of the program being debugged (at the address restored to the PC by the RTI). This is the 2nd instruction.
- The CPU gets an NMI - which saves the CPU state of the program being debugged on the stack
Now we're in the same state that we started in, except 1 instruction of the program being debugged has been executed, and the stacked CPU state is different as a result.
For more details, refer to the Programming guide.
The hardware for this timed NMI generation is incorporated in the mk2 memory mapping unit and is used by the "Trace" command in the latest version of BUGGY.
Here is a test program that I used to make sure that single-step was working correctly. It is a prototype of the code that is now part of BUGGY. It can be loaded and run under the control of BUGGY. To try it out, load BUGGY from CamelForth and type it in by hand (ah, the nostalgia) using the instructions in the comments within the code.
0001 * Type-in test program for trying multicomp NMI single-step logic on
0002 * real hardware: type in and execute under the control of BUGGY
0003 *
0004 * Test1: type in as-is. G2000 to execute. It should return to
0005 * the BUGGY prompt. D2069 to see final register state. Expect
0006 * to see A incremented (By first instruction at RESUME) and
0007 * PC incremented.
0008 *
0009 * Test2: A205A and enter LDY 8,S <return> . <return
0010 * G2000 to execute. It should return to
0011 * the BUGGY prompt. D2069 to see final register state. Expect
0012 * to see A still at 55, value of Y changed and PC incremented
0013 * by 3 (address of next instruction after 3-byte "LDY 8,S".
0014
0015 * Control register: bit 4 generates NMI.
0016 ffde MMUADR EQU $FFDE
0017
0018 * Type in code at this address.
0019 2000 ORG $2000
0020
0021 * On entry, S is set up as the stack pointer for BUGGY
0022
0023 * Link in to BUGGY NMI vector
0024 2000 8e 20 30 LDX #NMI
0025 2003 bf e2 90 STX $E290
0026
0027 * Build processor state on stack
0028 2006 10 8e 20 5a LDY #RESUME
0029 200a 34 20 PSHS Y * PCL, PCH: Return address
0030 200c 8e 20 5f LDX #INITIAL
0031 200f 10 ae 81 LDY ,X++
0032 2012 34 20 PSHS Y * UL, UH
0033 2014 10 ae 81 LDY ,X++
0034 2017 34 20 PSHS Y * YL, YH
0035 2019 10 ae 81 LDY ,X++
0036 201c 34 20 PSHS Y * XL, XH
0037 201e 10 ae 81 LDY ,X++
0038 2021 34 20 PSHS Y * DP, B
0039 2023 10 ae 81 LDY ,X++
0040 2026 34 20 PSHS Y * A, CC
0041
0042 * Now the stack looks like this:
0043 *
0044 * $80 * CC -- with ENTIRE bit set <-- STACK PTR
0045 * $55 * A
0046 * $AA * B
0047 * $06 * DP |
0048 * $DE * XH | S increments
0049 * $AD * XL v
0050 * $BE * YH
0051 * $EF * YL
0052 * $CA * UH
0053 * $FE * UL
0054 * $xx * PCH - high byte of "RESUME" address
0055 * $yy * PCL - low byte of "RESUME" address
0056
0057 2028 86 10 LDA #$10 * bit 4 set
0058 202a b7 ff de STA MMUADR * trigger the NMI
0059 * should execute RTI and 1 instruction at the stacked PC then
0060 * take the NMI
0061 202d 3b RTI
0062
0063 * never come back.. but just in case.
0064 202e 20 fe ELOOP1 BRA ELOOP1
0065
0066 * NMI Service routine. Processor state is on the
0067 * stack. If all went well, we will see PC incremented
0068 * and A incremented.
0069 2030 8e 20 69 NMI LDX #FINAL
0070 2033 10 ae e4 LDY 0,S
0071 2036 10 af 81 STY ,X++ * CC A
0072 2039 10 ae 62 LDY 2,S
0073 203c 10 af 81 STY ,X++ * B DP
0074 203f 10 ae 64 LDY 4,S
0075 2042 10 af 81 STY ,X++ * X
0076 2045 10 ae 66 LDY 6,S
0077 2048 10 af 81 STY ,X++ * Y
0078 204b 10 ae 68 LDY 8,S
0079 204e 10 af 81 STY ,X++ * U
0080 2051 10 ae 6a LDY 10,S
0081 2054 10 af 81 STY ,X++ * PC
0082 * If we did an RTI now it would go back to the instruction
0083 * of the stacked PC ie RESUME+1. Instead, go back to BUGGY
0084 2057 7e e4 09 JMP $e409
0085
0086 * This is the code sequence to be executed
0087 205a 4c RESUME INCA * Should only execute this instruction
0088 205b 4c INCA
0089 205c 4c INCA
0090 205d 20 fe ELOOP2 BRA ELOOP2 * Should never get here
0091
0092 * Initial processor state.
0093 205f ca INITIAL FCB $CA * UH
0094 2060 fe FCB $FE * UL
0095 2061 be FCB $BE * YH
0096 2062 ef FCB $EF * YL
0097 2063 de FCB $DE * XH
0098 2064 ad FCB $AD * XL
0099 2065 aa FCB $AA * B
0100 2066 06 FCB $06 * DP
0101 2067 80 FCB $80 * CC -- with ENTIRE bit set
0102 2068 55 FCB $55 * A
0103
0104 * Final processor state (gets written here)
0105 2069 00 FINAL FCB $00 * CC expect 80
0106 206a 00 FCB $00 * A 56 (55 incremented)
0107 206b 00 FCB $00 * B AA
0108 206c 00 FCB $00 * DP 06
0109 206d 00 FCB $00 * XH DE
0110 206e 00 FCB $00 * XL AD
0111 206f 00 FCB $00 * YH BE
0112 2070 00 FCB $00 * YL EF
0113 2071 00 FCB $00 * UH CA
0114 2072 00 FCB $00 * UL FE
0115 2073 00 FCB $00 * PCH 20
0116 2074 00 FCB $00 * PCL 5B (205A incremented)
Here are the waveforms for an RTL simulation of the single-step operation.
This is a PNG file - you can find it here: https://github.com/nealcrook/multicomp6809/blob/master/photos/nmi_sstep.png (it doesn't seem possible to zoom in on the WIKI view).