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