]> git.sur5r.net Git - cc65/blob - libsrc/dbg/dbg.c
Working
[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 #ifdef __PLUS4__
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 (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     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 int InputHex (char* Prompt, unsigned* Val)
526 /* Prompt for a hexadecimal value */
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 int InputGoto (unsigned* Addr)
567 /* Prompt "Goto" and read an address */
568 {
569     return InputHex ("Goto: ", Addr);
570 }
571
572
573
574 static void ErrorPrompt (char* Msg)
575 /* Display an error message and wait for a key */
576 {
577     /* Save the current prompt */
578     char* OldPrompt = ActivePrompt;
579
580     /* Display the new one */
581     DisplayPrompt (Msg);
582
583     /* Wait for a key and discard it */
584     cgetc ();
585
586     /* Restore the old prompt */
587     DisplayPrompt (OldPrompt);
588 }
589
590
591
592 static void BreakInRomError (void)
593 /* Print an error message if we cannot set a breakpoint */
594 {
595     ErrorPrompt ("Cannot set breakpoint - press a key");
596 }
597
598
599
600 /*****************************************************************************/
601 /*                            Breakpoint handling                            */
602 /*****************************************************************************/
603
604
605
606 static void DbgSetTmpBreak (unsigned Addr)
607 /* Set a breakpoint */
608 {
609     BreakPoint* B = DbgGetBreakSlot ();
610     B->bk_addr    = Addr;
611     B->bk_use     = BRK_TMP;
612 }
613
614
615
616 static void DbgToggleUserBreak (unsigned Addr)
617 /* Set a breakpoint */
618 {
619     BreakPoint* B = DbgIsBreak (Addr);
620
621     if (B) {
622         /* We have a breakpoint, remove it */
623         B->bk_use = BRK_EMPTY;
624         --DbgBreakCount;
625     } else {
626         /* We don't have a breakpoint, set one */
627         if (DbgBreakCount >= MAX_USERBREAKS) {
628             ErrorPrompt ("Too many breakpoints - press a key");
629         } else {
630             /* Test if we can set a breakpoint at that address */
631             if (!DbgIsRAM (Addr)) {
632                 BreakInRomError ();
633             } else {
634                 /* Set the breakpoint */
635                 B = DbgGetBreakSlot ();
636                 B->bk_addr = Addr;
637                 B->bk_use  = BRK_USER;
638                 ++DbgBreakCount;
639             }
640         }
641     }
642 }
643
644
645
646 static void DbgResetTmpBreaks (void)
647 /* Reset all temporary breakpoints */
648 {
649     unsigned char i;
650     BreakPoint* B = DbgBreaks;
651
652     for (i = 0; i < MAX_USERBREAKS; ++i) {
653         if (B->bk_use == BRK_TMP) {
654             B->bk_use = BRK_EMPTY;
655         }
656         ++B;
657     }
658 }
659
660
661
662 static unsigned char DbgTmpBreaksOk (void)
663 /* Check if the temporary breakpoints can be set, if so, return 1, if not,
664  * reset them all and return 0.
665  */
666 {
667     unsigned char i;
668     BreakPoint* B = DbgBreaks;
669     for (i = 0; i < MAX_USERBREAKS; ++i) {
670         if (B->bk_use == BRK_TMP && !DbgIsRAM (B->bk_addr)) {
671             BreakInRomError ();
672             DbgResetTmpBreaks ();
673             return 0;
674         }
675         ++B;
676     }
677     return 1;
678 }
679
680
681
682 /*****************************************************************************/
683 /*                          Assembler window stuff                           */
684 /*****************************************************************************/
685
686
687
688 static unsigned AsmBack (unsigned mem, unsigned char lines)
689 /* Go back in the assembler window the given number of lines (calculate
690  * new start address).
691  */
692 {
693     unsigned cur;
694     unsigned adr [32];
695     unsigned char in;
696
697     unsigned offs = 6;
698     while (1) {
699         in = 0;
700         cur = mem - (lines * 3) - offs;
701         while (1) {
702             cur += DbgDisAsmLen (cur);
703             adr [in] = cur;
704             in = (in + 1) & 0x1F;
705             if (cur >= mem) {
706                 if (cur == mem || offs == 12) {
707                     /* Found */
708                     return adr [(in - lines - 1) & 0x1F];
709                 } else {
710                     /* The requested address is inside an instruction, go back
711                      * one more byte and try again.
712                      */
713                     ++offs;
714                     break;
715                 }
716             }
717         }
718     }
719 }
720
721
722
723 static unsigned UpdateAsm (void)
724 /* Update the assembler window starting at the given address */
725 {
726     char buf [MAX_X];
727     unsigned char len;
728     unsigned char y;
729     unsigned char width = AsmFrame.fd_width;
730     unsigned char x = AsmFrame.fd_x1 + 1;
731     unsigned      m = AsmBack (AsmAddr, 2);
732
733     for (y = AsmFrame.fd_y1+1; y < AsmFrame.fd_y2; ++y) {
734         len = DbgDisAsm (m, buf, width);
735         if (m == brk_pc) {
736             buf [4] = '-';
737             buf [5] = '>';
738         }
739         if (DbgIsBreak (m)) {
740             buf [5] = '*';
741         }
742         if (m == AsmAddr) {
743             revers (1);
744             cputsxy (1, y, buf);
745             revers (0);
746         } else {
747             cputsxy (1, y, buf);
748         }
749         m += len;
750     }
751     return m;
752 }
753
754
755
756 static unsigned AsmArg16 (void)
757 /* Return a 16 bit argument */
758 {
759     return *(unsigned*)(AsmAddr+1);
760 }
761
762
763
764 static void AsmFollow (void)
765 /* Follow the current instruction */
766 {
767     switch (*(unsigned char*) AsmAddr) {
768
769         case OPC_JMP:
770         case OPC_JSR:
771             AsmAddr = AsmArg16 ();
772             break;
773
774         case OPC_JMPIND:
775             AsmAddr = *(unsigned*)AsmArg16 ();
776             break;
777
778         case OPC_BPL:
779         case OPC_BMI:
780         case OPC_BVC:
781         case OPC_BVS:
782         case OPC_BCC:
783         case OPC_BCS:
784         case OPC_BNE:
785         case OPC_BEQ:
786             AsmAddr = AsmAddr + 2 + *(signed char*)(AsmAddr+1);
787             break;
788
789         case OPC_RTS:
790             AsmAddr = (*(unsigned*) (DbgSP + 0x101) + 1);
791             break;
792
793         case OPC_RTI:
794             AsmAddr = *(unsigned*) (DbgSP + 0x102);
795             break;
796
797     }
798 }
799
800
801
802 static void AsmHome (void)
803 /* Set the cursor to home position */
804 {
805     AsmAddr = brk_pc;
806 }
807
808
809
810 static void InitAsm (void)
811 /* Initialize the asm window */
812 {
813     AsmHome ();
814     UpdateAsm ();
815 }
816
817
818
819 static char AsmHandler (void)
820 /* Get characters and handle them */
821 {
822     char c;
823     unsigned Last;
824
825     while (1) {
826
827         /* Update the window contents */
828         Last = UpdateAsm ();
829
830         /* Read and handle input */
831         switch (c = GetKeyUpdate ()) {
832
833             case  '+':
834                 AsmAddr = Last;
835                 break;
836
837             case '-':
838                 AsmAddr = AsmBack (AsmAddr, AsmFrame.fd_height);
839                 break;
840
841             case 't':
842 #ifdef CH_F2
843             case CH_F2:
844 #endif
845                 DbgToggleUserBreak (AsmAddr);
846                 break;
847
848             case 'f':
849                 AsmFollow ();
850                 break;
851
852             case 'g':
853                 InputGoto (&AsmAddr);
854                 break;
855
856             case 'o':
857                 AsmHome ();
858                 break;
859
860             case 'p':
861                 brk_pc = AsmAddr;
862                 break;
863
864             case CH_CURS_UP:
865                 AsmAddr = AsmBack (AsmAddr, 1);
866                 break;
867
868             case CH_CURS_DOWN:
869                 AsmAddr += DbgDisAsmLen (AsmAddr);
870                 break;
871
872             default:
873                 return c;
874
875         }
876     }
877 }
878
879
880
881 /*****************************************************************************/
882 /*                           Register window stuff                           */
883 /*****************************************************************************/
884
885
886
887 static unsigned UpdateReg (void)
888 /* Update the register window */
889 {
890     unsigned char x1 = RegFrame.fd_x1 + 5;
891     unsigned char x2 = x1 + 2;
892     unsigned char y = RegFrame.fd_y1;
893
894     /* Print the register contents */
895     gotoxy (x1, ++y);   cputhex16 (brk_pc);
896     gotoxy (x2, ++y);   cputhex8  (brk_sr);
897     gotoxy (x2, ++y);   cputhex8  (brk_a);
898     gotoxy (x2, ++y);   cputhex8  (brk_x);
899     gotoxy (x2, ++y);   cputhex8  (brk_y);
900     gotoxy (x2, ++y);   cputhex8  (DbgSP);
901     gotoxy (x1, ++y);   cputhex16 (DbgCS);
902     gotoxy (x1, ++y);   cputhex16 (DbgHI);
903
904     /* Not needed */
905     return 0;
906 }
907
908
909
910 static void InitReg (void)
911 /* Initialize the register window */
912 {
913     UpdateReg ();
914 }
915
916
917
918 static char RegHandler (void)
919 /* Get characters and handle them */
920 {
921     return GetKeyUpdate ();
922 }
923
924
925
926 /*****************************************************************************/
927 /*                             Stack window stuff                            */
928 /*****************************************************************************/
929
930
931
932 static unsigned UpdateStack (void)
933 /* Update the stack window */
934 {
935     unsigned char mem = StackAddr;
936     unsigned char x1 = StackFrame.fd_x1 + 1;
937     unsigned char x2 = x1 + 6;
938     unsigned char y;
939
940     for (y = StackFrame.fd_y2-1; y > StackFrame.fd_y1; --y) {
941         gotoxy (x1, y);
942         cputhex8 (mem);
943         gotoxy (x2, y);
944         cputhex8 (* (unsigned char*) (mem + 0x100));
945         ++mem;
946     }
947     return mem;
948 }
949
950
951
952 static void StackHome (void)
953 /* Set the cursor to home position */
954 {
955     StackAddr = DbgSP + 1;
956 }
957
958
959
960 static void InitStack (void)
961 /* Initialize the stack window */
962 {
963     StackHome ();
964     UpdateStack ();
965 }
966
967
968
969 static char StackHandler (void)
970 /* Get characters and handle them */
971 {
972     char c;
973     unsigned char BytesPerPage = StackFrame.fd_height;
974
975     while (1) {
976
977         /* Read and handle input */
978         switch (c = GetKeyUpdate ()) {
979
980             case  '+':
981                 StackAddr += BytesPerPage;
982                 break;
983
984             case '-':
985                 StackAddr -= BytesPerPage;
986                 break;
987
988             case 'o':
989                 StackHome ();
990                 break;
991
992             case CH_CURS_UP:
993                 --StackAddr;
994                 break;
995
996             case CH_CURS_DOWN:
997                 ++StackAddr;
998                 break;
999
1000             default:
1001                 return c;
1002
1003         }
1004
1005         /* Update the window contents */
1006         UpdateStack ();
1007     }
1008 }
1009
1010
1011
1012 /*****************************************************************************/
1013 /*                           C Stack window stuff                            */
1014 /*****************************************************************************/
1015
1016
1017
1018 static unsigned UpdateCStack (void)
1019 /* Update the C stack window */
1020 {
1021     unsigned mem     = CStackAddr;
1022     unsigned char x  = CStackFrame.fd_x1 + 5;
1023     unsigned char y;
1024
1025     for (y = CStackFrame.fd_y2-1; y > CStackFrame.fd_y1; --y) {
1026         gotoxy (x, y);
1027         cputhex16 (* (unsigned*)mem);
1028         mem += 2;
1029     }
1030     cputsxy (CStackFrame.fd_x1+1, CStackFrame.fd_y2-1, "->");
1031     return mem;
1032 }
1033
1034
1035
1036 static void CStackHome (void)
1037 /* Set the cursor to home position */
1038 {
1039     CStackAddr = DbgCS;
1040 }
1041
1042
1043
1044 static void InitCStack (void)
1045 /* Initialize the C stack window */
1046 {
1047     CStackHome ();
1048     UpdateCStack ();
1049 }
1050
1051
1052
1053 static char CStackHandler (void)
1054 /* Get characters and handle them */
1055 {
1056     char c;
1057     unsigned char BytesPerPage = CStackFrame.fd_height * 2;
1058
1059     while (1) {
1060
1061         /* Read and handle input */
1062         switch (c = GetKeyUpdate ()) {
1063
1064             case  '+':
1065                 CStackAddr += BytesPerPage;
1066                 break;
1067
1068             case '-':
1069                 CStackAddr -= BytesPerPage;
1070                 break;
1071
1072             case 'o':
1073                 CStackHome ();
1074                 break;
1075
1076             case CH_CURS_UP:
1077                 CStackAddr -= 2;
1078                 break;
1079
1080             case CH_CURS_DOWN:
1081                 CStackAddr += 2;
1082                 break;
1083
1084             default:
1085                 return c;
1086
1087         }
1088
1089         /* Update the window contents */
1090         UpdateCStack ();
1091     }
1092 }
1093
1094
1095
1096 /*****************************************************************************/
1097 /*                             Dump window stuff                             */
1098 /*****************************************************************************/
1099
1100
1101
1102 static unsigned UpdateDump (void)
1103 /* Update the dump window */
1104 {
1105     char Buf [MAX_X];
1106     unsigned char y;
1107     unsigned mem = DumpAddr;
1108     unsigned char x = DumpFrame.fd_x1 + 1;
1109     unsigned char* p = (unsigned char*) mem;
1110
1111     for (y = DumpFrame.fd_y1+1; y < DumpFrame.fd_y2; ++y) {
1112         cputsxy (x, y, DbgMemDump (mem, Buf, DUMP_BYTES));
1113         mem += DUMP_BYTES;
1114     }
1115     return mem;
1116 }
1117
1118
1119
1120 static void DumpHome (void)
1121 /* Set the cursor to home position */
1122 {
1123     DumpAddr = 0;
1124 }
1125
1126
1127
1128 static char DumpHandler (void)
1129 /* Get characters and handle them */
1130 {
1131     char c;
1132     unsigned BytesPerPage = DumpFrame.fd_height * 8;
1133
1134     while (1) {
1135
1136         /* Read and handle input */
1137         switch (c = GetKeyUpdate ()) {
1138
1139             case  '+':
1140                 DumpAddr += BytesPerPage;
1141                 break;
1142
1143             case '-':
1144                 DumpAddr -= BytesPerPage;
1145                 break;
1146
1147             case 'g':
1148                 InputGoto (&DumpAddr);
1149                 break;
1150
1151             case 'o':
1152                 DumpHome ();
1153                 break;
1154
1155             case CH_CURS_UP:
1156                 DumpAddr -= 8;
1157                 break;
1158
1159             case CH_CURS_DOWN:
1160                 DumpAddr += 8;
1161                 break;
1162
1163             default:
1164                 return c;
1165
1166         }
1167
1168         /* Update the window contents */
1169         UpdateDump ();
1170     }
1171 }
1172
1173
1174
1175 /*****************************************************************************/
1176 /*                             Help window stuff                             */
1177 /*****************************************************************************/
1178
1179
1180
1181 static char HelpHandler (void)
1182 /* Get characters and handle them */
1183 {
1184     /* Activate the frame */
1185     int OldActive = ActiveFrame;
1186     ActivateFrame (WIN_HELP, 1);
1187
1188     /* Say that we're waiting for a key */
1189     AnyKeyPrompt ();
1190
1191     /* Get a character and discard it */
1192     cgetc ();
1193
1194     /* Redraw the old stuff */
1195     Redraw (OldActive);
1196
1197     /* Done, return no char */
1198     return 0;
1199 }
1200
1201
1202
1203 /*****************************************************************************/
1204 /*                                Singlestep                                 */
1205 /*****************************************************************************/
1206
1207
1208
1209 static unsigned GetArg16 (void)
1210 /* Read an argument */
1211 {
1212     return *(unsigned*)(brk_pc+1);
1213 }
1214
1215
1216
1217 static unsigned GetStack16 (unsigned char Offs)
1218 /* Fetch a 16 bit value from stack top */
1219 {
1220     return *(unsigned*)(DbgSP+Offs+0x101);
1221 }
1222
1223
1224
1225 static void SetRTSBreak (void)
1226 /* Set a breakpoint at the return target */
1227 {
1228     DbgSetTmpBreak (GetStack16 (0) + 1);
1229 }
1230
1231
1232
1233 static void SingleStep (char StepInto)
1234 {
1235     signed char Offs;
1236
1237     switch (*(unsigned char*) brk_pc) {
1238
1239         case OPC_JMP:
1240             /* Set breakpoint at target */
1241             DbgSetTmpBreak (GetArg16 ());
1242             return;
1243
1244         case OPC_JMPIND:
1245             /* Indirect jump, ignore CPU error when crossing page */
1246             DbgSetTmpBreak (*(unsigned*)GetArg16 ());
1247             return;
1248
1249         case OPC_BPL:
1250         case OPC_BMI:
1251         case OPC_BVC:
1252         case OPC_BVS:
1253         case OPC_BCC:
1254         case OPC_BCS:
1255         case OPC_BNE:
1256         case OPC_BEQ:
1257             /* Be sure not to set the breakpoint twice if this is a jump to
1258              * the following instruction.
1259              */
1260             Offs = *(signed char*)(brk_pc+1);
1261             if (Offs) {
1262                 DbgSetTmpBreak (brk_pc + Offs + 2);
1263             }
1264             break;
1265
1266         case OPC_RTS:
1267             /* Set a breakpoint at the return target */
1268             SetRTSBreak ();
1269             return;
1270
1271         case OPC_RTI:
1272             /* Set a breakpoint at the return target */
1273             DbgSetTmpBreak (GetStack16 (1));
1274             return;
1275
1276         case OPC_JSR:
1277             if (StepInto) {
1278                 /* Set breakpoint at target */
1279                 DbgSetTmpBreak (GetArg16 ());
1280                 return;
1281             }
1282             break;
1283     }
1284
1285     /* Place a breakpoint behind the instruction */
1286     DbgSetTmpBreak (brk_pc + DbgDisAsmLen (brk_pc));
1287 }
1288
1289
1290
1291 /*****************************************************************************/
1292 /*                        High level window handling                         */
1293 /*****************************************************************************/
1294
1295
1296
1297 static void RedrawStatic (char Frame)
1298 /* Redraw static display stuff */
1299 {
1300     /* Reset the active frame */
1301     ActiveFrame = -1;
1302
1303     /* Clear the screen hide the cursor */
1304     bordercolor (COLOR_BORDER);
1305     bgcolor (COLOR_BACKGROUND);
1306     clrscr ();
1307     cursor (0);
1308
1309     /* Build the frame layout of the screen */
1310     textcolor (COLOR_FRAMELOW);
1311     DrawFrames ();
1312
1313     /* Draw the prompt line */
1314     HelpPrompt ();
1315
1316     /* Activate the active frame */
1317     ActivateFrame (Frame, 0);
1318 }
1319
1320
1321
1322 static void Redraw (char Frame)
1323 /* Redraw the display in case it's garbled */
1324 {
1325     /* Redraw the static stuff */
1326     RedrawStatic (Frame);
1327
1328     /* Init the window contents */
1329     UpdateAsm ();
1330     UpdateReg ();
1331     UpdateStack ();
1332     UpdateCStack ();
1333     UpdateDump ();
1334 }
1335
1336
1337
1338 static char GetKeyUpdate (void)
1339 /* Wait for a key updating the windows in the background */
1340 {
1341     static unsigned char Win;
1342
1343     /* While there are no keys... */
1344     while (!kbhit ()) {
1345
1346         switch (Win) {
1347
1348             case 0:
1349                 UpdateAsm ();
1350                 break;
1351
1352             case 1:
1353                 UpdateStack ();
1354                 break;
1355
1356             case 2:
1357                 UpdateCStack ();
1358                 break;
1359
1360             case 3:
1361                 UpdateDump ();
1362                 break;
1363         }
1364
1365         Win = (Win + 1) & 0x03;
1366
1367     }
1368
1369     /* We have a key - return it */
1370     return cgetc ();
1371 }
1372
1373
1374
1375 /*****************************************************************************/
1376 /*                       Externally visible functions                        */
1377 /*****************************************************************************/
1378
1379
1380
1381 void DbgEntry (void)
1382 /* Start up the debugger */
1383 {
1384     static unsigned char FirstTime = 1;
1385     char c;
1386     char done;
1387
1388     /* If this is the first call, setup the display */
1389     if (FirstTime) {
1390         FirstTime = 0;
1391
1392         /* Draw the window, default active frame is ASM frame */
1393         RedrawStatic (WIN_ASM);
1394         InitAsm ();
1395         InitReg ();
1396         InitStack ();
1397         InitCStack ();
1398         UpdateDump ();
1399     }
1400
1401     /* Only initialize variables here, don't do a display update. The actual
1402      * display update will be done while waiting for user input.
1403      */
1404     AsmHome ();
1405     UpdateReg ();               /* Must update this (static later) */
1406     StackHome ();
1407     CStackHome ();
1408
1409     /* Wait for user input */
1410     done = 0;
1411     while (!done) {
1412         c = Frames [ActiveFrame]->fd_func ();
1413         switch (c) {
1414
1415             case '1':
1416             case '2':
1417             case '3':
1418             case '4':
1419             case '5':
1420                 ActivateFrame (c - '1', 0);
1421                 break;
1422
1423             case '?':
1424 #ifdef CH_F1
1425             case CH_F1:
1426 #endif
1427                 HelpHandler ();
1428                 break;
1429
1430             case 'u':
1431 #ifdef CH_F3
1432             case CH_F3:
1433 #endif
1434                 /* Go until return */
1435                 SetRTSBreak ();
1436                 done = 1;
1437                 break;
1438
1439             case 'h':
1440 #ifdef CH_F4
1441             case CH_F4:
1442 #endif
1443                 /* Go to cursor, only possible if cursor not at current PC */
1444                 if (AsmAddr != brk_pc) {
1445                     DbgSetTmpBreak (AsmAddr);
1446                     done = 1;
1447                 }
1448                 break;
1449
1450             case ' ':
1451 #ifdef CH_F7
1452             case CH_F7:
1453 #endif
1454                 SingleStep (1);
1455                 if (DbgTmpBreaksOk ()) {
1456                     /* Could set breakpoints */
1457                     done = 1;
1458                 }
1459                 break;
1460
1461             case '\n':
1462 #ifdef CH_F8
1463             case CH_F8:
1464 #endif
1465                 SingleStep (0);
1466                 if (DbgTmpBreaksOk ()) {
1467                     /* Could set breakpoints */
1468                     done = 1;
1469                 }
1470                 break;
1471
1472             case 'c':
1473             case 0:
1474                 done = 1;
1475                 break;
1476
1477             case 's':
1478                 /* Skip instruction */
1479                 brk_pc += DbgDisAsmLen (brk_pc);
1480                 InitAsm ();
1481                 break;
1482
1483             case 'r':
1484                 /* Redraw screen */
1485                 Redraw (ActiveFrame);
1486                 break;
1487
1488             case 'q':
1489                 /* Quit program */
1490                 clrscr ();
1491                 exit (1);
1492
1493         }
1494     }
1495 }
1496
1497