ConDebug.c
1 /** Z80: portable Z80 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 DebugZ80() ****************************************/ 19 /** When CONDEBUG #undefined, we use plain command line. **/ 20 /*************************************************************/ 21 #include "Debug.c" 22 23 #else 24 /** Console DebugZ80() ***************************************/ 25 /** When CONDEBUG #defined, we use EMULib console. **/ 26 /*************************************************************/ 27 28 #include "Z80.h" 29 #include "Console.h" 30 #include <stdlib.h> 31 32 #define DebugZ80 OriginalDebugZ80 33 #include "Debug.c" 34 #undef DebugZ80 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 /** DebugZ80() ***********************************************/ 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 Z80 registers. **/ 51 /*************************************************************/ 52 byte DebugZ80(Z80 *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 R->Trace=0; 68 return(1); 69 } 70 71 X = ((VideoW>>3)-32)>>1; 72 Y = ((VideoH>>3)-23)>>1; 73 Addr = R->PC.W; 74 A = ~Addr; 75 K = 0; 76 77 for(DrawWindow=1,MemoryDump=ExitNow=0;!ExitNow&&VideoImg;) 78 { 79 if(DrawWindow) 80 { 81 CONWindow(X,Y,32,23,CLR_TEXT,CLR_BACK,"Z80 Debugger"); 82 83 sprintf(S,"PC %04X",R->PC.W); 84 CONSetColor(CLR_BACK,CLR_PC); 85 CONPrint(X+24,Y+18,S); 86 sprintf(S,"SP %04X",R->SP.W); 87 CONSetColor(CLR_BACK,CLR_SP); 88 CONPrint(X+24,Y+19,S); 89 90 CONSetColor(CLR_TEXT,CLR_BACK); 91 sprintf(S, 92 " %c%c%c%c%c%c\n\n" 93 "AF %04X\nBC %04X\nDE %04X\nHL %04X\nIX %04X\nIY %04X\n\n" 94 "AF'%04X\nBC'%04X\nDE'%04X\nHL'%04X\n\n" 95 "IR %02X%02X", 96 R->AF.B.l&0x80? 'S':'.',R->AF.B.l&0x40? 'Z':'.',R->AF.B.l&0x10? 'H':'.', 97 R->AF.B.l&0x04? 'P':'.',R->AF.B.l&0x02? 'N':'.',R->AF.B.l&0x01? 'C':'.', 98 R->AF.W,R->BC.W,R->DE.W,R->HL.W, 99 R->IX.W,R->IY.W, 100 R->AF1.W,R->BC1.W,R->DE1.W,R->HL1.W, 101 R->I,R->R 102 ); 103 CONPrint(X+24,Y+2,S); 104 sprintf(S, 105 "%s %s", 106 R->IFF&0x04? "IM2":R->IFF&0x02? "IM1":"IM0", 107 R->IFF&0x01? "EI":"DI" 108 ); 109 CONPrint(X+25,Y+21,S); 110 DrawWindow=0; 111 A=~Addr; 112 } 113 114 /* If top address has changed... */ 115 if(A!=Addr) 116 { 117 /* Clear display */ 118 CONBox((X+1)<<3,(Y+2)<<3,23*8,20*8,CLR_BACK); 119 120 if(MemoryDump) 121 { 122 /* Draw memory dump */ 123 for(J=0,A=Addr;J<20;J++,A+=4) 124 { 125 if(A==R->PC.W) CONSetColor(CLR_BACK,CLR_PC); 126 else if(A==R->SP.W) CONSetColor(CLR_BACK,CLR_SP); 127 else CONSetColor(CLR_TEXT,CLR_BACK); 128 sprintf(S,"%04X%c",A,A==R->PC.W? CON_MORE:A==R->SP.W? CON_LESS:':'); 129 CONPrint(X+1,Y+J+2,S); 130 131 CONSetColor(CLR_TEXT,CLR_BACK); 132 sprintf(S, 133 "%02X %02X %02X %02X %c%c%c%c", 134 RdZ80(A),RdZ80(A+1),RdZ80(A+2),RdZ80(A+3), 135 ChrDump(RdZ80(A)),ChrDump(RdZ80(A+1)), 136 ChrDump(RdZ80(A+2)),ChrDump(RdZ80(A+3)) 137 ); 138 CONPrint(X+7,Y+J+2,S); 139 } 140 } 141 else 142 { 143 /* Draw listing */ 144 for(J=0,A=Addr;J<20;J++) 145 { 146 if(A==R->PC.W) CONSetColor(CLR_BACK,CLR_PC); 147 else if(A==R->SP.W) CONSetColor(CLR_BACK,CLR_SP); 148 else CONSetColor(CLR_TEXT,CLR_BACK); 149 sprintf(S,"%04X%c",A,A==R->PC.W? CON_MORE:A==R->SP.W? CON_LESS:':'); 150 CONPrint(X+1,Y+J+2,S); 151 152 ABuf[J]=A; 153 A+=DAsm(S,A); 154 155 CONSetColor(CLR_TEXT,CLR_BACK); 156 CONPrintN(X+7,Y+J+2,S,23); 157 } 158 } 159 160 /* Display redrawn */ 161 A=Addr; 162 } 163 164 /* Draw pointer */ 165 CONChar(X+6,Y+K+2,CON_ARROW); 166 167 /* Show screen buffer */ 168 ShowVideo(); 169 170 /* Get key code */ 171 I=WaitKey(); 172 173 /* Clear pointer */ 174 CONChar(X+6,Y+K+2,' '); 175 176 /* Get and process key code */ 177 switch(I) 178 { 179 case 'H': 180 CONMsg( 181 -1,-1,-1,-1, 182 CLR_BACK,CLR_DIALOG, 183 "Debugger Help", 184 "ENTER - Execute next opcode\0" 185 " UP - Previous opcode\0" 186 " DOWN - Next opcode\0" 187 " LEFT - Page up\0" 188 "RIGHT - Page down\0" 189 " H - This help page\0" 190 " G - Go to address\0" 191 " D - Disassembler view\0" 192 " M - Memory dump view\0" 193 " S - Show stack\0" 194 " J - Jump to cursor\0" 195 " R - Run to cursor\0" 196 " C - Continue execution\0" 197 " Q - Quit emulator\0" 198 ); 199 DrawWindow=1; 200 break; 201 case CON_UP: 202 if(K) --K; 203 else 204 if(MemoryDump) Addr-=4; 205 else for(--Addr;Addr+DAsm(S,Addr)>A;--Addr); 206 break; 207 case CON_DOWN: 208 if(K<19) ++K; 209 else 210 if(MemoryDump) Addr+=4; 211 else Addr+=DAsm(S,Addr); 212 break; 213 case CON_LEFT: 214 if(MemoryDump) 215 Addr-=4*20; 216 else 217 { 218 for(I=20,Addr=~A;(Addr>A)||((A^Addr)&~Addr&0x8000);++I) 219 for(J=0,Addr=A-I;J<20;++J) Addr+=DAsm(S,Addr); 220 Addr=A-I+1; 221 } 222 break; 223 case CON_RIGHT: 224 if(MemoryDump) 225 Addr+=4*20; 226 else 227 for(J=0;J<20;++J) Addr+=DAsm(S,Addr); 228 break; 229 case CON_OK: 230 ExitNow=1; 231 break; 232 case 'Q': 233 return(0); 234 case CON_EXIT: 235 case 'C': 236 R->Trap=0xFFFF; 237 R->Trace=0; 238 ExitNow=1; 239 break; 240 case 'R': 241 R->Trap=ABuf[K]; 242 R->Trace=0; 243 ExitNow=1; 244 break; 245 case 'M': 246 MemoryDump=1; 247 A=~Addr; 248 break; 249 case 'S': 250 MemoryDump=1; 251 Addr=R->SP.W; 252 K=0; 253 A=~Addr; 254 break; 255 case 'D': 256 MemoryDump=0; 257 A=~Addr; 258 break; 259 case 'G': 260 if(CONInput(-1,-1,CLR_BACK,CLR_DIALOG,"Go to Address:",S,5|CON_HEX)) 261 { Addr=strtol(S,0,16);K=0; } 262 DrawWindow=1; 263 break; 264 case 'J': 265 R->PC.W=ABuf[K]; 266 A=~Addr; 267 break; 268 } 269 } 270 271 /* Continue emulation */ 272 return(1); 273 } 274 275 #endif /* CONDEBUG */ 276 #endif /* DEBUG */