4 * Ullrich von Bassewitz, 08.08.1998
20 /*****************************************************************************/
21 /* Function forwards */
22 /*****************************************************************************/
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);
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);
43 /*****************************************************************************/
45 /*****************************************************************************/
47 /* Color definitions */
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
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
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
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
82 /* Screen definitions */
87 # define DUMP_BYTES 16
101 # define DUMP_BYTES 8
108 /* Key definitions */
136 /* Defines for opcodes */
145 #define OPC_JMPIND 0x6C
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 */
161 /* Descriptor for one text line */
168 /* Window descriptor */
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 */
185 /* Texts for the windows */
186 static TextDesc RegText [] = {
196 static TextDesc HelpText [] = {
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" },
213 { 1, 16, "s Skip next instruction" },
218 static FrameDesc AsmFrame = {
219 CH_ULCORNER, CH_TTEE, CH_LTEE, CH_CROSS,
220 0, 0, MAX_X - 10, 15,
226 static FrameDesc RegFrame = {
227 CH_TTEE, CH_URCORNER, CH_LTEE, CH_RTEE,
228 MAX_X - 10, 0, MAX_X - 1, 9,
232 sizeof (RegText) / sizeof (RegText [0]), RegText
234 static FrameDesc StackFrame = {
235 CH_LTEE, CH_RTEE, CH_CROSS, CH_RTEE,
236 MAX_X - 10, 9, MAX_X - 1, 15,
242 static FrameDesc CStackFrame = {
243 CH_CROSS, CH_RTEE, CH_BTEE, CH_LRCORNER,
244 MAX_X - 10, 15, MAX_X - 1, MAX_Y - 1,
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,
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,
264 sizeof (HelpText) / sizeof (HelpText [0]), HelpText
266 static FrameDesc* Frames [] = {
275 /* Number of active frame, -1 = none */
276 static int ActiveFrame = -1;
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 */
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 */
301 /* Values for the bk_use field of struct BreakPoint */
302 #define BRK_EMPTY 0x00
303 #define BRK_USER 0x01
306 /* Structure describing a breakpoint */
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 */
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];
322 /*****************************************************************************/
323 /* Forwards for functions in the assembler source */
324 /*****************************************************************************/
328 BreakPoint* DbgGetBreakSlot (void);
329 /* Search for a free breakpoint slot. Return a pointer to the slot or 0 */
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.
338 /*****************************************************************************/
339 /* Frame/window drawing code */
340 /*****************************************************************************/
344 static void DrawFrame (FrameDesc* F, char Active)
345 /* Draw one window frame */
349 unsigned char tl, tr, bl, br;
350 unsigned char x1, y1, width;
351 unsigned char OldColor;
353 /* Determine the characters for the corners, set frame color */
355 OldColor = textcolor (COLOR_FRAMEHIGH);
361 OldColor = textcolor (COLOR_FRAMELOW);
368 /* Get the coordinates into locals for faster access */
374 cputcxy (x1, y1, tl);
379 cvlinexy (x1, ++y1, F->fd_height);
387 cvlinexy (F->fd_x2, y1, F->fd_height);
389 /* If the window has static text associated, print the text */
390 textcolor (COLOR_TEXTLOW);
391 Count = F->fd_textcount;
394 cputsxy (x1 + T->x, y1 + T->y, T->text);
398 /* Set the old color */
399 textcolor (OldColor);
404 static void DrawFrames (void)
405 /* Draw all frames */
410 /* Build the frame layout of the screen */
411 for (I = 0; I < sizeof (Frames) / sizeof (Frames [0]); ++I) {
421 static void ActivateFrame (int Num, unsigned char Clear)
422 /* Activate a new frame, deactivate the old one */
427 if (ActiveFrame != Num) {
429 /* Deactivate the old one */
430 if (ActiveFrame >= 0) {
431 DrawFrame (Frames [ActiveFrame], 0);
434 /* Activate the new one */
435 if ((ActiveFrame = Num) >= 0) {
436 F = Frames [ActiveFrame];
437 /* Clear the frame if requested */
439 for (y = F->fd_y1+1; y < F->fd_y2; ++y) {
440 cclearxy (F->fd_x1+1, y, F->fd_width);
446 /* Redraw the current prompt line */
447 DisplayPrompt (ActivePrompt);
454 /*****************************************************************************/
456 /*****************************************************************************/
460 static void DisplayPrompt (char* s)
461 /* Display a prompt */
463 unsigned char OldColor;
465 /* Remember the current color */
466 OldColor = textcolor (COLOR_TEXTHIGH);
468 /* Clear the old prompt if there is one */
470 textcolor (PromptColor);
471 chlinexy ((MAX_X - PromptLength) / 2, MAX_Y-1, PromptLength);
474 /* Get the new prompt data */
476 PromptColor = OldColor;
477 PromptLength = strlen (ActivePrompt);
479 /* Display the new prompt */
480 textcolor (COLOR_TEXTHIGH);
481 cputsxy ((MAX_X - PromptLength) / 2, MAX_Y-1, ActivePrompt);
483 /* Restore the old color */
484 textcolor (PromptColor);
489 static void HelpPrompt (void)
490 /* Display a prompt line mentioning the help key */
492 DisplayPrompt ("Press F1 for help");
497 static void AnyKeyPrompt (void)
499 DisplayPrompt ("Press any key to continue");
504 static char Input (char* Prompt, char* Buf, unsigned char Count)
505 /* Read input from the user, return 1 on success, 0 if aborted */
508 unsigned char OldColor;
509 unsigned char OldCursor;
515 /* Clear the current prompt line */
516 cclearxy (0, MAX_Y-1, MAX_X);
518 /* Display the new prompt */
519 OldColor = textcolor (COLOR_TEXTHIGH);
520 cputsxy (0, MAX_Y-1, Prompt);
521 textcolor (COLOR_TEXTLOW);
523 /* Remember where we are, enable the cursor */
525 OldCursor = cursor (1);
527 /* Get input and handle it */
531 if (isalnum (c) && i < Count) {
533 cputcxy (x1 + i, MAX_Y-1, c);
535 } else if (i > 0 && c == CH_DEL) {
537 cputcxy (x1 + i, MAX_Y-1, ' ');
538 gotoxy (x1 + i, MAX_Y-1);
539 } else if (c == '\n') {
542 } else if (c == CH_ESC) {
548 /* Reset settings, display old prompt line */
550 textcolor (OldColor);
554 ActivateFrame (Frame, 0);
561 static int InputHex (char* Prompt, unsigned* Val)
562 /* Prompt for a hexadecimal value */
569 /* Read input from the user (4 digits max), check input */
570 if (Input (Prompt, Buf, sizeof (Buf)-1) && isxdigit (Buf [0])) {
572 /* Check the characters and convert to hex */
575 while ((C = *P) && isxdigit (C)) {
580 C = toupper (C) - ('A' - 10);
586 /* Assign the value */
602 static int InputGoto (unsigned* Addr)
603 /* Prompt "Goto" and read an address */
605 return InputHex ("Goto: ", Addr);
610 static void ErrorPrompt (char* Msg)
611 /* Display an error message and wait for a key */
613 /* Save the current prompt */
614 char* OldPrompt = ActivePrompt;
616 /* Display the new one */
619 /* Wait for a key and discard it */
622 /* Restore the old prompt */
623 DisplayPrompt (OldPrompt);
628 static void BreakInRomError (void)
629 /* Print an error message if we cannot set a breakpoint */
631 ErrorPrompt ("Cannot set breakpoint - press a key");
636 /*****************************************************************************/
637 /* Breakpoint handling */
638 /*****************************************************************************/
642 static void DbgSetTmpBreak (unsigned Addr)
643 /* Set a breakpoint */
645 BreakPoint* B = DbgGetBreakSlot ();
652 static void DbgToggleUserBreak (unsigned Addr)
653 /* Set a breakpoint */
655 BreakPoint* B = DbgIsBreak (Addr);
658 /* We have a breakpoint, remove it */
659 B->bk_use = BRK_EMPTY;
662 /* We don't have a breakpoint, set one */
663 if (DbgBreakCount >= MAX_USERBREAKS) {
664 ErrorPrompt ("Too many breakpoints - press a key");
666 /* Test if we can set a breakpoint at that address */
667 if (!DbgIsRAM (Addr)) {
670 /* Set the breakpoint */
671 B = DbgGetBreakSlot ();
673 B->bk_use = BRK_USER;
682 static void DbgResetTmpBreaks (void)
683 /* Reset all temporary breakpoints */
686 BreakPoint* B = DbgBreaks;
688 for (i = 0; i < MAX_USERBREAKS; ++i) {
689 if (B->bk_use == BRK_TMP) {
690 B->bk_use = BRK_EMPTY;
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.
704 BreakPoint* B = DbgBreaks;
705 for (i = 0; i < MAX_USERBREAKS; ++i) {
706 if (B->bk_use == BRK_TMP && !DbgIsRAM (B->bk_addr)) {
708 DbgResetTmpBreaks ();
718 /*****************************************************************************/
719 /* Assembler window stuff */
720 /*****************************************************************************/
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).
736 cur = mem - (lines * 3) - offs;
738 cur += DbgDisAsmLen (cur);
740 in = (in + 1) & 0x1F;
742 if (cur == mem || offs == 12) {
744 return adr [(in - lines - 1) & 0x1F];
746 /* The requested address is inside an instruction, go back
747 * one more byte and try again.
759 static unsigned UpdateAsm (void)
760 /* Update the assembler window starting at the given address */
765 unsigned char width = AsmFrame.fd_width;
766 unsigned char x = AsmFrame.fd_x1 + 1;
767 unsigned m = AsmBack (AsmAddr, 2);
769 for (y = AsmFrame.fd_y1+1; y < AsmFrame.fd_y2; ++y) {
770 len = DbgDisAsm (m, buf, width);
775 if (DbgIsBreak (m)) {
792 static unsigned AsmArg16 (void)
793 /* Return a 16 bit argument */
795 return *(unsigned*)(AsmAddr+1);
800 static void AsmFollow (void)
801 /* Follow the current instruction */
803 switch (*(unsigned char*) AsmAddr) {
807 AsmAddr = AsmArg16 ();
811 AsmAddr = *(unsigned*)AsmArg16 ();
822 AsmAddr = AsmAddr + 2 + *(signed char*)(AsmAddr+1);
826 AsmAddr = (*(unsigned*) (DbgSP + 0x101) + 1);
830 AsmAddr = *(unsigned*) (DbgSP + 0x102);
838 static void AsmHome (void)
839 /* Set the cursor to home position */
846 static void InitAsm (void)
847 /* Initialize the asm window */
855 static char AsmHandler (void)
856 /* Get characters and handle them */
863 /* Update the window contents */
866 /* Read and handle input */
867 switch (c = GetKeyUpdate ()) {
874 AsmAddr = AsmBack (AsmAddr, AsmFrame.fd_height);
878 DbgToggleUserBreak (AsmAddr);
886 InputGoto (&AsmAddr);
898 AsmAddr = AsmBack (AsmAddr, 1);
902 AsmAddr += DbgDisAsmLen (AsmAddr);
914 /*****************************************************************************/
915 /* Register window stuff */
916 /*****************************************************************************/
920 static unsigned UpdateReg (void)
921 /* Update the register window */
923 unsigned char x1 = RegFrame.fd_x1 + 5;
924 unsigned char x2 = x1 + 2;
925 unsigned char y = RegFrame.fd_y1;
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);
943 static void InitReg (void)
944 /* Initialize the register window */
951 static char RegHandler (void)
952 /* Get characters and handle them */
954 return GetKeyUpdate ();
959 /*****************************************************************************/
960 /* Stack window stuff */
961 /*****************************************************************************/
965 static unsigned UpdateStack (void)
966 /* Update the stack window */
968 unsigned char mem = StackAddr;
969 unsigned char x1 = StackFrame.fd_x1 + 1;
970 unsigned char x2 = x1 + 6;
973 for (y = StackFrame.fd_y2-1; y > StackFrame.fd_y1; --y) {
977 cputhex8 (* (unsigned char*) (mem + 0x100));
985 static void StackHome (void)
986 /* Set the cursor to home position */
988 StackAddr = DbgSP + 1;
993 static void InitStack (void)
994 /* Initialize the stack window */
1002 static char StackHandler (void)
1003 /* Get characters and handle them */
1006 unsigned char BytesPerPage = StackFrame.fd_height;
1010 /* Read and handle input */
1011 switch (c = GetKeyUpdate ()) {
1014 StackAddr += BytesPerPage;
1018 StackAddr -= BytesPerPage;
1038 /* Update the window contents */
1045 /*****************************************************************************/
1046 /* C Stack window stuff */
1047 /*****************************************************************************/
1051 static unsigned UpdateCStack (void)
1052 /* Update the C stack window */
1054 unsigned mem = CStackAddr;
1055 unsigned char x = CStackFrame.fd_x1 + 5;
1058 for (y = CStackFrame.fd_y2-1; y > CStackFrame.fd_y1; --y) {
1060 cputhex16 (* (unsigned*)mem);
1063 cputsxy (CStackFrame.fd_x1+1, CStackFrame.fd_y2-1, "->");
1069 static void CStackHome (void)
1070 /* Set the cursor to home position */
1077 static void InitCStack (void)
1078 /* Initialize the C stack window */
1086 static char CStackHandler (void)
1087 /* Get characters and handle them */
1090 unsigned char BytesPerPage = CStackFrame.fd_height * 2;
1094 /* Read and handle input */
1095 switch (c = GetKeyUpdate ()) {
1098 CStackAddr += BytesPerPage;
1102 CStackAddr -= BytesPerPage;
1122 /* Update the window contents */
1129 /*****************************************************************************/
1130 /* Dump window stuff */
1131 /*****************************************************************************/
1135 static unsigned UpdateDump (void)
1136 /* Update the dump window */
1140 unsigned mem = DumpAddr;
1141 unsigned char x = DumpFrame.fd_x1 + 1;
1142 unsigned char* p = (unsigned char*) mem;
1144 for (y = DumpFrame.fd_y1+1; y < DumpFrame.fd_y2; ++y) {
1145 cputsxy (x, y, DbgMemDump (mem, Buf, DUMP_BYTES));
1153 static void DumpHome (void)
1154 /* Set the cursor to home position */
1161 static char DumpHandler (void)
1162 /* Get characters and handle them */
1165 unsigned BytesPerPage = DumpFrame.fd_height * 8;
1169 /* Read and handle input */
1170 switch (c = GetKeyUpdate ()) {
1173 DumpAddr += BytesPerPage;
1177 DumpAddr -= BytesPerPage;
1181 InputGoto (&DumpAddr);
1201 /* Update the window contents */
1208 /*****************************************************************************/
1209 /* Help window stuff */
1210 /*****************************************************************************/
1214 static char HelpHandler (void)
1215 /* Get characters and handle them */
1217 /* Activate the frame */
1218 int OldActive = ActiveFrame;
1219 ActivateFrame (WIN_HELP, 1);
1221 /* Say that we're waiting for a key */
1224 /* Get a character and discard it */
1227 /* Redraw the old stuff */
1230 /* Done, return no char */
1236 /*****************************************************************************/
1238 /*****************************************************************************/
1242 static unsigned GetArg16 (void)
1243 /* Read an argument */
1245 return *(unsigned*)(brk_pc+1);
1250 static unsigned GetStack16 (unsigned char Offs)
1251 /* Fetch a 16 bit value from stack top */
1253 return *(unsigned*)(DbgSP+Offs+0x101);
1258 static void SetRTSBreak (void)
1259 /* Set a breakpoint at the return target */
1261 DbgSetTmpBreak (GetStack16 (0) + 1);
1266 static void SingleStep (char StepInto)
1270 switch (*(unsigned char*) brk_pc) {
1273 /* Set breakpoint at target */
1274 DbgSetTmpBreak (GetArg16 ());
1278 /* Indirect jump, ignore CPU error when crossing page */
1279 DbgSetTmpBreak (*(unsigned*)GetArg16 ());
1290 /* Be sure not to set the breakpoint twice if this is a jump to
1291 * the following instruction.
1293 Offs = *(signed char*)(brk_pc+1);
1295 DbgSetTmpBreak (brk_pc + Offs + 2);
1300 /* Set a breakpoint at the return target */
1305 /* Set a breakpoint at the return target */
1306 DbgSetTmpBreak (GetStack16 (1));
1311 /* Set breakpoint at target */
1312 DbgSetTmpBreak (GetArg16 ());
1318 /* Place a breakpoint behind the instruction */
1319 DbgSetTmpBreak (brk_pc + DbgDisAsmLen (brk_pc));
1324 /*****************************************************************************/
1325 /* High level window handling */
1326 /*****************************************************************************/
1330 static void RedrawStatic (char Frame)
1331 /* Redraw static display stuff */
1333 /* Reset the active frame */
1336 /* Clear the screen hide the cursor */
1337 bordercolor (COLOR_BORDER);
1338 bgcolor (COLOR_BACKGROUND);
1342 /* Build the frame layout of the screen */
1343 textcolor (COLOR_FRAMELOW);
1346 /* Draw the prompt line */
1349 /* Activate the active frame */
1350 ActivateFrame (Frame, 0);
1355 static void Redraw (char Frame)
1356 /* Redraw the display in case it's garbled */
1358 /* Redraw the static stuff */
1359 RedrawStatic (Frame);
1361 /* Init the window contents */
1371 static char GetKeyUpdate (void)
1372 /* Wait for a key updating the windows in the background */
1374 static unsigned char Win;
1376 /* While there are no keys... */
1398 Win = (Win + 1) & 0x03;
1402 /* We have a key - return it */
1408 /*****************************************************************************/
1409 /* Externally visible functions */
1410 /*****************************************************************************/
1414 void DbgEntry (void)
1415 /* Start up the debugger */
1417 static unsigned char FirstTime = 1;
1421 /* If this is the first call, setup the display */
1425 /* Draw the window, default active frame is ASM frame */
1426 RedrawStatic (WIN_ASM);
1434 /* Only initialize variables here, don't do a display update. The actual
1435 * display update will be done while waiting for user input.
1438 UpdateReg (); /* Must update this (static later) */
1443 /* Wait for user input */
1446 c = Frames [ActiveFrame]->fd_func ();
1454 ActivateFrame (c - '1', 0);
1462 /* Go until return */
1468 /* Go to cursor, only possible if cursor not at current PC */
1469 if (AsmAddr != brk_pc) {
1470 DbgSetTmpBreak (AsmAddr);
1479 SingleStep (c == CH_F7 || c == ' ');
1480 if (DbgTmpBreaksOk ()) {
1481 /* Could set breakpoints */
1492 /* Skip instruction */
1493 brk_pc += DbgDisAsmLen (brk_pc);
1499 Redraw (ActiveFrame);