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