]> git.sur5r.net Git - cc65/blob - libsrc/dbg/dbg.c
Fixed _textcolor definition.
[cc65] / libsrc / dbg / dbg.c
1 /*
2 ** dbg.c
3 **
4 ** Ullrich von Bassewitz, 08.08.1998
5 **
6 */
7
8
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <conio.h>
14 #include <ctype.h>
15 #include <6502.h>
16 #include <dbg.h>
17
18
19
20 /*****************************************************************************/
21 /*                             Function forwards                             */
22 /*****************************************************************************/
23
24
25
26 /* Forwards for handler functions */
27 static char AsmHandler (void);
28 static char RegHandler (void);
29 static char StackHandler (void);
30 static char CStackHandler (void);
31 static char DumpHandler (void);
32 static char HelpHandler (void);
33
34 /* Forwards for other functions */
35 static void DisplayPrompt (const char* s);
36 static void SingleStep (char StepInto);
37 static void RedrawStatic (char  Frame);
38 static void Redraw (char Frame);
39 static char GetKeyUpdate (void);
40
41
42
43 /*****************************************************************************/
44 /*                                   Data                                    */
45 /*****************************************************************************/
46
47
48
49 /* Color definitions */
50 #if defined(__C16__)
51 #  define COLOR_BORDER          (BCOLOR_DARKBLUE | CATTR_LUMA6)
52 #  define COLOR_BACKGROUND      COLOR_WHITE
53 #  define COLOR_TEXTHIGH        COLOR_BLACK
54 #  define COLOR_TEXTLOW         COLOR_GRAY1
55 #  define COLOR_FRAMEHIGH       COLOR_BLACK
56 #  define COLOR_FRAMELOW        COLOR_GRAY2
57 #else
58 #  if defined(COLOR_GRAY3)
59 #    define COLOR_BORDER        COLOR_BLACK
60 #    define COLOR_BACKGROUND    COLOR_BLACK
61 #    define COLOR_TEXTHIGH      COLOR_WHITE
62 #    define COLOR_TEXTLOW       COLOR_GRAY3
63 #    define COLOR_FRAMEHIGH     COLOR_WHITE
64 #    define COLOR_FRAMELOW      COLOR_GRAY3
65 #  else
66 #    if defined(__APPLE2__)
67 #      define COLOR_BORDER      COLOR_BLACK
68 #      define COLOR_BACKGROUND  COLOR_BLACK
69 #      define COLOR_TEXTHIGH    COLOR_BLACK
70 #      define COLOR_TEXTLOW     COLOR_BLACK
71 #      define COLOR_FRAMEHIGH   COLOR_BLACK
72 #      define COLOR_FRAMELOW    COLOR_BLACK
73 #    else
74 #      define COLOR_BORDER      COLOR_BLACK
75 #      define COLOR_BACKGROUND  COLOR_BLACK
76 #      define COLOR_TEXTHIGH    COLOR_WHITE
77 #      define COLOR_TEXTLOW     COLOR_WHITE
78 #      define COLOR_FRAMEHIGH   COLOR_WHITE
79 #      define COLOR_FRAMELOW    COLOR_WHITE
80 #    endif
81 #  endif
82 #endif
83 #ifndef COLOR_BLACK
84 #  define COLOR_BLACK   0
85 #endif
86 #ifndef COLOR_WHITE
87 #  define COLOR_WHITE   1
88 #endif
89
90 /* Screen definitions */
91 #if defined(__CBM610__)
92 #  define BIGSCREEN
93 #  define MAX_X         80
94 #  define MAX_Y         25
95 #  define DUMP_BYTES    16
96 #elif defined(__APPLE2__) || defined(__ATARI__)
97 #  define MAX_X         40
98 #  define MAX_Y         24
99 #  define DUMP_BYTES     8
100 #else
101 #  define MAX_X         40
102 #  define MAX_Y         25
103 #  define DUMP_BYTES     8
104 #endif
105
106 /* Replacement key definitions */
107 #ifndef CH_DEL
108 #  define CH_DEL        ('H' - 'A' + 1)         /* Ctrl+H */
109 #endif
110
111 /* Replacement char definitions */
112 #ifndef CH_ULCORNER
113 #  define CH_ULCORNER   '+'
114 #endif
115 #ifndef CH_URCORNER
116 #  define CH_URCORNER   '+'
117 #endif
118 #ifndef CH_LLCORNER
119 #  define CH_LLCORNER   '+'
120 #endif
121 #ifndef CH_LRCORNER
122 #  define CH_LRCORNER   '+'
123 #endif
124 #ifndef CH_TTEE
125 #  define CH_TTEE       '+'
126 #endif
127 #ifndef CH_LTEE
128 #  define CH_LTEE       '+'
129 #endif
130 #ifndef CH_RTEE
131 #  define CH_RTEE       '+'
132 #endif
133 #ifndef CH_BTEE
134 #  define CH_BTEE       '+'
135 #endif
136 #ifndef CH_CROSS
137 #  define CH_CROSS      '+'
138 #endif
139
140 /* Defines for opcodes */
141 #define OPC_BRK         0x00
142 #define OPC_BPL         0x10
143 #define OPC_JSR         0x20
144 #define OPC_BMI         0x30
145 #define OPC_RTI         0x40
146 #define OPC_JMP         0x4C
147 #define OPC_BVC         0x50
148 #define OPC_RTS         0x60
149 #define OPC_JMPIND      0x6C
150 #define OPC_BVS         0x70
151 #define OPC_BCC         0x90
152 #define OPC_BCS         0xB0
153 #define OPC_BNE         0xD0
154 #define OPC_BEQ         0xF0
155
156
157
158 /* Register values that are used also in the assembler stuff */
159 extern unsigned char DbgSP;             /* Stack pointer */
160 extern unsigned      DbgCS;             /* C stack pointer */
161 extern unsigned      DbgHI;             /* High 16 bit of primary reg */
162
163
164
165 /* Descriptor for one text line */
166 typedef struct {
167     unsigned char x;
168     unsigned char y;
169     const char*   text;
170 } TextDesc;
171
172 /* Window descriptor */
173 typedef struct {
174     unsigned char fd_tl;                /* Top left char */
175     unsigned char fd_tr;                /* Top right char */
176     unsigned char fd_bl;                /* Bottom left char */
177     unsigned char fd_br;                /* Bottom right char */
178     unsigned char fd_x1, fd_y1;         /* Upper left corner */
179     unsigned char fd_x2, fd_y2;         /* Lower right corner */
180     unsigned char fd_width, fd_height;  /* Redundant but faster */
181     unsigned char fd_visible;           /* Is the window currently visible? */
182     char (*fd_func) (void);             /* Handler function */
183     unsigned char fd_textcount;         /* Number of text lines to print */
184     const TextDesc* fd_text;            /* Static text in the window */
185 } FrameDesc;
186
187
188
189 /* Texts for the windows */
190 static const TextDesc RegText [] = {
191     { 1,  0, "PC" },
192     { 1,  1, "SR" },
193     { 1,  2, "A"  },
194     { 1,  3, "X"  },
195     { 1,  4, "Y"  },
196     { 1,  5, "SP" },
197     { 1,  6, "CS" },
198     { 1,  7, "HI" }
199 };
200 static const TextDesc HelpText [] = {
201     { 1,  0, "F1, ?     Help"                           },
202     { 1,  1, "F2, t     Toggle breakpoint"              },
203     { 1,  2, "F3, u     Run until subroutine returns"   },
204     { 1,  3, "F4, h     Run to cursor"                  },
205     { 1,  4, "F7, space Step into"                      },
206     { 1,  5, "F8, enter Step over"                      },
207     { 1,  6, "1-5       Select active window"           },
208     { 1,  7, "+         Page down"                      },
209     { 1,  8, "-         Page up"                        },
210     { 1,  9, "Cursor    Move up/down"                   },
211     { 1, 10, "a/z       Move up/down"                   },
212     { 1, 11, "c         Continue"                       },
213     { 1, 12, "f         Follow instruction"             },
214     { 1, 13, "o         Goto origin"                    },
215     { 1, 14, "p         Use as new PC value"            },
216     { 1, 15, "q         Quit"                           },
217     { 1, 16, "r         Redraw screen"                  },
218     { 1, 17, "s         Skip next instruction"          },
219 };
220
221
222 /* Window data */
223 static const FrameDesc AsmFrame = {
224     CH_ULCORNER, CH_TTEE, CH_LTEE, CH_CROSS,
225     0, 0, MAX_X - 10, 15,
226     MAX_X - 11, 14,
227     1,
228     AsmHandler,
229     0, 0
230 };
231 static const FrameDesc RegFrame = {
232     CH_TTEE, CH_URCORNER, CH_LTEE, CH_RTEE,
233     MAX_X - 10, 0, MAX_X - 1, 9,
234     8, 8,
235     1,
236     RegHandler,
237     sizeof (RegText) / sizeof (RegText [0]), RegText
238 };
239 static const FrameDesc StackFrame = {
240     CH_LTEE, CH_RTEE, CH_CROSS, CH_RTEE,
241     MAX_X - 10, 9, MAX_X - 1, 15,
242     8, 5,
243     1,
244     StackHandler,
245     0, 0
246 };
247 static const FrameDesc CStackFrame = {
248     CH_CROSS, CH_RTEE, CH_BTEE, CH_LRCORNER,
249     MAX_X - 10, 15, MAX_X - 1, MAX_Y - 1,
250     8, MAX_Y - 17,
251     1,
252     CStackHandler,
253     0, 0
254 };
255 static const FrameDesc DumpFrame = {
256     CH_LTEE, CH_CROSS, CH_LLCORNER, CH_BTEE,
257     0, 15, MAX_X - 10, MAX_Y-1,
258     MAX_X - 11, MAX_Y - 17,
259     1,
260     DumpHandler,
261     0, 0
262 };
263 static const FrameDesc HelpFrame = {
264     CH_ULCORNER, CH_URCORNER, CH_LLCORNER, CH_LRCORNER,
265     0, 0, MAX_X - 1, MAX_Y-1,
266     MAX_X - 2, MAX_Y - 2,
267     0,
268     HelpHandler,
269     sizeof (HelpText) / sizeof (HelpText [0]), HelpText
270 };
271 static const FrameDesc* const Frames [] = {
272     &AsmFrame,
273     &RegFrame,
274     &StackFrame,
275     &CStackFrame,
276     &DumpFrame,
277     &HelpFrame
278 };
279
280 /* Number of active frame, -1 = none */
281 static int ActiveFrame = -1;
282
283 /* Window names */
284 #define WIN_ASM         0
285 #define WIN_REG         1
286 #define WIN_STACK       2
287 #define WIN_CSTACK      3
288 #define WIN_DUMP        4
289 #define WIN_HELP        5
290
291 /* Other window data */
292 static unsigned AsmAddr;        /* Start address of output */
293 static unsigned DumpAddr;       /* Start address of output */
294 static unsigned CStackAddr;     /* Start address of output */
295 static unsigned char StackAddr; /* Start address of output */
296
297
298
299 /* Prompt line data */
300 static const char* ActivePrompt = 0;  /* Last prompt line displayed */
301 static char PromptColor;        /* Color behind prompt */
302 static char PromptLength;       /* Length of current prompt string */
303
304
305
306 /* Values for the bk_use field of struct BreakPoint */
307 #define BRK_EMPTY       0x00
308 #define BRK_USER        0x01
309 #define BRK_TMP         0x80
310
311 /* Structure describing a breakpoint */
312 typedef struct {
313     unsigned      bk_addr;      /* Address, 0 if unused */
314     unsigned char bk_opc;       /* Opcode */
315     unsigned char bk_use;       /* 1 if in use, 0 otherwise */
316 } BreakPoint;
317
318
319
320 /* Temporary breakpoints - also accessed from the assembler source */
321 #define MAX_USERBREAKS  10
322 unsigned char DbgBreakCount = 0;
323 BreakPoint DbgBreaks [MAX_USERBREAKS+2];
324
325
326
327 /*****************************************************************************/
328 /*              Forwards for functions in the assembler source               */
329 /*****************************************************************************/
330
331
332
333 BreakPoint* DbgGetBreakSlot (void);
334 /* Search for a free breakpoint slot. Return a pointer to the slot or 0 */
335
336 BreakPoint* DbgIsBreak (unsigned Addr);
337 /* Check if there is a user breakpoint at the given address, if so, return
338 ** a pointer to the slot, else return 0.
339 */
340
341
342
343 /*****************************************************************************/
344 /*                         Frame/window drawing code                         */
345 /*****************************************************************************/
346
347
348
349 static void DrawFrame (register const FrameDesc* F, char Active)
350 /* Draw one window frame */
351 {
352     const TextDesc* T;
353     unsigned char Count;
354     unsigned char tl, tr, bl, br;
355     unsigned char x1, y1, width;
356     unsigned char OldColor;
357
358     /* Determine the characters for the corners, set frame color */
359     if (Active) {
360         OldColor = textcolor (COLOR_FRAMEHIGH);
361         tl = CH_ULCORNER;
362         tr = CH_URCORNER;
363         bl = CH_LLCORNER;
364         br = CH_LRCORNER;
365     } else {
366         OldColor = textcolor (COLOR_FRAMELOW);
367         tl = F->fd_tl;
368         tr = F->fd_tr;
369         bl = F->fd_bl;
370         br = F->fd_br;
371     }
372
373     /* Get the coordinates into locals for faster access */
374     x1 = F->fd_x1;
375     y1 = F->fd_y1;
376     width = F->fd_width;
377
378     /* Top line */
379     cputcxy (x1, y1, tl);
380     chline (width);
381     cputc (tr);
382
383     /* Left line */
384     cvlinexy (x1, ++y1, F->fd_height);
385
386     /* Bottom line */
387     cputc (bl);
388     chline (width);
389     cputc (br);
390
391     /* Right line */
392     cvlinexy (F->fd_x2, y1, F->fd_height);
393
394     /* If the window has static text associated, print the text */
395     (void) textcolor (COLOR_TEXTLOW);
396     Count = F->fd_textcount;
397     T = F->fd_text;
398     while (Count--) {
399         cputsxy (x1 + T->x, y1 + T->y, T->text);
400         ++T;
401     }
402
403     /* Set the old color */
404     (void) textcolor (OldColor);
405 }
406
407
408
409 static void DrawFrames (void)
410 /* Draw all frames */
411 {
412     unsigned char I;
413     const FrameDesc* F;
414
415     /* Build the frame layout of the screen */
416     for (I = 0; I < sizeof (Frames) / sizeof (Frames [0]); ++I) {
417         F = Frames [I];
418         if (F->fd_visible) {
419             DrawFrame (F, 0);
420         }
421     }
422 }
423
424
425
426 static void ActivateFrame (int Num, unsigned char Clear)
427 /* Activate a new frame, deactivate the old one */
428 {
429     unsigned char y;
430     register const FrameDesc* F;
431
432     if (ActiveFrame != Num) {
433
434         /* Deactivate the old one */
435         if (ActiveFrame >= 0) {
436             DrawFrame (Frames [ActiveFrame], 0);
437         }
438
439         /* Activate the new one */
440         if ((ActiveFrame = Num) >= 0) {
441             F = Frames [ActiveFrame];
442             /* Clear the frame if requested */
443             if (Clear) {
444                 for (y = F->fd_y1+1; y < F->fd_y2; ++y) {
445                     cclearxy (F->fd_x1+1, y, F->fd_width);
446                 }
447             }
448             DrawFrame (F, 1);
449         }
450
451         /* Redraw the current prompt line */
452         DisplayPrompt (ActivePrompt);
453
454     }
455 }
456
457
458
459 /*****************************************************************************/
460 /*                                Prompt line                                */
461 /*****************************************************************************/
462
463
464
465 static void DisplayPrompt (const char* s)
466 /* Display a prompt */
467 {
468     unsigned char OldColor;
469
470     /* Remember the current color */
471     OldColor = textcolor (COLOR_TEXTHIGH);
472
473     /* Clear the old prompt if there is one */
474     if (ActivePrompt) {
475         (void) textcolor (PromptColor);
476         chlinexy ((MAX_X - PromptLength) / 2, MAX_Y-1, PromptLength);
477     }
478
479     /* Get the new prompt data */
480     ActivePrompt = s;
481     PromptColor  = OldColor;
482     PromptLength = strlen (ActivePrompt);
483
484     /* Display the new prompt */
485     (void) textcolor (COLOR_TEXTHIGH);
486     cputsxy ((MAX_X - PromptLength) / 2, MAX_Y-1, ActivePrompt);
487
488     /* Restore the old color */
489     (void) textcolor (PromptColor);
490 }
491
492
493
494 static void HelpPrompt (void)
495 /* Display a prompt line mentioning the help key */
496 {
497     DisplayPrompt ("Press F1 for help");
498 }
499
500
501
502 static void AnyKeyPrompt (void)
503 {
504     DisplayPrompt ("Press any key to continue");
505 }
506
507
508
509 static char IsAbortKey (char C)
510 /* Return true if C is an abort key */
511 {
512 #if defined(CH_ESC)
513     if (C == CH_ESC) {
514         return 1;
515     }
516 #endif
517 #if defined(CH_STOP)
518     if (C == CH_STOP) {
519         return 1;
520     }
521 #endif
522 #if !defined(CH_ESC) && !defined(CH_STOP)
523     /* Avoid compiler warning about unused parameter */
524     (void) C;
525 #endif
526     return 0;
527 }
528
529
530
531 static char Input (char* Prompt, char* Buf, unsigned char Count)
532 /* Read input from the user, return 1 on success, 0 if aborted */
533 {
534     int Frame;
535     unsigned char OldColor;
536     unsigned char OldCursor;
537     unsigned char x1;
538     unsigned char i;
539     unsigned char done;
540     char c;
541
542     /* Clear the current prompt line */
543     cclearxy (0, MAX_Y-1, MAX_X);
544
545     /* Display the new prompt */
546     OldColor = textcolor (COLOR_TEXTHIGH);
547     cputsxy (0, MAX_Y-1, Prompt);
548     (void) textcolor (COLOR_TEXTLOW);
549
550     /* Remember where we are, enable the cursor */
551     x1 = wherex ();
552     OldCursor = cursor (1);
553
554     /* Get input and handle it */
555     i = done = 0;
556     do {
557         c = cgetc ();
558         if (isalnum (c) && i < Count) {
559             Buf [i] = c;
560             cputcxy (x1 + i, MAX_Y-1, c);
561             ++i;
562         } else if (i > 0 && c == CH_DEL) {
563             --i;
564             cputcxy (x1 + i, MAX_Y-1, ' ');
565             gotoxy (x1 + i, MAX_Y-1);
566         } else if (c == '\n') {
567             Buf [i] = '\0';
568             done = 1;
569         } else if (IsAbortKey (c)) {
570             /* Abort */
571             done = 2;
572         }
573     } while (!done);
574
575     /* Reset settings, display old prompt line */
576     cursor (OldCursor);
577     (void) textcolor (OldColor);
578     DrawFrames ();
579     Frame = ActiveFrame;
580     ActiveFrame = -1;
581     ActivateFrame (Frame, 0);
582
583     return (done == 1);
584 }
585
586
587
588 static char InputHex (char* Prompt, unsigned* Val)
589 /* Prompt for a hexadecimal value. Return 0 on failure. */
590 {
591     char Buf [5];
592     char* P;
593     char C;
594     unsigned V;
595
596     /* Read input from the user (4 digits max), check input */
597     if (Input (Prompt, Buf, sizeof (Buf)-1) && isxdigit (Buf [0])) {
598
599         /* Check the characters and convert to hex */
600         P = Buf;
601         V = 0;
602         while ((C = *P) && isxdigit (C)) {
603             V <<= 4;
604             if (isdigit (C)) {
605                 C -= '0';
606             } else {
607                 C = toupper (C) - ('A' - 10);
608             }
609             V += C;
610             ++P;
611         }
612
613         /* Assign the value */
614         *Val = V;
615
616         /* Success */
617         return 1;
618
619     } else {
620
621         /* Failure */
622         return 0;
623
624     }
625 }
626
627
628
629 static void ErrorPrompt (const char* Msg)
630 /* Display an error message and wait for a key */
631 {
632     /* Save the current prompt */
633     const char* OldPrompt = ActivePrompt;
634
635     /* Display the new one */
636     DisplayPrompt (Msg);
637
638     /* Wait for a key and discard it */
639     cgetc ();
640
641     /* Restore the old prompt */
642     DisplayPrompt (OldPrompt);
643 }
644
645
646
647 static char InputGoto (unsigned* Addr)
648 /* Prompt "Goto" and read an address. Print an error and return 0 on failure. */
649 {
650     char Ok;
651     Ok = InputHex ("Goto: ", Addr);
652     if (!Ok) {
653         ErrorPrompt ("Invalid input - press a key");
654     }
655     return Ok;
656 }
657
658
659
660 static void BreakInRomError (void)
661 /* Print an error message if we cannot set a breakpoint */
662 {
663     ErrorPrompt ("Cannot set breakpoint - press a key");
664 }
665
666
667
668 /*****************************************************************************/
669 /*                            Breakpoint handling                            */
670 /*****************************************************************************/
671
672
673
674 static void DbgSetTmpBreak (unsigned Addr)
675 /* Set a breakpoint */
676 {
677     BreakPoint* B = DbgGetBreakSlot ();
678     B->bk_addr    = Addr;
679     B->bk_use     = BRK_TMP;
680 }
681
682
683
684 static void DbgToggleUserBreak (unsigned Addr)
685 /* Set a breakpoint */
686 {
687     register BreakPoint* B = DbgIsBreak (Addr);
688
689     if (B) {
690         /* We have a breakpoint, remove it */
691         B->bk_use = BRK_EMPTY;
692         --DbgBreakCount;
693     } else {
694         /* We don't have a breakpoint, set one */
695         if (DbgBreakCount >= MAX_USERBREAKS) {
696             ErrorPrompt ("Too many breakpoints - press a key");
697         } else {
698             /* Test if we can set a breakpoint at that address */
699             if (!DbgIsRAM (Addr)) {
700                 BreakInRomError ();
701             } else {
702                 /* Set the breakpoint */
703                 B = DbgGetBreakSlot ();
704                 B->bk_addr = Addr;
705                 B->bk_use  = BRK_USER;
706                 ++DbgBreakCount;
707             }
708         }
709     }
710 }
711
712
713
714 static void DbgResetTmpBreaks (void)
715 /* Reset all temporary breakpoints */
716 {
717     unsigned char i;
718     BreakPoint* B = DbgBreaks;
719
720     for (i = 0; i < MAX_USERBREAKS; ++i) {
721         if (B->bk_use == BRK_TMP) {
722             B->bk_use = BRK_EMPTY;
723         }
724         ++B;
725     }
726 }
727
728
729
730 static unsigned char DbgTmpBreaksOk (void)
731 /* Check if the temporary breakpoints can be set, if so, return 1, if not,
732 ** reset them all and return 0.
733 */
734 {
735     unsigned char i;
736     BreakPoint* B = DbgBreaks;
737     for (i = 0; i < MAX_USERBREAKS; ++i) {
738         if (B->bk_use == BRK_TMP && !DbgIsRAM (B->bk_addr)) {
739             BreakInRomError ();
740             DbgResetTmpBreaks ();
741             return 0;
742         }
743         ++B;
744     }
745     return 1;
746 }
747
748
749
750 /*****************************************************************************/
751 /*                          Assembler window stuff                           */
752 /*****************************************************************************/
753
754
755
756 static unsigned AsmBack (unsigned mem, unsigned char lines)
757 /* Go back in the assembler window the given number of lines (calculate
758 ** new start address).
759 */
760 {
761     unsigned cur;
762     unsigned adr [32];
763     unsigned char in;
764
765     unsigned offs = 6;
766     while (1) {
767         in = 0;
768         cur = mem - (lines * 3) - offs;
769         while (1) {
770             cur += DbgDisAsmLen (cur);
771             adr [in] = cur;
772             in = (in + 1) & 0x1F;
773             if (cur >= mem) {
774                 if (cur == mem || offs == 12) {
775                     /* Found */
776                     return adr [(in - lines - 1) & 0x1F];
777                 } else {
778                     /* The requested address is inside an instruction, go back
779                     ** one more byte and try again.
780                     */
781                     ++offs;
782                     break;
783                 }
784             }
785         }
786     }
787 }
788
789
790
791 static unsigned UpdateAsm (void)
792 /* Update the assembler window starting at the given address */
793 {
794     char buf [MAX_X];
795     unsigned char len;
796     unsigned char y;
797     unsigned char width = AsmFrame.fd_width;
798     unsigned char x = AsmFrame.fd_x1 + 1;
799     unsigned      m = AsmBack (AsmAddr, 2);
800
801     for (y = AsmFrame.fd_y1+1; y < AsmFrame.fd_y2; ++y) {
802         len = DbgDisAsm (m, buf, width);
803         if (m == brk_pc) {
804             buf [4] = '-';
805             buf [5] = '>';
806         }
807         if (DbgIsBreak (m)) {
808             buf [5] = '*';
809         }
810         if (m == AsmAddr) {
811             revers (1);
812             cputsxy (1, y, buf);
813             revers (0);
814         } else {
815             cputsxy (1, y, buf);
816         }
817         m += len;
818     }
819     return m;
820 }
821
822
823
824 static unsigned AsmArg16 (void)
825 /* Return a 16 bit argument */
826 {
827     return *(unsigned*)(AsmAddr+1);
828 }
829
830
831
832 static void AsmFollow (void)
833 /* Follow the current instruction */
834 {
835     switch (*(unsigned char*) AsmAddr) {
836
837         case OPC_JMP:
838         case OPC_JSR:
839             AsmAddr = AsmArg16 ();
840             break;
841
842         case OPC_JMPIND:
843             AsmAddr = *(unsigned*)AsmArg16 ();
844             break;
845
846         case OPC_BPL:
847         case OPC_BMI:
848         case OPC_BVC:
849         case OPC_BVS:
850         case OPC_BCC:
851         case OPC_BCS:
852         case OPC_BNE:
853         case OPC_BEQ:
854             AsmAddr = AsmAddr + 2 + *(signed char*)(AsmAddr+1);
855             break;
856
857         case OPC_RTS:
858             AsmAddr = (*(unsigned*) (DbgSP + 0x101) + 1);
859             break;
860
861         case OPC_RTI:
862             AsmAddr = *(unsigned*) (DbgSP + 0x102);
863             break;
864
865     }
866 }
867
868
869
870 static void AsmHome (void)
871 /* Set the cursor to home position */
872 {
873     AsmAddr = brk_pc;
874 }
875
876
877
878 static void InitAsm (void)
879 /* Initialize the asm window */
880 {
881     AsmHome ();
882     UpdateAsm ();
883 }
884
885
886
887 static char AsmHandler (void)
888 /* Get characters and handle them */
889 {
890     char c;
891     unsigned Last;
892
893     while (1) {
894
895         /* Update the window contents */
896         Last = UpdateAsm ();
897
898         /* Read and handle input */
899         switch (c = GetKeyUpdate ()) {
900
901             case  '+':
902                 AsmAddr = Last;
903                 break;
904
905             case '-':
906                 AsmAddr = AsmBack (AsmAddr, AsmFrame.fd_height);
907                 break;
908
909             case 't':
910 #ifdef CH_F2
911             case CH_F2:
912 #endif
913                 DbgToggleUserBreak (AsmAddr);
914                 break;
915
916             case 'f':
917                 AsmFollow ();
918                 break;
919
920             case 'g':
921                 InputGoto (&AsmAddr);
922                 break;
923
924             case 'o':
925                 AsmHome ();
926                 break;
927
928             case 'p':
929                 brk_pc = AsmAddr;
930                 break;
931
932             case 'a':
933 #ifdef CH_CURS_UP
934             case CH_CURS_UP:
935 #endif
936                 AsmAddr = AsmBack (AsmAddr, 1);
937                 break;
938
939             case 'z':
940 #ifdef CH_CURS_DOWN
941             case CH_CURS_DOWN:
942 #endif
943                 AsmAddr += DbgDisAsmLen (AsmAddr);
944                 break;
945
946             default:
947                 return c;
948
949         }
950     }
951 }
952
953
954
955 /*****************************************************************************/
956 /*                           Register window stuff                           */
957 /*****************************************************************************/
958
959
960
961 static unsigned UpdateReg (void)
962 /* Update the register window */
963 {
964     unsigned char x1 = RegFrame.fd_x1 + 5;
965     unsigned char x2 = x1 + 2;
966     unsigned char y = RegFrame.fd_y1;
967
968     /* Print the register contents */
969     gotoxy (x1, ++y);   cputhex16 (brk_pc);
970     gotoxy (x2, ++y);   cputhex8  (brk_sr);
971     gotoxy (x2, ++y);   cputhex8  (brk_a);
972     gotoxy (x2, ++y);   cputhex8  (brk_x);
973     gotoxy (x2, ++y);   cputhex8  (brk_y);
974     gotoxy (x2, ++y);   cputhex8  (DbgSP);
975     gotoxy (x1, ++y);   cputhex16 (DbgCS);
976     gotoxy (x1, ++y);   cputhex16 (DbgHI);
977
978     /* Not needed */
979     return 0;
980 }
981
982
983
984 static void InitReg (void)
985 /* Initialize the register window */
986 {
987     UpdateReg ();
988 }
989
990
991
992 static char RegHandler (void)
993 /* Get characters and handle them */
994 {
995     return GetKeyUpdate ();
996 }
997
998
999
1000 /*****************************************************************************/
1001 /*                             Stack window stuff                            */
1002 /*****************************************************************************/
1003
1004
1005
1006 static unsigned UpdateStack (void)
1007 /* Update the stack window */
1008 {
1009     unsigned char mem = StackAddr;
1010     unsigned char x1 = StackFrame.fd_x1 + 1;
1011     unsigned char x2 = x1 + 6;
1012     unsigned char y;
1013
1014     for (y = StackFrame.fd_y2-1; y > StackFrame.fd_y1; --y) {
1015         gotoxy (x1, y);
1016         cputhex8 (mem);
1017         gotoxy (x2, y);
1018         cputhex8 (* (unsigned char*) (mem + 0x100));
1019         ++mem;
1020     }
1021     return mem;
1022 }
1023
1024
1025
1026 static void StackHome (void)
1027 /* Set the cursor to home position */
1028 {
1029     StackAddr = DbgSP + 1;
1030 }
1031
1032
1033
1034 static void InitStack (void)
1035 /* Initialize the stack window */
1036 {
1037     StackHome ();
1038     UpdateStack ();
1039 }
1040
1041
1042
1043 static char StackHandler (void)
1044 /* Get characters and handle them */
1045 {
1046     char c;
1047     unsigned char BytesPerPage = StackFrame.fd_height;
1048
1049     while (1) {
1050
1051         /* Read and handle input */
1052         switch (c = GetKeyUpdate ()) {
1053
1054             case  '+':
1055                 StackAddr += BytesPerPage;
1056                 break;
1057
1058             case '-':
1059                 StackAddr -= BytesPerPage;
1060                 break;
1061
1062             case 'o':
1063                 StackHome ();
1064                 break;
1065
1066             case 'a':
1067 #ifdef CH_CURS_UP:
1068             case CH_CURS_UP:
1069 #endif
1070                 --StackAddr;
1071                 break;
1072
1073             case 'z':
1074 #ifdef CH_CURS_DOWN
1075             case CH_CURS_DOWN:
1076 #endif
1077                 ++StackAddr;
1078                 break;
1079
1080             default:
1081                 return c;
1082
1083         }
1084
1085         /* Update the window contents */
1086         UpdateStack ();
1087     }
1088 }
1089
1090
1091
1092 /*****************************************************************************/
1093 /*                           C Stack window stuff                            */
1094 /*****************************************************************************/
1095
1096
1097
1098 static unsigned UpdateCStack (void)
1099 /* Update the C stack window */
1100 {
1101     unsigned mem     = CStackAddr;
1102     unsigned char x  = CStackFrame.fd_x1 + 5;
1103     unsigned char y;
1104
1105     for (y = CStackFrame.fd_y2-1; y > CStackFrame.fd_y1; --y) {
1106         gotoxy (x, y);
1107         cputhex16 (* (unsigned*)mem);
1108         mem += 2;
1109     }
1110     cputsxy (CStackFrame.fd_x1+1, CStackFrame.fd_y2-1, "->");
1111     return mem;
1112 }
1113
1114
1115
1116 static void CStackHome (void)
1117 /* Set the cursor to home position */
1118 {
1119     CStackAddr = DbgCS;
1120 }
1121
1122
1123
1124 static void InitCStack (void)
1125 /* Initialize the C stack window */
1126 {
1127     CStackHome ();
1128     UpdateCStack ();
1129 }
1130
1131
1132
1133 static char CStackHandler (void)
1134 /* Get characters and handle them */
1135 {
1136     char c;
1137     unsigned char BytesPerPage = CStackFrame.fd_height * 2;
1138
1139     while (1) {
1140
1141         /* Read and handle input */
1142         switch (c = GetKeyUpdate ()) {
1143
1144             case  '+':
1145                 CStackAddr += BytesPerPage;
1146                 break;
1147
1148             case '-':
1149                 CStackAddr -= BytesPerPage;
1150                 break;
1151
1152             case 'o':
1153                 CStackHome ();
1154                 break;
1155
1156             case 'a':
1157 #ifdef CH_CURS_UP
1158             case CH_CURS_UP:
1159 #endif
1160                 CStackAddr -= 2;
1161                 break;
1162
1163             case 'z':
1164 #ifdef CH_CURS_DOWN
1165             case CH_CURS_DOWN:
1166 #endif
1167                 CStackAddr += 2;
1168                 break;
1169
1170             default:
1171                 return c;
1172
1173         }
1174
1175         /* Update the window contents */
1176         UpdateCStack ();
1177     }
1178 }
1179
1180
1181
1182 /*****************************************************************************/
1183 /*                             Dump window stuff                             */
1184 /*****************************************************************************/
1185
1186
1187
1188 static unsigned UpdateDump (void)
1189 /* Update the dump window */
1190 {
1191     char Buf [MAX_X];
1192     unsigned char y;
1193     unsigned mem = DumpAddr;
1194     unsigned char x = DumpFrame.fd_x1 + 1;
1195     unsigned char* p = (unsigned char*) mem;
1196
1197     for (y = DumpFrame.fd_y1+1; y < DumpFrame.fd_y2; ++y) {
1198         cputsxy (x, y, DbgMemDump (mem, Buf, DUMP_BYTES));
1199         mem += DUMP_BYTES;
1200     }
1201     return mem;
1202 }
1203
1204
1205
1206 static void DumpHome (void)
1207 /* Set the cursor to home position */
1208 {
1209     DumpAddr = 0;
1210 }
1211
1212
1213
1214 static char DumpHandler (void)
1215 /* Get characters and handle them */
1216 {
1217     char c;
1218     unsigned BytesPerPage = DumpFrame.fd_height * 8;
1219
1220     while (1) {
1221
1222         /* Read and handle input */
1223         switch (c = GetKeyUpdate ()) {
1224
1225             case  '+':
1226                 DumpAddr += BytesPerPage;
1227                 break;
1228
1229             case '-':
1230                 DumpAddr -= BytesPerPage;
1231                 break;
1232
1233             case 'g':
1234                 InputGoto (&DumpAddr);
1235                 break;
1236
1237             case 'o':
1238                 DumpHome ();
1239                 break;
1240
1241             case 'a':
1242 #ifdef CH_CURS_UP
1243             case CH_CURS_UP:
1244 #endif
1245                 DumpAddr -= 8;
1246                 break;
1247
1248             case 'z':
1249 #ifdef CH_CURS_DOWN
1250             case CH_CURS_DOWN:
1251 #endif
1252                 DumpAddr += 8;
1253                 break;
1254
1255             default:
1256                 return c;
1257
1258         }
1259
1260         /* Update the window contents */
1261         UpdateDump ();
1262     }
1263 }
1264
1265
1266
1267 /*****************************************************************************/
1268 /*                             Help window stuff                             */
1269 /*****************************************************************************/
1270
1271
1272
1273 static char HelpHandler (void)
1274 /* Get characters and handle them */
1275 {
1276     /* Activate the frame */
1277     int OldActive = ActiveFrame;
1278     ActivateFrame (WIN_HELP, 1);
1279
1280     /* Say that we're waiting for a key */
1281     AnyKeyPrompt ();
1282
1283     /* Get a character and discard it */
1284     cgetc ();
1285
1286     /* Redraw the old stuff */
1287     Redraw (OldActive);
1288
1289     /* Done, return no char */
1290     return 0;
1291 }
1292
1293
1294
1295 /*****************************************************************************/
1296 /*                                Singlestep                                 */
1297 /*****************************************************************************/
1298
1299
1300
1301 static unsigned GetArg16 (void)
1302 /* Read an argument */
1303 {
1304     return *(unsigned*)(brk_pc+1);
1305 }
1306
1307
1308
1309 static unsigned GetStack16 (unsigned char Offs)
1310 /* Fetch a 16 bit value from stack top */
1311 {
1312     return *(unsigned*)(DbgSP+Offs+0x101);
1313 }
1314
1315
1316
1317 static void SetRTSBreak (void)
1318 /* Set a breakpoint at the return target */
1319 {
1320     DbgSetTmpBreak (GetStack16 (0) + 1);
1321 }
1322
1323
1324
1325 static void SingleStep (char StepInto)
1326 {
1327     signed char Offs;
1328
1329     switch (*(unsigned char*) brk_pc) {
1330
1331         case OPC_JMP:
1332             /* Set breakpoint at target */
1333             DbgSetTmpBreak (GetArg16 ());
1334             return;
1335
1336         case OPC_JMPIND:
1337             /* Indirect jump, ignore CPU error when crossing page */
1338             DbgSetTmpBreak (*(unsigned*)GetArg16 ());
1339             return;
1340
1341         case OPC_BPL:
1342         case OPC_BMI:
1343         case OPC_BVC:
1344         case OPC_BVS:
1345         case OPC_BCC:
1346         case OPC_BCS:
1347         case OPC_BNE:
1348         case OPC_BEQ:
1349             /* Be sure not to set the breakpoint twice if this is a jump to
1350             ** the following instruction.
1351             */
1352             Offs = ((signed char*)brk_pc)[1];
1353             if (Offs) {
1354                 DbgSetTmpBreak (brk_pc + Offs + 2);
1355             }
1356             break;
1357
1358         case OPC_RTS:
1359             /* Set a breakpoint at the return target */
1360             SetRTSBreak ();
1361             return;
1362
1363         case OPC_RTI:
1364             /* Set a breakpoint at the return target */
1365             DbgSetTmpBreak (GetStack16 (1));
1366             return;
1367
1368         case OPC_JSR:
1369             if (StepInto) {
1370                 /* Set breakpoint at target */
1371                 DbgSetTmpBreak (GetArg16 ());
1372                 return;
1373             }
1374             break;
1375     }
1376
1377     /* Place a breakpoint behind the instruction */
1378     DbgSetTmpBreak (brk_pc + DbgDisAsmLen (brk_pc));
1379 }
1380
1381
1382
1383 /*****************************************************************************/
1384 /*                        High level window handling                         */
1385 /*****************************************************************************/
1386
1387
1388
1389 static void RedrawStatic (char Frame)
1390 /* Redraw static display stuff */
1391 {
1392     /* Reset the active frame */
1393     ActiveFrame = -1;
1394
1395     /* Clear the screen hide the cursor */
1396     (void) bordercolor (COLOR_BORDER);
1397     (void) bgcolor (COLOR_BACKGROUND);
1398     clrscr ();
1399     cursor (0);
1400
1401     /* Build the frame layout of the screen */
1402     (void) textcolor (COLOR_FRAMELOW);
1403     DrawFrames ();
1404
1405     /* Draw the prompt line */
1406     HelpPrompt ();
1407
1408     /* Activate the active frame */
1409     ActivateFrame (Frame, 0);
1410 }
1411
1412
1413
1414 static void Redraw (char Frame)
1415 /* Redraw the display in case it's garbled */
1416 {
1417     /* Redraw the static stuff */
1418     RedrawStatic (Frame);
1419
1420     /* Init the window contents */
1421     UpdateAsm ();
1422     UpdateReg ();
1423     UpdateStack ();
1424     UpdateCStack ();
1425     UpdateDump ();
1426 }
1427
1428
1429
1430 static char GetKeyUpdate (void)
1431 /* Wait for a key updating the windows in the background */
1432 {
1433     static unsigned char Win;
1434
1435     /* While there are no keys... */
1436     while (!kbhit ()) {
1437
1438         switch (Win) {
1439
1440             case 0:
1441                 UpdateAsm ();
1442                 break;
1443
1444             case 1:
1445                 UpdateStack ();
1446                 break;
1447
1448             case 2:
1449                 UpdateCStack ();
1450                 break;
1451
1452             case 3:
1453                 UpdateDump ();
1454                 break;
1455         }
1456
1457         Win = (Win + 1) & 0x03;
1458
1459     }
1460
1461     /* We have a key - return it */
1462     return cgetc ();
1463 }
1464
1465
1466
1467 /*****************************************************************************/
1468 /*                       Externally visible functions                        */
1469 /*****************************************************************************/
1470
1471
1472
1473 void DbgEntry (void)
1474 /* Start up the debugger */
1475 {
1476     static unsigned char FirstTime = 1;
1477     char c;
1478     char done;
1479
1480     /* If this is the first call, setup the display */
1481     if (FirstTime) {
1482         FirstTime = 0;
1483
1484         /* Draw the window, default active frame is ASM frame */
1485         RedrawStatic (WIN_ASM);
1486         InitAsm ();
1487         InitReg ();
1488         InitStack ();
1489         InitCStack ();
1490         UpdateDump ();
1491     }
1492
1493     /* Only initialize variables here, don't do a display update. The actual
1494     ** display update will be done while waiting for user input.
1495     */
1496     AsmHome ();
1497     UpdateReg ();               /* Must update this (static later) */
1498     StackHome ();
1499     CStackHome ();
1500
1501     /* Wait for user input */
1502     done = 0;
1503     while (!done) {
1504         c = Frames [ActiveFrame]->fd_func ();
1505         switch (c) {
1506
1507             case '1':
1508             case '2':
1509             case '3':
1510             case '4':
1511             case '5':
1512                 ActivateFrame (c - '1', 0);
1513                 break;
1514
1515             case '?':
1516 #ifdef CH_F1
1517             case CH_F1:
1518 #endif
1519                 HelpHandler ();
1520                 break;
1521
1522             case 'u':
1523 #ifdef CH_F3
1524             case CH_F3:
1525 #endif
1526                 /* Go until return */
1527                 SetRTSBreak ();
1528                 done = 1;
1529                 break;
1530
1531             case 'h':
1532 #ifdef CH_F4
1533             case CH_F4:
1534 #endif
1535                 /* Go to cursor, only possible if cursor not at current PC */
1536                 if (AsmAddr != brk_pc) {
1537                     DbgSetTmpBreak (AsmAddr);
1538                     done = 1;
1539                 }
1540                 break;
1541
1542             case ' ':
1543 #ifdef CH_F7
1544             case CH_F7:
1545 #endif
1546                 SingleStep (1);
1547                 if (DbgTmpBreaksOk ()) {
1548                     /* Could set breakpoints */
1549                     done = 1;
1550                 }
1551                 break;
1552
1553             case '\n':
1554 #ifdef CH_F8
1555             case CH_F8:
1556 #endif
1557                 SingleStep (0);
1558                 if (DbgTmpBreaksOk ()) {
1559                     /* Could set breakpoints */
1560                     done = 1;
1561                 }
1562                 break;
1563
1564             case 'c':
1565             case 0:
1566                 done = 1;
1567                 break;
1568
1569             case 's':
1570                 /* Skip instruction */
1571                 brk_pc += DbgDisAsmLen (brk_pc);
1572                 InitAsm ();
1573                 break;
1574
1575             case 'r':
1576                 /* Redraw screen */
1577                 Redraw (ActiveFrame);
1578                 break;
1579
1580             case 'q':
1581                 /* Quit program */
1582                 clrscr ();
1583                 exit (1);
1584
1585         }
1586     }
1587 }
1588
1589
1590