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