1 /***************************************************************************
3 * ZXEmuT -- ZX Spectrum Emulator with Tcl scripting
5 * Copyright (C) 2012-2020 Ketmar Dark <ketmar@ketmar.no-ip.org>
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **************************************************************************/
20 //#define USE_URASM_DISASM
22 #include "../libzymosis/zymosis.h"
23 #ifdef USE_URASM_DISASM
24 # include "../liburasm/liburasm.h"
26 # include "../libzymosis/zymosis_utils.h"
28 #include "libvideo/video.h"
30 #include "emucommon.h"
34 #include "zxscrdraw.h"
39 ////////////////////////////////////////////////////////////////////////////////
40 int debuggerActive
= 0;
46 static int dbgAllowLabels
= 0x03;
48 static uint8_t dbgBreakpoints
[65536]; //FIXME: for 128
51 ////////////////////////////////////////////////////////////////////////////////
52 //static VOverlay *dbgOverlay = NULL;
53 static uint16_t dbgUnasmTop
= 0;
54 static uint16_t dbgAddrSkip
= 0;
55 //static uint16_t dbgCurAddr = 0;
56 static uint16_t dbgPageAddrs
[32];
57 static int dbgPageY
= 0;
58 static int dbgHidden
= 0;
59 static int offsetLabels
= 1;
60 static int dbgMemMode
= 1;
63 typedef int (*KeyEventCB
) (SDL_KeyboardEvent
*key
);
64 typedef void (*DrawOverlayCB
) (void);
66 static KeyEventCB dbgKeyEventFn
= NULL
;
67 static DrawOverlayCB dbgDrawOverlayFn
= NULL
;
70 #define DBG_UNASM_HEIGHT (VID_TEXT_HEIGHT-5)
73 ////////////////////////////////////////////////////////////////////////////////
74 typedef struct DebugLabelT
{
75 char *name
; /* malloced */
76 int value
; /* [0..65535] */
78 struct DebugLabelT
*nextBucket
; /* in bucket */
79 struct DebugLabelT
*nextName
; /* list of all known labels */
82 /*TODO: faster searching by name */
83 static DebugLabel
*labelBuckets
[65536];
84 static DebugLabel
*labelHead
= NULL
;
85 static DebugLabel
*labelTail
= NULL
;
87 static __attribute__((constructor
)) void dbgInitLabelsCtor (void) {
88 for (unsigned f
= 0; f
< 65536; ++f
) labelBuckets
[f
] = NULL
;
92 void dbgClearLabels (void) {
93 for (unsigned f
= 0; f
< 65536; ++f
) labelBuckets
[f
] = NULL
;
95 DebugLabel
*l
= labelHead
;
96 labelHead
= l
->nextName
;
100 labelHead
= labelTail
= NULL
;
104 static DebugLabel
*dbgFindLabelByNameIntr (const char *name
, DebugLabel
**prevp
) {
105 if (prevp
) *prevp
= NULL
;
106 if (!name
|| !name
[0]) return NULL
;
107 DebugLabel
*prev
= NULL
;
108 for (DebugLabel
*curr
= labelHead
; curr
; prev
= curr
, curr
= curr
->nextName
) {
109 if (strcasecmp(curr
->name
, name
) == 0) {
110 if (prevp
) *prevp
= prev
;
118 static void dbgRemoveLabelIntr (DebugLabel
*prev
, DebugLabel
*curr
) {
119 if (!curr
) return; // just in case
120 /* remove from linked list */
121 if (prev
) prev
->nextName
= curr
->nextName
; else labelHead
= curr
->nextName
;
122 if (!curr
->nextName
) labelTail
= prev
;
123 /* remove from bucket */
125 for (DebugLabel
*cc
= labelBuckets
[curr
->value
]; cc
; prev
= cc
, cc
= cc
->nextBucket
) {
128 if (prev
) prev
->nextBucket
= cc
->nextBucket
; else labelBuckets
[curr
->value
] = cc
->nextBucket
;
132 /* we can free it here */
138 int dbgFindLabelByName (const char *name
) {
139 DebugLabel
*lbl
= dbgFindLabelByNameIntr(name
, NULL
);
140 return (lbl
? lbl
->value
: -1);
144 const char *dbgFindLabelByVal (int val
, int asoffset
) {
145 if (val
< 0 || val
> 65535) return NULL
;
146 for (DebugLabel
*lbl
= labelBuckets
[val
]; lbl
; lbl
= lbl
->nextBucket
) {
147 if (lbl
->value
== val
&& lbl
->asoffset
== asoffset
) return lbl
->name
;
153 void dbgAddLabel (int addr
, const char *name
, int asoffset
) {
154 if (addr
< 0 || addr
> 65535 || !name
|| !name
[0]) return;
155 DebugLabel
*prev
= NULL
;
156 DebugLabel
*lbl
= dbgFindLabelByNameIntr(name
, &prev
);
158 if (lbl
->value
== addr
) {
160 lbl
->asoffset
= asoffset
;
161 strcpy(lbl
->name
, name
);
164 /* remove it, so it will be readded */
165 dbgRemoveLabelIntr(prev
, lbl
);
166 /* remove label with the same value, if there is any */
168 lbl = dbgFindLabelByVal(addr);
170 lbl = dbgFindLabelByNameIntr(lbl->name, &prev);
171 dbgRemoveLabelIntr(prev, lbl);
175 /* it is guaranteed to be a new label */
176 lbl
= malloc(sizeof(DebugLabel
));
177 lbl
->name
= strdup(name
);
179 lbl
->asoffset
= asoffset
;
180 lbl
->nextBucket
= NULL
;
181 lbl
->nextName
= NULL
;
183 if (labelTail
) labelTail
->nextName
= lbl
; else labelHead
= lbl
;
186 prev
= labelBuckets
[addr
];
188 while (prev
->nextBucket
) prev
= prev
->nextBucket
;
189 prev
->nextBucket
= lbl
;
191 labelBuckets
[addr
] = lbl
;
196 void dbgRemoveLabel (const char *name
) {
198 DebugLabel
*lbl
= dbgFindLabelByNameIntr(name
, &prev
);
199 if (lbl
) dbgRemoveLabelIntr(prev
, lbl
);
204 int dbgSaveRefFile (const char *fname
) {
205 if (!fname
|| !fname
[0]) return -1;
206 FILE *fo
= fopen(fname
, "w");
208 for (DebugLabel
*curr
= labelHead
; curr
; curr
= curr
->nextName
) {
209 if (fprintf(fo
, "#%04X %s\n", curr
->value
, curr
->name
) < 0) {
214 return (fclose(fo
) ? -4 : 0);
218 static __attribute__((always_inline
)) inline int digitInBase (char ch
, int base
) {
219 if (!ch
|| base
< 1) return -1;
220 if (ch
>= '0' && ch
<= '9') {
222 return (ch
< base
? ch
: -1);
224 if (base
<= 10) return -1;
225 if (ch
>= 'a' && ch
<= 'z') ch
-= 'a';
226 else if (ch
>= 'A' && ch
<= 'Z') ch
-= 'A';
229 return (ch
< base
? ch
: -1);
234 int dbgLoadRefFile (const char *fname
) {
235 if (!fname
|| !fname
[0]) return -1;
236 FILE *fl
= fopen(fname
, "r");
241 while (fgets(line
, (int)sizeof(line
)-2, fl
) != NULL
) {
242 size_t slen
= strlen(line
);
243 if (slen
== 0) { ignoreLine
= 1; continue; }
244 const int eol
= (line
[slen
-1] == '\n' || line
[slen
-1] == '\r');
245 if (ignoreLine
) { ignoreLine
= !eol
; continue; }
248 /* remove comments */
250 char *cmt
= strchr(line
, ';');
256 cmt
= strstr(line
, "//");
265 /* remove trailing spaces */
266 while (slen
> 0 && (unsigned)(line
[slen
-1]&0xff) <= 32) --slen
;
267 if (slen
== 0) continue;
270 /* remove leading spaces */
272 while (line
[slen
] && (unsigned)(line
[slen
]&0xff) <= 32) ++slen
;
273 if (!line
[slen
]) continue; /* empty line */
274 memmove(line
, line
+slen
, strlen(line
+slen
)+1);
279 if (line
[0] == '$' || line
[0] == '#' || (line
[0] == '0' && (line
[1] == 'x' || line
[1] == 'X'))) {
281 pos
= (line
[0] == '0' ? 2 : 1);
283 } else if (digitInBase(line
[0], 10)) {
289 if (digitInBase(line
[pos
], base
) < 0) continue;
292 int d
= digitInBase(line
[pos
], base
);
295 if (val
> 65535) break;
298 if (val
> 65535 || !line
[pos
] || (unsigned)(line
[pos
]&0xff) > 32) continue;
299 while (line
[pos
] && (unsigned)(line
[pos
]&0xff) <= 32) ++pos
;
300 if (!line
[pos
]) continue; /* empty line */
301 memmove(line
, line
+pos
, strlen(line
+pos
)+1);
304 while (line
[pos
] && (unsigned)(line
[pos
]&0xff) > 32) ++pos
;
305 const char occ
= line
[pos
];
307 //fprintf(stderr, "NEW LABEL: #%04X <%s>\n", (unsigned)val, line);
308 // ignore labels starting with "__", or ending with "_"
309 // nope, add "X...__" labels as offsets (my convention)
310 const char *lbltype
= "";
312 lbltype
= line
+pos
+1;
313 while (*lbltype
&& (unsigned)(*lbltype
&0xff) <= 32) ++lbltype
;
315 // ignore "equ" labels
316 if (strcmp(lbltype
, "equ") == 0) continue;
318 if (pos
> 3 && line
[0] != '_' && line
[pos
-1] == '_' && line
[pos
-2] == '_') {
319 dbgAddLabel(val
, line
, 1/*asoffset*/);
322 if (pos
>= 2 && line
[0] == '_' && line
[1] == '_') continue;
323 if (pos
== 1 && line
[0] == '_') continue;
324 if (pos
> 1 && line
[pos
-1] == '_') continue;
325 if (strcmp(lbltype
, "stofs") == 0) {
326 dbgAddLabel(val
, line
, 1/*asoffset*/);
328 dbgAddLabel(val
, line
, 0/*asoffset*/);
336 void dbgIteratorFree (void *it
) {
337 /* nothing to do here */
341 static int xstrStartsWithCI (const char *s0
, const char *s1
) {
342 if (!s0
|| !s1
|| !s0
[0] || !s1
[0]) return 0;
346 if (c0
>= 'a' && c0
<= 'z') c0
= c0
-'a'+'A';
348 if (c1
>= 'a' && c1
<= 'z') c1
= c1
-'a'+'A';
349 if (c0
!= c1
) return 0;
356 void *dbgFirstLabelByPrefix (const char *pfx
) {
357 if (!pfx
|| !pfx
[0]) return NULL
;
358 for (DebugLabel
*lbl
= labelHead
; lbl
; lbl
= lbl
->nextName
) {
359 if (xstrStartsWithCI(lbl
->name
, pfx
)) return lbl
;
365 void *dbgNextLabelByPrefix (void *it
, const char *pfx
) {
366 if (!it
|| !pfx
|| !pfx
[0]) return NULL
;
367 DebugLabel
*lbl
= (DebugLabel
*)it
;
368 for (lbl
= lbl
->nextName
; lbl
; lbl
= lbl
->nextName
) {
369 if (xstrStartsWithCI(lbl
->name
, pfx
)) return lbl
;
375 const char *dbgIteratorLabelName (const void *it
) {
376 if (!it
) return NULL
;
377 const DebugLabel
*lbl
= (const DebugLabel
*)it
;
382 #ifdef USE_URASM_DISASM
385 static const char *dbgZymGetLabel (uint16_t value
, int type
/*ZYM_DIS_ATYPE_XXX*/) {
386 if ((dbgAllowLabels
&1) == 0) return NULL
;
387 // it is safe to use static buffer here
388 static char namebuf
[128];
389 if (type
== ZYM_DIS_ATYPE_WORD
|| type
== ZYM_DIS_ATYPE_PC_ADDR
||
390 type
== ZYM_DIS_ATYPE_DATA_ADDR
)
392 /* \x01: label start; \x02: label end */
393 const char *n
= dbgFindLabelByVal(value
, 0/*asoffset*/);
396 strncpy(namebuf
+1, n
, sizeof(namebuf
)-2);
397 namebuf
[sizeof(namebuf
)-1] = 0;
398 namebuf
[sizeof(namebuf
)-2] = 0;
399 strcat(namebuf
, "\x01");
402 } else if (type
== ZYM_DIS_ATYPE_OFFSET
&& offsetLabels
) {
403 /* \x01: label start; \x02: label end */
405 const char *n
= dbgFindLabelByVal(value
, 1/*asoffset*/);
406 if (!n
) { ofs
= 1; n
= dbgFindLabelByVal(value
+1, 1/*asoffset*/); }
407 if (!n
) { ofs
= 2; n
= dbgFindLabelByVal(value
+2, 1/*asoffset*/); }
408 if (!n
) { ofs
= -1; n
= dbgFindLabelByVal(value
-1, 1/*asoffset*/); }
409 if (!n
) { ofs
= -2; n
= dbgFindLabelByVal(value
-2, 1/*asoffset*/); }
410 //if (!n) { ofs = 3; n = dbgFindLabelByVal(value+3, 1/*asoffset*/); }
413 snprintf(namebuf
, sizeof(namebuf
), "\x02%s%d%s", (ofs
< 0 ? "" : "+"), ofs
, n
);
415 snprintf(namebuf
, sizeof(namebuf
), "\x02%s", n
);
419 strncpy(namebuf+1, n, sizeof(namebuf)-2);
421 namebuf
[sizeof(namebuf
)-1] = 0;
422 namebuf
[sizeof(namebuf
)-2] = 0;
423 strcat(namebuf
, "\x01");
432 ////////////////////////////////////////////////////////////////////////////////
433 static int dbgKeyEventMain (SDL_KeyboardEvent
*key
);
434 static int dbgKeyEventNewAddr (SDL_KeyboardEvent
*key
);
437 ////////////////////////////////////////////////////////////////////////////////
440 zym_regpair_t bc
, de
, hl
, af
, sp
, ix
, iy
;
441 zym_regpair_t bcx
, dex
, hlx
, afx
;
449 static void dbgSaveRegs (void) {
450 oldDState
.pc
= z80
.pc
;
451 oldDState
.bc
.w
= z80
.bc
.w
;
452 oldDState
.de
.w
= z80
.de
.w
;
453 oldDState
.hl
.w
= z80
.hl
.w
;
454 oldDState
.af
.w
= z80
.af
.w
;
455 oldDState
.sp
.w
= z80
.sp
.w
;
456 oldDState
.ix
.w
= z80
.ix
.w
;
457 oldDState
.iy
.w
= z80
.iy
.w
;
458 oldDState
.bcx
.w
= z80
.bcx
.w
;
459 oldDState
.dex
.w
= z80
.dex
.w
;
460 oldDState
.hlx
.w
= z80
.hlx
.w
;
461 oldDState
.afx
.w
= z80
.afx
.w
;
462 oldDState
.regI
= z80
.regI
;
463 oldDState
.regR
= z80
.regR
;
464 oldDState
.iff1
= z80
.iff1
;
465 oldDState
.iff2
= z80
.iff2
;
466 oldDState
.im
= z80
.im
;
473 void dbgInit (void) {
474 memset(dbgBreakpoints
, 0, sizeof(dbgBreakpoints
));
478 ////////////////////////////////////////////////////////////////////////////////
480 static void dbgDrawrClear (void) {
481 clearVO(dbgOverlay, 255); // transparent
485 static void dbgDrawRect (int x, int y, int w, int h, Uint8 bg, Uint8 fc) {
486 if (bg != 255) fillRectVO(dbgOverlay, x, y, w, h, bg);
487 if (fc != 255) drawFrameVO(dbgOverlay, x+1, y+1, w-2, h-2, fc);
492 ////////////////////////////////////////////////////////////////////////////////
493 static void dbgDrawStack (int x
, int y
) {
496 dbgDrawRect(x
, y
, 10*6+10, 4*8+6, 0, 7);
500 addr
= (addr
-4)&0xffff;
501 for (int f
= 0; f
< 8; ++f
) {
502 Uint8 fc
= (f
< 2 ? 7: f
> 2 ? 70 : 15);
504 snprintf(buf
, sizeof(buf
), "#%02X", z80
.mem_read(&z80
, (addr
+1)&0xffff, ZYM_MEMIO_OTHER
));
505 snprintf(buf
+3, sizeof(buf
)-3, "%02X", z80
.mem_read(&z80
, addr
, ZYM_MEMIO_OTHER
));
506 addr
= (addr
+2)&0xffff;
507 drawStr6VO(dbgOverlay
, buf
, x
+(f
< 4 ? 0 : 5*6+4), y
+8*(f
&0x03), fc
, 255);
512 addr
= (addr
-8)&0xffff;
513 vt_writechars(x
, y
+0, 5*3, ' ', 7);
514 vt_writechars(x
, y
+1, 5*3, ' ', 7);
515 vt_writechars(x
, y
+2, 5*3, ' ', 7);
516 vt_writechars(x
, y
+3, 5*3, ' ', 7);
517 for (int f
= 0; f
< 12; ++f
) {
518 Uint8 fc
= (f
< 2+4 ? 7: f
> 2+4 ? 5 : 15);
520 snprintf(buf
, sizeof(buf
), "#%02X", z80
.mem_read(&z80
, (addr
+1)&0xffff, ZYM_MEMIO_OTHER
));
521 snprintf(buf
+3, sizeof(buf
)-3, "%02X", z80
.mem_read(&z80
, addr
, ZYM_MEMIO_OTHER
));
522 addr
= (addr
+2)&0xffff;
523 vt_writestrz(x
+(f
< 4 ? 0 : f
< 8 ? 6 : 12), y
+(f
&0x03), buf
, fc
);
529 static void dbgDrawMemBytes (int x
, int y
, uint16_t addr
) {
531 addr
= (addr
-8)&0xffff;
533 vt_writechars(x, y+0, 5*3, ' ', 7);
534 vt_writechars(x, y+1, 5*3, ' ', 7);
535 vt_writechars(x, y+2, 5*3, ' ', 7);
536 vt_writechars(x, y+3, 5*3, ' ', 7);
538 for (int dy
= 0; dy
< 4; ++dy
) {
539 uint8_t bc
= (dy
== 1 ? 1 : 0);
540 snprintf(buf
, sizeof(buf
), "%04X", addr
);
541 vt_writestrz(x
, y
+dy
, buf
, (0)|(5<<4));
542 for (int dx
= 0; dx
< 8; ++dx
) {
543 uint8_t fc
= (dx
&1 ? 5 : 7);
544 snprintf(buf
, sizeof(buf
), "%02X", z80
.mem_read(&z80
, addr
, ZYM_MEMIO_OTHER
));
545 addr
= (addr
+1)&0xffff;
546 vt_writestrz(x
+4+dx
*2, y
+dy
, buf
, fc
|(bc
<<4));
552 static void dbgDrawMemBytesChars (int x
, int y
, uint16_t addr
) {
554 addr
= (addr
-4)&0xffff;
555 vt_writechars(x
, y
+0, 20, ' ', 0x07);
556 vt_writechars(x
, y
+1, 20, ' ', 0x17);
557 vt_writechars(x
, y
+2, 20, ' ', 0x07);
558 vt_writechars(x
, y
+3, 20, ' ', 0x07);
559 for (int dy
= 0; dy
< 4; ++dy
) {
560 uint8_t bc
= (dy
== 1 ? 1 : 0);
561 snprintf(buf
, sizeof(buf
), "%04X", addr
);
562 vt_writestrz(x
, y
+dy
, buf
, (0)|(5<<4));
563 for (int dx
= 0; dx
< 4; ++dx
) {
564 uint8_t b
= z80
.mem_read(&z80
, addr
, ZYM_MEMIO_OTHER
);
565 uint8_t fc
= (dx
&1 ? 5 : 7);
566 snprintf(buf
, sizeof(buf
), "%02X", b
);
567 addr
= (addr
+1)&0xffff;
568 vt_writestrz(x
+5+dx
*2, y
+dy
, buf
, fc
|(bc
<<4));
569 vt_writechar(x
+7+4*2+dx
, y
+dy
, b
, fc
|(bc
<<4));
575 static void dbgDrawMemBytes6 (int x
, int y
, uint16_t addr
) {
577 addr
= (addr
-6)&0xffff;
578 vt_writechars(x
, y
+0, 20, ' ', 0x07);
579 vt_writechars(x
, y
+1, 20, ' ', 0x17);
580 vt_writechars(x
, y
+2, 20, ' ', 0x07);
581 vt_writechars(x
, y
+3, 20, ' ', 0x07);
582 for (int dy
= 0; dy
< 4; ++dy
) {
583 uint8_t bc
= (dy
== 1 ? 1 : 0);
584 snprintf(buf
, sizeof(buf
), "%04X", addr
);
585 vt_writestrz(x
, y
+dy
, buf
, (0)|(5<<4));
586 for (int dx
= 0; dx
< 6; ++dx
) {
587 uint8_t b
= z80
.mem_read(&z80
, addr
, ZYM_MEMIO_OTHER
);
588 uint8_t fc
= (dx
&1 ? 5 : 7);
589 snprintf(buf
, sizeof(buf
), "%02X", b
);
590 addr
= (addr
+1)&0xffff;
591 vt_writestrz(x
+5+dx
*2, y
+dy
, buf
, fc
|(bc
<<4));
597 static void dbgDrawHexW (int x
, int y
, uint16_t n
, int hilight
) {
598 Uint8 fc
= (hilight
> 0 ? 15 : 7);
599 Uint8 bc
= (hilight
< 0 ? 0 : 0);
601 snprintf(buf
, sizeof(buf
), "%04X", n
);
602 //drawStr6VO(dbgOverlay, buf, x, y, fc, bc);
603 vt_writestrz(x
/6, y
/8, buf
, fc
|(bc
<<4));
607 static void dbgDrawHexB (int x
, int y
, uint16_t n
, int hilight
) {
608 Uint8 fc
= (hilight
? 15 : 7);
610 snprintf(buf
, sizeof(buf
), "%02X", n
);
611 //drawStr6VO(dbgOverlay, buf, x, y, fc, 255);
612 vt_writestrz(x
/6, y
/8, buf
, fc
);
616 static void dbgDrawPortsFFD (void) {
618 drawStr6VO(dbgOverlay
, "7FFD:# ", dbgOverlay
->w
-8*6-3, 2*8+3, 70, 0);
619 dbgDrawHexB(dbgOverlay
->w
-2*6-3, 2*8+3, zxLastOut7ffd
, 0);
620 drawStr6VO(dbgOverlay
, "1FFD:# ", dbgOverlay
->w
-8*6-3, 3*8+3, 70, 0);
621 dbgDrawHexB(dbgOverlay
->w
-2*6-3, 3*8+3, zxLastOut1ffd
, 0);
624 snprintf(buf
, sizeof(buf
), "7FFD:#%02X", zxLastOut7ffd
);
625 vt_writestrz(VID_TEXT_WIDTH
-8, 2, buf
, 7);
626 snprintf(buf
, sizeof(buf
), "1FFD:#%02X", zxLastOut1ffd
);
627 vt_writestrz(VID_TEXT_WIDTH
-8, 3, buf
, 7);
632 static void dbgDrawROMs (void) {
634 drawStr6VO(dbgOverlay
, "R ", dbgOverlay
->w
-3*6-3, 3, 70, 0);
635 dbgDrawHexB(dbgOverlay
->w
-2*6-3, 3, zxLastPagedROM
, 0);
638 snprintf(buf
, sizeof(buf
), "R%02X", zxLastPagedROM
);
639 vt_writestrz(VID_TEXT_WIDTH
-3, 0, buf
, 7);
644 static void dbgDrawPCPrevPC (void) {
647 int tx
= dbgOverlay
->w
-8*6-3;
648 snprintf(buf
, sizeof(buf
), "%04X", z80
.prev_pc
);
649 drawStr6VO(dbgOverlay
, buf
, tx
, 3, 70, 0);
650 snprintf(buf
, sizeof(buf
), "%04X=PC", z80
.org_pc
);
651 drawStr6VO(dbgOverlay
, buf
, tx
, 11, 7, 0);
653 snprintf(buf
, sizeof(buf
), "%04X", z80
.prev_pc
);
654 vt_writestrz(VID_TEXT_WIDTH
-8, 0, buf
, 5);
655 snprintf(buf
, sizeof(buf
), "%04X=PC", z80
.org_pc
);
656 vt_writestrz(VID_TEXT_WIDTH
-8, 1, buf
, 15);
661 static void dbgDrawPortsRegRPCs () {
663 int x
= dbgOverlay
->w
-8*6-5;
664 dbgDrawRect(x
, 0, 8*6+5, 4*8+6, 0, 7);
672 static void dbgDrawRegs (int x
, int y
) {
673 const char *flgS
[2] = { "sz.h.pnc", "SZ5H3PNC" };
677 dbgDrawRect(x
, y
, 32*6+6, 4*8+6, 0, 7);
682 if (dbgIntrHit
) drawChar6VO(dbgOverlay
, 'I', dbgOverlay
->w
-6, 0, 15, 0);
683 if (dbgNMIHit
) drawChar6VO(dbgOverlay
, 'N', dbgOverlay
->w
-6*2, 0, 14, 0);
684 if (zxTRDOSPagedIn
) drawStr6VO(dbgOverlay
, "TRD", dbgOverlay
->w
-6*3, 8, 15, 0);
686 drawStr6VO(dbgOverlay
, "af: af' sp: ir:", x
, y
+8*0, 70, 255);
687 drawStr6VO(dbgOverlay
, "bc: bc' pc: t:", x
, y
+8*1, 70, 255);
688 drawStr6VO(dbgOverlay
, "de: de' ix: im ,i:", x
, y
+8*2, 70, 255);
689 drawStr6VO(dbgOverlay
, "hl: hl' iy:", x
, y
+8*3, 70, 255);
691 dbgDrawHexW(x
+3*6, y
+8*0, z80
.af
.w
, (z80
.af
.w
!= oldDState
.af
.w
));
692 dbgDrawHexW(x
+3*6, y
+8*1, z80
.bc
.w
, (z80
.bc
.w
!= oldDState
.bc
.w
));
693 dbgDrawHexW(x
+3*6, y
+8*2, z80
.de
.w
, (z80
.de
.w
!= oldDState
.de
.w
));
694 dbgDrawHexW(x
+3*6, y
+8*3, z80
.hl
.w
, (z80
.hl
.w
!= oldDState
.hl
.w
));
696 dbgDrawHexW(x
+11*6, y
+8*0, z80
.afx
.w
, (z80
.afx
.w
!= oldDState
.afx
.w
));
697 dbgDrawHexW(x
+11*6, y
+8*1, z80
.bcx
.w
, (z80
.bcx
.w
!= oldDState
.bcx
.w
));
698 dbgDrawHexW(x
+11*6, y
+8*2, z80
.dex
.w
, (z80
.dex
.w
!= oldDState
.dex
.w
));
699 dbgDrawHexW(x
+11*6, y
+8*3, z80
.hlx
.w
, (z80
.hlx
.w
!= oldDState
.hlx
.w
));
701 dbgDrawHexW(x
+19*6, y
+8*0, z80
.sp
.w
, (z80
.sp
.w
!= oldDState
.sp
.w
));
702 dbgDrawHexW(x
+19*6, y
+8*1, z80
.pc
, (z80
.pc
!= oldDState
.pc
));
703 dbgDrawHexW(x
+19*6, y
+8*2, z80
.ix
.w
, (z80
.ix
.w
!= oldDState
.ix
.w
));
704 dbgDrawHexW(x
+19*6, y
+8*3, z80
.iy
.w
, (z80
.iy
.w
!= oldDState
.iy
.w
));
706 dbgDrawHexB(x
+28*6, y
+8*0, z80
.regI
, (z80
.regI
!= oldDState
.regI
));
707 dbgDrawHexB(x
+30*6, y
+8*0, z80
.regR
, (z80
.regR
!= oldDState
.regR
));
709 snprintf(buf
, sizeof(buf
), "%5d", z80
.tstates
);
710 drawStr6VO(dbgOverlay
, buf
, x
+27*6, y
+8*1, 7, 0);
712 drawChar6VO(dbgOverlay
, z80
.im
+'0', x
+26*6, y
+8*2, (z80
.im
!= oldDState
.im
? 15 : 7), 255);
713 drawChar6VO(dbgOverlay
, z80
.iff1
+'0', x
+30*6, y
+8*2, (z80
.iff1
!= oldDState
.iff1
? 15 : 7), 255);
714 drawChar6VO(dbgOverlay
, z80
.iff2
+'0', x
+31*6, y
+8*2, (z80
.iff2
!= oldDState
.iff2
? 15 : 7), 255);
716 for (int f
= 0; f
< 8; ++f
) {
718 if (((z80
.af
.f
>>(7-f
))&0x01) != ((oldDState
.af
.f
>>(7-f
))&0x01)) c
= 15;
719 else if ((z80
.af
.f
>>(7-f
))&0x01) c
= 7;
721 drawChar6VO(dbgOverlay
, flgS
[(z80
.af
.f
>>(7-f
))&0x01][f
], x
+(24+f
)*6, y
+8*3, c
, 255);
726 if (dbgIntrHit
) vt_writechar(VID_TEXT_WIDTH
-1, 0, 'I', 15);
727 if (dbgNMIHit
) vt_writechar(VID_TEXT_WIDTH
-2, 0, 'N', 14);
728 if (zxTRDOSPagedIn
) vt_writestrz(VID_TEXT_WIDTH
-3, 1, "TRD", 15);
730 vt_writestrz(x
, y
+0, "AF: AF' SP: IR: ", 5);
731 vt_writestrz(x
, y
+1, "BC: BC' PC: t: ", 5);
732 vt_writestrz(x
, y
+2, "DE: DE' IX: im ,IF", 5);
733 vt_writestrz(x
, y
+3, "HL: HL' IY: ", 5);
737 dbgDrawHexW(x
+3*6, y
+8*0, z80
.af
.w
, (z80
.af
.w
!= oldDState
.af
.w
));
738 dbgDrawHexW(x
+3*6, y
+8*1, z80
.bc
.w
, (z80
.bc
.w
!= oldDState
.bc
.w
));
739 dbgDrawHexW(x
+3*6, y
+8*2, z80
.de
.w
, (z80
.de
.w
!= oldDState
.de
.w
));
740 dbgDrawHexW(x
+3*6, y
+8*3, z80
.hl
.w
, (z80
.hl
.w
!= oldDState
.hl
.w
));
742 dbgDrawHexW(x
+11*6, y
+8*0, z80
.afx
.w
, (z80
.afx
.w
!= oldDState
.afx
.w
));
743 dbgDrawHexW(x
+11*6, y
+8*1, z80
.bcx
.w
, (z80
.bcx
.w
!= oldDState
.bcx
.w
));
744 dbgDrawHexW(x
+11*6, y
+8*2, z80
.dex
.w
, (z80
.dex
.w
!= oldDState
.dex
.w
));
745 dbgDrawHexW(x
+11*6, y
+8*3, z80
.hlx
.w
, (z80
.hlx
.w
!= oldDState
.hlx
.w
));
747 dbgDrawHexW(x
+19*6, y
+8*0, z80
.sp
.w
, (z80
.sp
.w
!= oldDState
.sp
.w
));
748 dbgDrawHexW(x
+19*6, y
+8*1, z80
.pc
, (z80
.pc
!= oldDState
.pc
));
749 dbgDrawHexW(x
+19*6, y
+8*2, z80
.ix
.w
, (z80
.ix
.w
!= oldDState
.ix
.w
));
750 dbgDrawHexW(x
+19*6, y
+8*3, z80
.iy
.w
, (z80
.iy
.w
!= oldDState
.iy
.w
));
752 dbgDrawHexB(x
+28*6, y
+8*0, z80
.regI
, (z80
.regI
!= oldDState
.regI
));
753 dbgDrawHexB(x
+30*6, y
+8*0, z80
.regR
, (z80
.regR
!= oldDState
.regR
));
755 snprintf(buf
, sizeof(buf
), "%5d", z80
.tstates
);
756 vt_writestrz((x
+27*6)/6, y
/8+1, buf
, 7);
760 vt_writechar(x
+26, y
+2, z80
.im
+'0', (z80
.im
!= oldDState
.im
? 15 : 7));
761 vt_writechar(x
+30, y
+2, z80
.iff1
+'0', (z80
.iff1
!= oldDState
.iff1
? 15 : 7));
762 vt_writechar(x
+31, y
+2, z80
.iff2
+'0', (z80
.iff2
!= oldDState
.iff2
? 15 : 7));
764 for (int f
= 0; f
< 8; ++f
) {
766 if (((z80
.af
.f
>>(7-f
))&0x01) != ((oldDState
.af
.f
>>(7-f
))&0x01)) c
= 15;
767 else if ((z80
.af
.f
>>(7-f
))&0x01) c
= 7;
769 vt_writechar(x
+(24+f
), y
+3, flgS
[(z80
.af
.f
>>(7-f
))&0x01][f
], c
);
775 ////////////////////////////////////////////////////////////////////////////////
776 static uint8_t dbgGetByte (uint16_t addr
) {
777 return z80
.mem_read(&z80
, addr
, ZYM_MEMIO_OTHER
);
781 static inline int dbgOpLenAtAddr (uint16_t addr
) {
782 #ifdef USE_URASM_DISASM
783 const int idx
= urasm_disasm_opfind(addr
);
784 return urasm_disasm_oplen(idx
);
786 zym_op_meminfo_t nfo
;
787 zym_op_meminfo(&z80
, &nfo
, addr
);
793 static void dbgUnasmUp (void) {
794 for (int f
= 8; f
> 0; --f
) {
795 uint16_t a
= ((int32_t)dbgUnasmTop
-f
)&0xffff;
796 const int inslen
= dbgOpLenAtAddr(a
);
797 if (((a
+inslen
)&0xffff) == dbgUnasmTop
) { dbgUnasmTop
= a
; return; }
799 dbgUnasmTop
= ((int32_t)dbgUnasmTop
-1)&0xffff;
803 static void dbgUnasmDown (void) {
804 const int inslen
= dbgOpLenAtAddr(dbgUnasmTop
);
805 dbgUnasmTop
= (dbgUnasmTop
+inslen
)&0xffff;
809 static void dbgBuildPageInfo (void) {
811 for (int f
= 0; f
< DBG_UNASM_HEIGHT
; ++f
) {
812 const int inslen
= dbgOpLenAtAddr(a
);
814 a
= (a
+inslen
)&0xffff;
819 static void dbgCenterUnasm (uint16_t addr
) {
821 for (int f
= 0; f
< DBG_UNASM_HEIGHT
/2-1; ++f
) dbgUnasmUp();
824 for (int f
= 0; f
< DBG_UNASM_HEIGHT
; ++f
) {
825 if (dbgPageAddrs
[f
] == addr
) { dbgPageY
= f
; return; }
827 dbgUnasmTop
= z80
.pc
;
832 /* \x01: default color; \x02: label start; \x03: number start */
833 static void dbgDrawStr6VO (const char *s
, int x
, int y
, Uint8 fc
, Uint8 bg
) {
834 if (!s
|| !s
[0]) return;
835 //VOverlay *v = dbgOverlay;
839 if (ch
>= 1 && ch
<= 3) { inLabel
= ch
-1; continue; }
841 //drawChar6VO(v, ch, x, y, (inLabel == 1 ? (bg < 7 ? 5+8 : 69) : (bg < 7 && inLabel == 2) ? 67 : ch == ',' ? (bg < 7 ? 69 : 5) : fc), bg);
843 inLabel
== 1 ? (bg
>= 2 ? 5+8 : 5) :
844 (bg
< 7 && inLabel
== 2) ? 4+8 :
845 ch
== ',' ? (bg
< 2 ? 3 : 1) :
847 vt_writechar(x
/6, y
/8, ch
, (cc
&0x0f)|(bg
<<4));
853 static int dbgStrLen (const char *s
) {
858 if (ch
>= 1 && ch
<= 3) continue;
865 /* returns bytes in instruction */
866 static int dbgDrawUnasmLine (uint16_t addr
, int x
, int y
, Uint8 fc
, Uint8 bc
) {
869 #ifdef USE_URASM_DISASM
870 const int inslen
= dbgOpLenAtAddr(addr
);
872 urasm_disasm_opdisasm(disbuf
, addr
);
875 zym_disasm_init(&disop
);
876 disop
.flags
= ZYM_DIS_FLAGS_DEFAULT
;
877 zym_disasm_one(&z80
, &disop
, addr
);
878 const int inslen
= disop
.inslen
;
879 char *disbuf
= disop
.disbuf
;
882 //dbgDrawRect(x, y, 52*6+2, 8, bc, 255);
883 vt_writechars(x
/6, y
/8, VID_TEXT_WIDTH
, ' ', fc
|(bc
<<4));
885 snprintf(buf
, sizeof(buf
), "%04X", addr
);
886 //drawStr6VO(dbgOverlay, buf, x, y, fc, bc);
887 vt_writestrz(x
/6, y
/8, buf
, fc
|(bc
<<4));
891 for (int f
= 0; f
< inslen
; ++f
) {
892 snprintf(buf
, sizeof(buf
), "%02X", dbgGetByte((addr
+f
)&0xffff));
893 //drawStr6VO(dbgOverlay, buf, x+(5+f*2)*6, y, (bc >= 7 ? fc : 68), bc);
894 vt_writestrz(opx
, y
/8, buf
, (bc
>= 7 ? fc
: 4+(f
&1))|(bc
<<4));
896 if (inslen
<= 3) ++opx
;
900 if ((t
= strchr(disbuf
, '\t')) != NULL
) *t
++ = '\0';
901 dbgDrawStr6VO(disbuf
, x
+16*6, y
, fc
, bc
);
904 dbgDrawStr6VO(t
, x
+21*6, y
, fc
, bc
);
907 // draw address label
908 if (dbgAllowLabels
&2) {
909 const char *lbl
= dbgFindLabelByVal(addr
, 0/*asoffset*/);
911 int lleft
= VID_TEXT_WIDTH
-(t
? 21+dbgStrLen(t
) : dbgStrLen(disbuf
));
914 strncpy(lbuf
+1, lbl
, sizeof(lbuf
)-1);
915 lbuf
[sizeof(lbuf
)-1] = 0;
916 int nlen
= (int)strlen(lbuf
);
917 if (nlen
> lleft
) { nlen
= lleft
; lbuf
[lleft
] = 0; }
918 //drawStr6VO(dbgOverlay, lbuf, x+(52-nlen)*6, y, 4, bc);
919 vt_writestrz(x
/6+(VID_TEXT_WIDTH
-nlen
), y
/8, lbuf
, 4|(bc
<<4));
926 static void dbgDrawUnasm (int x
, int y
) {
927 uint16_t addr
= dbgUnasmTop
;
929 //dbgDrawRect(x, y, 52*6+6+2, DBG_UNASM_HEIGHT*8+6, 0, 7);
935 for (int f
= 0; f
< DBG_UNASM_HEIGHT
; ++f
) {
939 if (addr
== z80
.pc
) {
940 if (dbgBreakpoints
[addr
]&DBG_BP_EXEC
) {
950 bc
= (f
== dbgPageY
? 15 : 7);
953 if (dbgBreakpoints
[addr
]&DBG_BP_EXEC
) {
971 inslen
= dbgDrawUnasmLine(addr
, x
, y
+f
*8, fc
, bc
);
972 addr
= (addr
+inslen
)&0xffff;
977 // -2: on screen, but invisible (must move left to fix)
979 // 0..DBG_UNASM_HEIGHT-1: ok
981 static int dbgIsPCOnScreen (void) {
982 for (int f
= 0; f
< DBG_UNASM_HEIGHT
; ++f
) {
983 if (dbgPageAddrs
[f
] == z80
.pc
) return f
;
986 if (z80
.pc
< dbgUnasmTop
) {
989 int end
= dbgUnasmTop
;
991 for (int f
= 0; f
< DBG_UNASM_HEIGHT
; ++f
) {
992 const int inslen
= dbgOpLenAtAddr(end
&0xffff);
993 if (end
== z80
.pc
) return f
;
994 if (z80
.pc
> end
&& z80
.pc
< end
+inslen
) return -2; // invisible
997 return DBG_UNASM_HEIGHT
;
1002 static void dbgToPC (void) {
1005 int pcpos
= dbgIsPCOnScreen();
1008 dbgUnasmTop
= ((int32_t)dbgUnasmTop
+1)&0xffff;
1010 } else if (pcpos
< 0 || pcpos
>= DBG_UNASM_HEIGHT
) {
1011 dbgCenterUnasm(z80
.pc
);
1020 ////////////////////////////////////////////////////////////////////////////////
1021 // to view original screen
1022 int dbgIsHidden (void) {
1027 void dbgDraw (void) {
1030 //if (dbgOverlay == NULL) dbgOverlay = createVO(320, 240);
1034 dbgDrawPortsRegRPCs();
1035 dbgDrawStack(32*6+6+6-6, 0);
1037 if (dbgMemMode
== 0) dbgDrawMemBytes(51, 0, z80
.pc
);
1038 else if (dbgMemMode
== 1) dbgDrawMemBytes6(51, 0, z80
.pc
);
1039 else dbgDrawMemBytesChars(51, 0, z80
.pc
);
1041 vt_writechars(0, 4, VID_TEXT_WIDTH
, 0xc4, 5);
1042 for (int y
= 0; y
< 4; ++y
) {
1043 vt_writechar(32, y
, 0xb3, 5);
1044 vt_writechar(50, y
, 0xb3, 5);
1045 vt_writechar(VID_TEXT_WIDTH
-9, y
, 0xb3, 5);
1047 vt_writechar(32, 4, 0xc1, 5);
1048 vt_writechar(50, 4, 0xc1, 5);
1049 vt_writechar(VID_TEXT_WIDTH
-9, 4, 0xc1, 5);
1051 dbgDrawUnasm(0, 4*8+5+8);
1053 if (dbgDrawOverlayFn
!= NULL
) dbgDrawOverlayFn();
1054 //blitVO(dbgOverlay, 0, 0, dbgAlpha);
1057 for (int y
= 0; y
< 16; ++y
) {
1058 for (int x
= 0; x
< 16; ++x
) {
1059 vt_writechar(x
, y
, y
*16+x
, 0x0f);
1062 for (int x
= 0; x
< 16; ++x
) {
1063 vt_writechar(x
, VID_TEXT_HEIGHT
-1, '*', (x
<<4)|(x
< 8 ? 15 : 0));
1070 ////////////////////////////////////////////////////////////////////////////////
1071 void dbgSetActive (int st
) {
1073 if (st
!= debuggerActive
) {
1074 if ((debuggerActive
= st
) != 0) {
1075 #ifdef USE_URASM_DISASM
1076 urasm_getbyte
= dbgGetByte
;
1078 zym_disasm_getlabel
= dbgZymGetLabel
;
1079 zym_disasm_mnemo_end
= "\t";
1080 zym_disasm_num_start
= "\x03";
1081 zym_disasm_num_end
= "\x01";
1084 dbgCenterUnasm(z80
.pc
);
1085 dbgKeyEventFn
= dbgKeyEventMain
;
1087 zxRealiseScreen(z80
.tstates
);
1089 if (dbgBreakpoints
[z80
.pc
]) {
1090 dbgAddrSkip
= z80
.pc
;
1097 ////////////////////////////////////////////////////////////////////////////////
1098 int dbgKeyEvent (SDL_KeyboardEvent
*key
) {
1099 if (dbgKeyEventFn
!= NULL
) return dbgKeyEventFn(key
);
1104 ////////////////////////////////////////////////////////////////////////////////
1105 static int dbgNewAddrPos
;
1106 static char dbgNewAddrBuf
[8];
1107 static KeyEventCB dbgNewAddrPrevKeyEventFn
;
1108 static DrawOverlayCB dbgNewAddrPrevDrawOverlayFn
;
1111 void dbgSetUnasmAddr (uint16_t addr
) {
1118 static void dbgNewAddrDeinit (int setaddr
) {
1119 dbgKeyEventFn
= dbgNewAddrPrevKeyEventFn
;
1120 dbgDrawOverlayFn
= dbgNewAddrPrevDrawOverlayFn
;
1123 for (int f
= 0; f
< 4; ++f
) dbgUnasmTop
= (dbgUnasmTop
*16)+dbgNewAddrBuf
[f
]-'0'-(dbgNewAddrBuf
[f
] > '9' ? 7 : 0);
1130 static void dbgDrawNewAddr (void) {
1132 drawStr6VO(dbgOverlay
, dbgNewAddrBuf
, 3, 4*8+5+3/*+dbgPageY*8*/, 0, 5+8);
1133 drawChar6VO(dbgOverlay
, dbgNewAddrBuf
[dbgNewAddrPos
], 3+dbgNewAddrPos
*6, 4*8+5+3/*+dbgPageY*8*/, 0, 6+8);
1135 vt_writestrz(0, 4+1, dbgNewAddrBuf
, (5+8)<<4);
1136 vt_writechar(0+dbgNewAddrPos
, 4+1, dbgNewAddrBuf
[dbgNewAddrPos
], (6+8)<<4);
1141 static int dbgKeyEventNewAddr (SDL_KeyboardEvent
*key
) {
1142 if (key
->type
== SDL_KEYDOWN
&& (key
->keysym
.mod
&KMOD_CTRL
) == 0) {
1143 if (key
->keysym
.unicode
>= 32 && key
->keysym
.unicode
< 127) {
1144 char ch
= toupper(key
->keysym
.unicode
);
1145 if ((ch
>= '0' && ch
<= '9') || (ch
>= 'A' && ch
<= 'F')) {
1146 dbgNewAddrBuf
[dbgNewAddrPos
++] = ch
;
1147 if (dbgNewAddrPos
> 3) dbgNewAddrPos
= 3;
1152 switch (key
->keysym
.sym
) {
1154 dbgNewAddrDeinit(0);
1157 dbgNewAddrDeinit(1);
1159 case SDLK_LEFT
: case SDLK_KP4
: case SDLK_BACKSPACE
:
1160 if (dbgNewAddrPos
> 0) --dbgNewAddrPos
;
1162 case SDLK_RIGHT
: case SDLK_KP6
:
1163 if (dbgNewAddrPos
< 3) ++dbgNewAddrPos
;
1165 case SDLK_HOME
: case SDLK_KP7
:
1168 case SDLK_END
: case SDLK_KP1
:
1172 if ((key
->keysym
.mod
&KMOD_SHIFT
) != 0) {
1173 snprintf(dbgNewAddrBuf
, sizeof(dbgNewAddrBuf
), "%04X", z80
.pc
);
1184 static void dbgNewAddrInit (void) {
1185 dbgNewAddrPrevKeyEventFn
= dbgKeyEventFn
;
1186 dbgNewAddrPrevDrawOverlayFn
= dbgDrawOverlayFn
;
1187 dbgKeyEventFn
= dbgKeyEventNewAddr
;
1188 dbgDrawOverlayFn
= dbgDrawNewAddr
;
1190 snprintf(dbgNewAddrBuf
, sizeof(dbgNewAddrBuf
), "%04X", dbgUnasmTop
);
1194 ////////////////////////////////////////////////////////////////////////////////
1195 static int dbgKeyEventMain (SDL_KeyboardEvent
*key
) {
1196 if (key
->type
== SDL_KEYDOWN
&& (key
->keysym
.mod
&KMOD_ALT
) != 0) {
1197 switch (key
->keysym
.sym
) {
1199 dbgHidden
= !dbgHidden
;
1205 if (key
->type
== SDL_KEYDOWN
&& (key
->keysym
.mod
&KMOD_CTRL
) != 0) {
1208 switch (key
->keysym
.sym
) {
1210 ots
= zxOldScreenTS
;
1212 zxRealiseScreen(machineInfo
.tsperframe
);
1213 zxOldScreenTS
= ots
;
1215 case SDLK_UP
: case SDLK_KP8
:
1216 if (dbgPageY
< DBG_UNASM_HEIGHT
-1) {
1222 case SDLK_DOWN
: case SDLK_KP2
:
1233 if (key
->type
== SDL_KEYDOWN
&& (key
->keysym
.mod
&KMOD_CTRL
) == 0) {
1235 switch (key
->keysym
.sym
) {
1236 case SDLK_ESCAPE
: case SDLK_RETURN
: case SDLK_SPACE
:
1244 switch (key
->keysym
.sym
) {
1248 case SDLK_UP
: case SDLK_KP8
:
1256 case SDLK_DOWN
: case SDLK_KP2
:
1257 if (++dbgPageY
>= DBG_UNASM_HEIGHT
) {
1258 dbgPageY
= DBG_UNASM_HEIGHT
-1;
1263 case SDLK_PAGEUP
: case SDLK_KP9
:
1264 for (int f
= 0; f
< DBG_UNASM_HEIGHT
; ++f
) dbgUnasmUp();
1267 case SDLK_PAGEDOWN
: case SDLK_KP3
:
1268 for (int f
= 0; f
< DBG_UNASM_HEIGHT
; ++f
) dbgUnasmDown();
1271 case SDLK_HOME
: case SDLK_KP7
:
1274 case SDLK_END
: case SDLK_KP1
:
1275 dbgPageY
= DBG_UNASM_HEIGHT
-1;
1277 case SDLK_LEFT
: case SDLK_KP4
:
1278 dbgUnasmTop
= ((int32_t)dbgUnasmTop
-1)&0xffff;
1281 case SDLK_RIGHT
: case SDLK_KP6
:
1282 dbgUnasmTop
= (dbgUnasmTop
+1)&0xffff;
1285 case SDLK_F7
: // step
1287 dbgAddrSkip
= z80
.pc
;
1289 //fprintf(stderr, "%d %d\n", dbgIntrHit, dbgNMIHit);
1290 zxRealiseScreen(z80
.tstates
);
1294 case SDLK_F8
: // to next
1296 dbgAddrSkip
= z80
.pc
;
1298 int na
= (dbgPageAddrs
[dbgPageY
]+dbgOpLenAtAddr(dbgPageAddrs
[dbgPageY
]))&0xffff;
1299 dbgBreakpoints
[na
] |= DBG_BP_EXECONE
;
1304 dbgBreakpoints
[dbgPageAddrs
[dbgPageY
]] ^= DBG_BP_EXEC
;
1309 case SDLK_d
: // difference between PC and current address
1310 cprintf("PC=#%04X; diff=%d\n", z80
.pc
, (int)dbgPageAddrs
[dbgPageY
]-(int)z80
.pc
);
1313 if ((key
->keysym
.mod
&KMOD_SHIFT
) == 0) {
1314 dbgAllowLabels
^= 0x01;
1316 dbgAllowLabels
^= 0x02;
1320 dbgMemMode
= (dbgMemMode
+1)%3;
1323 offsetLabels
= !offsetLabels
;
1329 return (dbgHidden
? 1 : 0);
1333 ////////////////////////////////////////////////////////////////////////////////
1334 static int breakpointHit (uint8_t type
) {
1336 snprintf(sbuf
, sizeof(sbuf
), "::breakpointhit %u", type
);
1337 if (Jim_Eval(jim
, sbuf
) == JIM_OK
) {
1338 Jim_Obj
*res
= Jim_GetResult(jim
);
1340 /* process string results */
1341 const char *resstr
= Jim_String(res
);
1342 if (resstr
&& strcasecmp(resstr
, "stop") == 0) dostop
= 1;
1343 if (!dostop
&& Jim_GetLong(jim
, res
, &dostop
) != JIM_OK
) dostop
= 0;
1344 if (!dostop
) return 0;
1346 Jim_MakeErrorMessage(jim
);
1347 cprintf("\4=== JIM ERROR ===\n%s\n=================\n", Jim_GetString(Jim_GetResult(jim
), NULL
));
1354 int z80CheckBP (uint16_t addrport
, uint8_t type
) {
1355 if (type
== DBG_BP_NONE
) return 0;
1358 uint16_t addrport
= z80
.pc
;
1360 Z80_GetOpMemInfo(&z80
, &nfo
, addrport
);
1362 if (debuggerActive
>= 0) {
1363 if ((dbgBreakpoints
[addrport
]&type
) != 0) {
1364 if (dbgAddrSkip
== addrport
&& (type
&(DBG_BP_EXEC
|DBG_BP_EXECONE
)) != 0) { dbgAddrSkip
= 0; return 0; }
1365 type
&= dbgBreakpoints
[addrport
];
1366 dbgBreakpoints
[addrport
] &= ~DBG_BP_EXECONE
;
1367 res
= breakpointHit(type
);
1369 /* check low port (0 means any) */
1370 type
&= DBG_BP_PORTIN
|DBG_BP_PORTOUT
;
1372 if ((dbgBreakpoints
[addrport
&0xff]&type
) != 0 || (dbgBreakpoints
[0]&type
) != 0) {
1373 type
&= dbgBreakpoints
[addrport
];
1374 res
= breakpointHit(type
);
1383 const char *dbgGetBPTypeStr (uint8_t type
) {
1384 static char buf
[16];
1386 if (type
&DBG_BP_EXEC
) buf
[pos
++] = 'E';
1387 if (type
&DBG_BP_READ
) buf
[pos
++] = 'R';
1388 if (type
&DBG_BP_WRITE
) buf
[pos
++] = 'W';
1389 if (type
&DBG_BP_PORTIN
) buf
[pos
++] = 'I';
1390 if (type
&DBG_BP_PORTOUT
) buf
[pos
++] = 'O';
1391 if (!pos
) return "";
1397 uint8_t dbgGetBPType (uint16_t addr
) {
1398 return dbgBreakpoints
[addr
];
1402 void dbgSetBPType (uint16_t addr
, uint8_t type
) {
1403 dbgBreakpoints
[addr
] = type
;
1407 void dbgBPClear (void) {
1408 memset(dbgBreakpoints
, 0, sizeof(dbgBreakpoints
));
1412 int dbgBPSaveToFile (const char *fname
) {
1413 if (!fname
|| !fname
[0]) return -1;
1414 FILE *fo
= fopen(fname
, "w");
1416 for (unsigned f
= 0; f
< 65536; ++f
) {
1417 const uint8_t bpt
= dbgGetBPType(f
&0xffffu
);
1418 if (bpt
== DBG_BP_NONE
) continue;
1419 if (fprintf(fo
, "%02X %02X\n", bpt
, f
) < 0) {
1424 return (fclose(fo
) == 0 ? 0 : -4);
1428 int dbgBPLoadFromFile (const char *fname
) {
1429 if (!fname
|| !fname
[0]) return -1;
1430 FILE *fl
= fopen(fname
, "r");
1435 while (fgets(line
, (int)sizeof(line
)-2, fl
) != NULL
) {
1436 size_t slen
= strlen(line
);
1437 if (slen
== 0) { ignoreLine
= 1; continue; }
1438 const int eol
= (line
[slen
-1] == '\n' || line
[slen
-1] == '\r');
1439 if (ignoreLine
) { ignoreLine
= !eol
; continue; }
1441 char *cmt
= strchr(line
, ';');
1444 slen
= strlen(line
);
1446 /* remove trailing spaces */
1447 while (slen
> 0 && (unsigned)(line
[slen
-1]&0xff) <= 32) --slen
;
1448 if (slen
== 0) continue;
1450 /* remove leading spaces */
1452 while (line
[slen
] && (unsigned)(line
[slen
]&0xff) <= 32) ++slen
;
1453 if (!line
[slen
]) continue; /* empty line */
1454 memmove(line
, line
+slen
, strlen(line
+slen
)+1);
1456 if (digitInBase(line
[0], 16) < 0) continue;
1461 int d
= digitInBase(line
[pos
], 16);
1464 if (type
> 255) break;
1467 if (type
== 0 || type
> 255) continue;
1468 if (!line
[pos
] || (unsigned)(line
[pos
]&0xff) > 32) continue;
1470 while (line
[pos
] && (unsigned)(line
[pos
]&0xff) <= 32) ++pos
;
1471 if (digitInBase(line
[pos
], 16) < 0) continue;
1474 int d
= digitInBase(line
[pos
], 16);
1477 if (addr
> 65535) break;
1480 if (addr
> 65535) continue;
1481 if (line
[pos
] && (unsigned)(line
[pos
]&0xff) > 32) continue;
1482 dbgSetBPType(addr
&0xffffu
, type
&0xff);