1 |
dpavlin |
23 |
/** M6502: portable 6502 emulator ****************************/ |
2 |
|
|
/** **/ |
3 |
|
|
/** ConDebug.c **/ |
4 |
|
|
/** **/ |
5 |
|
|
/** This file contains a console version of the built-in **/ |
6 |
|
|
/** debugger, using EMULib's Console.c. When -DCONDEBUG is **/ |
7 |
|
|
/** ommitted, ConDebug.c just includes the default command **/ |
8 |
|
|
/** line based debugger (Debug.c). **/ |
9 |
|
|
/** **/ |
10 |
|
|
/** Copyright (C) Marat Fayzullin 2005-2007 **/ |
11 |
|
|
/** You are not allowed to distribute this software **/ |
12 |
|
|
/** commercially. Please, notify me, if you make any **/ |
13 |
|
|
/** changes to this file. **/ |
14 |
|
|
/*************************************************************/ |
15 |
|
|
#ifdef DEBUG |
16 |
|
|
|
17 |
|
|
#ifndef CONDEBUG |
18 |
|
|
/** Normal Debug6502() ***************************************/ |
19 |
|
|
/** When CONDEBUG #undefined, we use plain command line. **/ |
20 |
|
|
/*************************************************************/ |
21 |
|
|
#include "Debug.c" |
22 |
|
|
|
23 |
|
|
#else |
24 |
|
|
/** Console Debug6502() **************************************/ |
25 |
|
|
/** When CONDEBUG #defined, we use EMULib console. **/ |
26 |
|
|
/*************************************************************/ |
27 |
|
|
|
28 |
|
|
#include "M6502.h" |
29 |
|
|
#include "Console.h" |
30 |
|
|
#include <stdlib.h> |
31 |
|
|
|
32 |
|
|
#define Debug6502 OriginalDebug6502 |
33 |
|
|
#include "Debug.c" |
34 |
|
|
#undef Debug6502 |
35 |
|
|
|
36 |
|
|
#define CLR_BACK PIXEL(255,255,255) |
37 |
|
|
#define CLR_TEXT PIXEL(0,0,0) |
38 |
|
|
#define CLR_DIALOG PIXEL(0,100,0) |
39 |
|
|
#define CLR_PC PIXEL(255,0,0) |
40 |
|
|
#define CLR_SP PIXEL(0,0,100) |
41 |
|
|
|
42 |
|
|
static byte ChrDump(byte C) |
43 |
|
|
{ |
44 |
|
|
return((C>=32)&&(C<128)? C:'.'); |
45 |
|
|
} |
46 |
|
|
|
47 |
|
|
/** Debug6502() **********************************************/ |
48 |
|
|
/** This function should exist if DEBUG is #defined. When **/ |
49 |
|
|
/** Trace!=0, it is called after each command executed by **/ |
50 |
|
|
/** the CPU, and given the 6502 registers. **/ |
51 |
|
|
/*************************************************************/ |
52 |
|
|
byte Debug6502(M6502 *R) |
53 |
|
|
{ |
54 |
|
|
char S[1024]; |
55 |
|
|
word A,Addr,ABuf[20]; |
56 |
|
|
int J,I,K,X,Y,MemoryDump,DrawWindow,ExitNow; |
57 |
|
|
|
58 |
|
|
/* If we don't have enough screen estate... */ |
59 |
|
|
if((VideoW<32*8)||(VideoH<23*8)) |
60 |
|
|
{ |
61 |
|
|
/* Show warning message */ |
62 |
|
|
CONMsg( |
63 |
|
|
-1,-1,-1,-1,PIXEL(255,255,255),PIXEL(255,0,0), |
64 |
|
|
"Error","Screen is\0too small!\0\0" |
65 |
|
|
); |
66 |
|
|
/* Continue emulation */ |
67 |
|
|
return(1); |
68 |
|
|
} |
69 |
|
|
|
70 |
|
|
X = ((VideoW>>3)-30)>>1; |
71 |
|
|
Y = ((VideoH>>3)-25)>>1; |
72 |
|
|
Addr = R->PC.W; |
73 |
|
|
A = ~Addr; |
74 |
|
|
K = 0; |
75 |
|
|
|
76 |
|
|
for(DrawWindow=1,MemoryDump=ExitNow=0;!ExitNow&&VideoImg;) |
77 |
|
|
{ |
78 |
|
|
if(DrawWindow) |
79 |
|
|
{ |
80 |
|
|
CONWindow(X,Y,30,25,CLR_TEXT,CLR_BACK,"6502 Debugger"); |
81 |
|
|
|
82 |
|
|
sprintf(S,"PC:%04X",R->PC.W); |
83 |
|
|
CONSetColor(CLR_BACK,CLR_PC); |
84 |
|
|
CONPrint(X+1,Y+2,S); |
85 |
|
|
sprintf(S,"SP:%04X",R->S+0x100); |
86 |
|
|
CONSetColor(CLR_BACK,CLR_SP); |
87 |
|
|
CONPrint(X+9,Y+2,S); |
88 |
|
|
CONPrint(X+25,Y+8,"STCK"); |
89 |
|
|
|
90 |
|
|
sprintf(S,"P:[%c%c%c%c%c%c%c%c]", |
91 |
|
|
R->P&0x80? 'N':'.', |
92 |
|
|
R->P&0x40? 'V':'.', |
93 |
|
|
R->P&0x20? 'R':'.', |
94 |
|
|
R->P&0x10? 'B':'.', |
95 |
|
|
R->P&0x08? 'D':'.', |
96 |
|
|
R->P&0x04? 'I':'.', |
97 |
|
|
R->P&0x02? 'Z':'.', |
98 |
|
|
R->P&0x01? 'C':'.' |
99 |
|
|
); |
100 |
|
|
CONSetColor(CLR_BACK,CLR_DIALOG); |
101 |
|
|
CONPrint(X+17,Y+2,S); |
102 |
|
|
|
103 |
|
|
sprintf(S,"A:%02X\nX:%02X\nY:%02X",R->A,R->X,R->Y); |
104 |
|
|
CONSetColor(CLR_TEXT,CLR_BACK); |
105 |
|
|
CONPrint(X+25,Y+4,S); |
106 |
|
|
|
107 |
|
|
for(J=0;J<15;++J) |
108 |
|
|
{ |
109 |
|
|
sprintf(S,"%02X",Rd6502(0x0100+(byte)(R->S+J+1))); |
110 |
|
|
CONPrint(X+26,Y+J+9,S); |
111 |
|
|
} |
112 |
|
|
|
113 |
|
|
DrawWindow=0; |
114 |
|
|
A=~Addr; |
115 |
|
|
} |
116 |
|
|
|
117 |
|
|
/* If top address has changed... */ |
118 |
|
|
if(A!=Addr) |
119 |
|
|
{ |
120 |
|
|
/* Clear display */ |
121 |
|
|
CONBox((X+1)<<3,(Y+4)<<3,23*8,20*8,CLR_BACK); |
122 |
|
|
|
123 |
|
|
if(MemoryDump) |
124 |
|
|
{ |
125 |
|
|
/* Draw memory dump */ |
126 |
|
|
for(J=0,A=Addr;J<20;J++,A+=4) |
127 |
|
|
{ |
128 |
|
|
if(A==R->PC.W) CONSetColor(CLR_BACK,CLR_PC); |
129 |
|
|
else if(A==R->S+0x100) CONSetColor(CLR_BACK,CLR_SP); |
130 |
|
|
else CONSetColor(CLR_TEXT,CLR_BACK); |
131 |
|
|
sprintf(S,"%04X%c",A,A==R->PC.W? CON_MORE:A==R->S+0x100? CON_LESS:':'); |
132 |
|
|
CONPrint(X+1,Y+J+4,S); |
133 |
|
|
|
134 |
|
|
CONSetColor(CLR_TEXT,CLR_BACK); |
135 |
|
|
sprintf(S, |
136 |
|
|
"%02X %02X %02X %02X %c%c%c%c", |
137 |
|
|
Rd6502(A),Rd6502(A+1),Rd6502(A+2),Rd6502(A+3), |
138 |
|
|
ChrDump(Rd6502(A)),ChrDump(Rd6502(A+1)), |
139 |
|
|
ChrDump(Rd6502(A+2)),ChrDump(Rd6502(A+3)) |
140 |
|
|
); |
141 |
|
|
CONPrint(X+7,Y+J+4,S); |
142 |
|
|
} |
143 |
|
|
} |
144 |
|
|
else |
145 |
|
|
{ |
146 |
|
|
/* Draw listing */ |
147 |
|
|
for(J=0,A=Addr;J<20;J++) |
148 |
|
|
{ |
149 |
|
|
if(A==R->PC.W) CONSetColor(CLR_BACK,CLR_PC); |
150 |
|
|
else if(A==R->S+0x100) CONSetColor(CLR_BACK,CLR_SP); |
151 |
|
|
else CONSetColor(CLR_TEXT,CLR_BACK); |
152 |
|
|
sprintf(S,"%04X%c",A,A==R->PC.W? CON_MORE:A==R->S+0x100? CON_LESS:':'); |
153 |
|
|
CONPrint(X+1,Y+J+4,S); |
154 |
|
|
|
155 |
|
|
ABuf[J]=A; |
156 |
|
|
A+=DAsm(S,A); |
157 |
|
|
|
158 |
|
|
CONSetColor(CLR_TEXT,CLR_BACK); |
159 |
|
|
CONPrintN(X+7,Y+J+4,S,17); |
160 |
|
|
} |
161 |
|
|
} |
162 |
|
|
|
163 |
|
|
/* Display redrawn */ |
164 |
|
|
A=Addr; |
165 |
|
|
} |
166 |
|
|
|
167 |
|
|
/* Draw pointer */ |
168 |
|
|
CONChar(X+6,Y+K+4,CON_ARROW); |
169 |
|
|
|
170 |
|
|
/* Show screen buffer */ |
171 |
|
|
ShowVideo(); |
172 |
|
|
|
173 |
|
|
/* Get key code */ |
174 |
|
|
I=WaitKey(); |
175 |
|
|
|
176 |
|
|
/* Clear pointer */ |
177 |
|
|
CONChar(X+6,Y+K+4,' '); |
178 |
|
|
|
179 |
|
|
/* Get and process key code */ |
180 |
|
|
switch(I) |
181 |
|
|
{ |
182 |
|
|
case 'H': |
183 |
|
|
CONMsg( |
184 |
|
|
-1,-1,-1,-1, |
185 |
|
|
CLR_BACK,CLR_DIALOG, |
186 |
|
|
"Debugger Help", |
187 |
|
|
"ENTER - Execute next opcode\0" |
188 |
|
|
" UP - Previous opcode\0" |
189 |
|
|
" DOWN - Next opcode\0" |
190 |
|
|
" LEFT - Page up\0" |
191 |
|
|
"RIGHT - Page down\0" |
192 |
|
|
" H - This help page\0" |
193 |
|
|
" G - Go to address\0" |
194 |
|
|
" D - Disassembler view\0" |
195 |
|
|
" M - Memory dump view\0" |
196 |
|
|
" S - Show stack\0" |
197 |
|
|
" J - Jump to cursor\0" |
198 |
|
|
" R - Run to cursor\0" |
199 |
|
|
" C - Continue execution\0" |
200 |
|
|
" Q - Quit emulator\0" |
201 |
|
|
); |
202 |
|
|
DrawWindow=1; |
203 |
|
|
break; |
204 |
|
|
case CON_UP: |
205 |
|
|
if(K) --K; |
206 |
|
|
else |
207 |
|
|
if(MemoryDump) Addr-=4; |
208 |
|
|
else for(--Addr;Addr+DAsm(S,Addr)>A;--Addr); |
209 |
|
|
break; |
210 |
|
|
case CON_DOWN: |
211 |
|
|
if(K<19) ++K; |
212 |
|
|
else |
213 |
|
|
if(MemoryDump) Addr+=4; |
214 |
|
|
else Addr+=DAsm(S,Addr); |
215 |
|
|
break; |
216 |
|
|
case CON_LEFT: |
217 |
|
|
if(MemoryDump) |
218 |
|
|
Addr-=4*20; |
219 |
|
|
else |
220 |
|
|
{ |
221 |
|
|
for(I=20,Addr=~A;(Addr>A)||((A^Addr)&~Addr&0x8000);++I) |
222 |
|
|
for(J=0,Addr=A-I;J<20;++J) Addr+=DAsm(S,Addr); |
223 |
|
|
Addr=A-I+1; |
224 |
|
|
} |
225 |
|
|
break; |
226 |
|
|
case CON_RIGHT: |
227 |
|
|
if(MemoryDump) |
228 |
|
|
Addr+=4*20; |
229 |
|
|
else |
230 |
|
|
for(J=0;J<20;++J) Addr+=DAsm(S,Addr); |
231 |
|
|
break; |
232 |
|
|
case CON_OK: |
233 |
|
|
ExitNow=1; |
234 |
|
|
break; |
235 |
|
|
case 'Q': |
236 |
|
|
return(0); |
237 |
|
|
case CON_EXIT: |
238 |
|
|
case 'C': |
239 |
|
|
R->Trap=0xFFFF; |
240 |
|
|
R->Trace=0; |
241 |
|
|
ExitNow=1; |
242 |
|
|
break; |
243 |
|
|
case 'R': |
244 |
|
|
R->Trap=ABuf[K]; |
245 |
|
|
R->Trace=0; |
246 |
|
|
ExitNow=1; |
247 |
|
|
break; |
248 |
|
|
case 'M': |
249 |
|
|
MemoryDump=1; |
250 |
|
|
A=~Addr; |
251 |
|
|
break; |
252 |
|
|
case 'S': |
253 |
|
|
MemoryDump=1; |
254 |
|
|
Addr=R->S+0x100; |
255 |
|
|
K=0; |
256 |
|
|
A=~Addr; |
257 |
|
|
break; |
258 |
|
|
case 'D': |
259 |
|
|
MemoryDump=0; |
260 |
|
|
A=~Addr; |
261 |
|
|
break; |
262 |
|
|
case 'G': |
263 |
|
|
if(CONInput(-1,-1,CLR_BACK,CLR_DIALOG,"Go to Address:",S,5|CON_HEX)) |
264 |
|
|
{ Addr=strtol(S,0,16);K=0; } |
265 |
|
|
DrawWindow=1; |
266 |
|
|
break; |
267 |
|
|
case 'J': |
268 |
|
|
R->PC.W=ABuf[K]; |
269 |
|
|
A=~Addr; |
270 |
|
|
break; |
271 |
|
|
} |
272 |
|
|
} |
273 |
|
|
|
274 |
|
|
/* Continue emulation */ |
275 |
|
|
return(1); |
276 |
|
|
} |
277 |
|
|
|
278 |
|
|
#endif /* CONDEBUG */ |
279 |
|
|
#endif /* DEBUG */ |