1
0
mirror of https://github.com/cc65/cc65.git synced 2024-07-05 21:29:03 +00:00
cc65/libsrc/dbg/dbg.c
Oliver Schmidt 98c47d1877 Introduced target 'atarixl'.
The target 'atarixl' is to be used for Atari XL (and better) machines.
It will disable the OS ROM and enable the Shadow RAM available on
those machine.

Note: This commit is only the inital step towards for this goal that just
replicates the target 'atari' as a starting point!
2013-05-28 21:56:37 +02:00

1591 lines
36 KiB
C

/*
* dbg.c
*
* Ullrich von Bassewitz, 08.08.1998
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <ctype.h>
#include <6502.h>
#include <dbg.h>
/*****************************************************************************/
/* Function forwards */
/*****************************************************************************/
/* Forwards for handler functions */
static char AsmHandler (void);
static char RegHandler (void);
static char StackHandler (void);
static char CStackHandler (void);
static char DumpHandler (void);
static char HelpHandler (void);
/* Forwards for other functions */
static void DisplayPrompt (char* s);
static void SingleStep (char StepInto);
static void RedrawStatic (char Frame);
static void Redraw (char Frame);
static char GetKeyUpdate (void);
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Color definitions */
#if defined(__PLUS4__) || defined(__C16__)
# define COLOR_BORDER (BCOLOR_DARKBLUE | CATTR_LUMA6)
# define COLOR_BACKGROUND COLOR_WHITE
# define COLOR_TEXTHIGH COLOR_BLACK
# define COLOR_TEXTLOW COLOR_GRAY1
# define COLOR_FRAMEHIGH COLOR_BLACK
# define COLOR_FRAMELOW COLOR_GRAY2
#else
# if defined(COLOR_GRAY3)
# define COLOR_BORDER COLOR_BLACK
# define COLOR_BACKGROUND COLOR_BLACK
# define COLOR_TEXTHIGH COLOR_WHITE
# define COLOR_TEXTLOW COLOR_GRAY3
# define COLOR_FRAMEHIGH COLOR_WHITE
# define COLOR_FRAMELOW COLOR_GRAY3
# else
# if defined(__APPLE2__) || defined(__APPLE2ENH__)
# define COLOR_BORDER COLOR_BLACK
# define COLOR_BACKGROUND COLOR_BLACK
# define COLOR_TEXTHIGH COLOR_BLACK
# define COLOR_TEXTLOW COLOR_BLACK
# define COLOR_FRAMEHIGH COLOR_BLACK
# define COLOR_FRAMELOW COLOR_BLACK
# else
# define COLOR_BORDER COLOR_BLACK
# define COLOR_BACKGROUND COLOR_BLACK
# define COLOR_TEXTHIGH COLOR_WHITE
# define COLOR_TEXTLOW COLOR_WHITE
# define COLOR_FRAMEHIGH COLOR_WHITE
# define COLOR_FRAMELOW COLOR_WHITE
# endif
# endif
#endif
#ifndef COLOR_BLACK
# define COLOR_BLACK 0
#endif
#ifndef COLOR_WHITE
# define COLOR_WHITE 1
#endif
/* Screen definitions */
#if defined(__CBM610__)
# define BIGSCREEN
# define MAX_X 80
# define MAX_Y 25
# define DUMP_BYTES 16
#elif defined(__APPLE2__) || defined(__APPLE2ENH__) || defined(__ATARI__) || defined(__ATARIXL__)
# define MAX_X 40
# define MAX_Y 24
# define DUMP_BYTES 8
#else
# define MAX_X 40
# define MAX_Y 25
# define DUMP_BYTES 8
#endif
/* Replacement key definitions */
#if defined(__APPLE2__) || defined(__LYNX__) || defined(__SIM6502__) || defined (__SIM65C02__) || defined(__SUPERVISION__)
# define CH_DEL ('H' - 'A' + 1) /* Ctrl+H */
#endif
/* Replacement char definitions */
#ifndef CH_ULCORNER
# define CH_ULCORNER '+'
#endif
#ifndef CH_URCORNER
# define CH_URCORNER '+'
#endif
#ifndef CH_LLCORNER
# define CH_LLCORNER '+'
#endif
#ifndef CH_LRCORNER
# define CH_LRCORNER '+'
#endif
#ifndef CH_TTEE
# define CH_TTEE '+'
#endif
#ifndef CH_LTEE
# define CH_LTEE '+'
#endif
#ifndef CH_RTEE
# define CH_RTEE '+'
#endif
#ifndef CH_BTEE
# define CH_BTEE '+'
#endif
#ifndef CH_CROSS
# define CH_CROSS '+'
#endif
/* Defines for opcodes */
#define OPC_BRK 0x00
#define OPC_BPL 0x10
#define OPC_JSR 0x20
#define OPC_BMI 0x30
#define OPC_RTI 0x40
#define OPC_JMP 0x4C
#define OPC_BVC 0x50
#define OPC_RTS 0x60
#define OPC_JMPIND 0x6C
#define OPC_BVS 0x70
#define OPC_BCC 0x90
#define OPC_BCS 0xB0
#define OPC_BNE 0xD0
#define OPC_BEQ 0xF0
/* Register values that are used also in the assembler stuff */
extern unsigned char DbgSP; /* Stack pointer */
extern unsigned DbgCS; /* C stack pointer */
extern unsigned DbgHI; /* High 16 bit of primary reg */
/* Descriptor for one text line */
typedef struct {
unsigned char x;
unsigned char y;
char* text;
} TextDesc;
/* Window descriptor */
typedef struct {
unsigned char fd_tl; /* Top left char */
unsigned char fd_tr; /* Top right char */
unsigned char fd_bl; /* Bottom left char */
unsigned char fd_br; /* Bottom right char */
unsigned char fd_x1, fd_y1; /* Upper left corner */
unsigned char fd_x2, fd_y2; /* Lower right corner */
unsigned char fd_width, fd_height; /* Redundant but faster */
unsigned char fd_visible; /* Is the window currently visible? */
char (*fd_func) (void); /* Handler function */
unsigned char fd_textcount; /* Number of text lines to print */
TextDesc* fd_text; /* Static text in the window */
} FrameDesc;
/* Texts for the windows */
static TextDesc RegText [] = {
{ 1, 0, "PC" },
{ 1, 1, "SR" },
{ 1, 2, "A" },
{ 1, 3, "X" },
{ 1, 4, "Y" },
{ 1, 5, "SP" },
{ 1, 6, "CS" },
{ 1, 7, "HI" }
};
static TextDesc HelpText [] = {
{ 1, 0, "F1, ? Help" },
{ 1, 1, "F2, t Toggle breakpoint" },
{ 1, 2, "F3, u Run until subroutine returns" },
{ 1, 3, "F4, h Run to cursor" },
{ 1, 4, "F7, space Step into" },
{ 1, 5, "F8, enter Step over" },
{ 1, 6, "1-5 Select active window" },
{ 1, 7, "+ Page down" },
{ 1, 8, "- Page up" },
{ 1, 9, "Cursor Move up/down" },
{ 1, 10, "a/z Move up/down" },
{ 1, 11, "c Continue" },
{ 1, 12, "f Follow instruction" },
{ 1, 13, "o Goto origin" },
{ 1, 14, "p Use as new PC value" },
{ 1, 15, "q Quit" },
{ 1, 16, "r Redraw screen" },
{ 1, 17, "s Skip next instruction" },
};
/* Window data */
static FrameDesc AsmFrame = {
CH_ULCORNER, CH_TTEE, CH_LTEE, CH_CROSS,
0, 0, MAX_X - 10, 15,
MAX_X - 11, 14,
1,
AsmHandler,
0, 0
};
static FrameDesc RegFrame = {
CH_TTEE, CH_URCORNER, CH_LTEE, CH_RTEE,
MAX_X - 10, 0, MAX_X - 1, 9,
8, 8,
1,
RegHandler,
sizeof (RegText) / sizeof (RegText [0]), RegText
};
static FrameDesc StackFrame = {
CH_LTEE, CH_RTEE, CH_CROSS, CH_RTEE,
MAX_X - 10, 9, MAX_X - 1, 15,
8, 5,
1,
StackHandler,
0, 0
};
static FrameDesc CStackFrame = {
CH_CROSS, CH_RTEE, CH_BTEE, CH_LRCORNER,
MAX_X - 10, 15, MAX_X - 1, MAX_Y - 1,
8, MAX_Y - 17,
1,
CStackHandler,
0, 0
};
static FrameDesc DumpFrame = {
CH_LTEE, CH_CROSS, CH_LLCORNER, CH_BTEE,
0, 15, MAX_X - 10, MAX_Y-1,
MAX_X - 11, MAX_Y - 17,
1,
DumpHandler,
0, 0
};
static FrameDesc HelpFrame = {
CH_ULCORNER, CH_URCORNER, CH_LLCORNER, CH_LRCORNER,
0, 0, MAX_X - 1, MAX_Y-1,
MAX_X - 2, MAX_Y - 2,
0,
HelpHandler,
sizeof (HelpText) / sizeof (HelpText [0]), HelpText
};
static FrameDesc* Frames [] = {
&AsmFrame,
&RegFrame,
&StackFrame,
&CStackFrame,
&DumpFrame,
&HelpFrame
};
/* Number of active frame, -1 = none */
static int ActiveFrame = -1;
/* Window names */
#define WIN_ASM 0
#define WIN_REG 1
#define WIN_STACK 2
#define WIN_CSTACK 3
#define WIN_DUMP 4
#define WIN_HELP 5
/* Other window data */
static unsigned AsmAddr; /* Start address of output */
static unsigned DumpAddr; /* Start address of output */
static unsigned CStackAddr; /* Start address of output */
static unsigned char StackAddr; /* Start address of output */
/* Prompt line data */
static char* ActivePrompt = 0; /* Last prompt line displayed */
static char PromptColor; /* Color behind prompt */
static char PromptLength; /* Length of current prompt string */
/* Values for the bk_use field of struct BreakPoint */
#define BRK_EMPTY 0x00
#define BRK_USER 0x01
#define BRK_TMP 0x80
/* Structure describing a breakpoint */
typedef struct {
unsigned bk_addr; /* Address, 0 if unused */
unsigned char bk_opc; /* Opcode */
unsigned char bk_use; /* 1 if in use, 0 otherwise */
} BreakPoint;
/* Temporary breakpoints - also accessed from the assembler source */
#define MAX_USERBREAKS 10
unsigned char DbgBreakCount = 0;
BreakPoint DbgBreaks [MAX_USERBREAKS+2];
/*****************************************************************************/
/* Forwards for functions in the assembler source */
/*****************************************************************************/
BreakPoint* DbgGetBreakSlot (void);
/* Search for a free breakpoint slot. Return a pointer to the slot or 0 */
BreakPoint* DbgIsBreak (unsigned Addr);
/* Check if there is a user breakpoint at the given address, if so, return
* a pointer to the slot, else return 0.
*/
/*****************************************************************************/
/* Frame/window drawing code */
/*****************************************************************************/
static void DrawFrame (register FrameDesc* F, char Active)
/* Draw one window frame */
{
TextDesc* T;
unsigned char Count;
unsigned char tl, tr, bl, br;
unsigned char x1, y1, width;
unsigned char OldColor;
/* Determine the characters for the corners, set frame color */
if (Active) {
OldColor = textcolor (COLOR_FRAMEHIGH);
tl = CH_ULCORNER;
tr = CH_URCORNER;
bl = CH_LLCORNER;
br = CH_LRCORNER;
} else {
OldColor = textcolor (COLOR_FRAMELOW);
tl = F->fd_tl;
tr = F->fd_tr;
bl = F->fd_bl;
br = F->fd_br;
}
/* Get the coordinates into locals for faster access */
x1 = F->fd_x1;
y1 = F->fd_y1;
width = F->fd_width;
/* Top line */
cputcxy (x1, y1, tl);
chline (width);
cputc (tr);
/* Left line */
cvlinexy (x1, ++y1, F->fd_height);
/* Bottom line */
cputc (bl);
chline (width);
cputc (br);
/* Right line */
cvlinexy (F->fd_x2, y1, F->fd_height);
/* If the window has static text associated, print the text */
(void) textcolor (COLOR_TEXTLOW);
Count = F->fd_textcount;
T = F->fd_text;
while (Count--) {
cputsxy (x1 + T->x, y1 + T->y, T->text);
++T;
}
/* Set the old color */
(void) textcolor (OldColor);
}
static void DrawFrames (void)
/* Draw all frames */
{
unsigned char I;
FrameDesc* F;
/* Build the frame layout of the screen */
for (I = 0; I < sizeof (Frames) / sizeof (Frames [0]); ++I) {
F = Frames [I];
if (F->fd_visible) {
DrawFrame (F, 0);
}
}
}
static void ActivateFrame (int Num, unsigned char Clear)
/* Activate a new frame, deactivate the old one */
{
unsigned char y;
register FrameDesc* F;
if (ActiveFrame != Num) {
/* Deactivate the old one */
if (ActiveFrame >= 0) {
DrawFrame (Frames [ActiveFrame], 0);
}
/* Activate the new one */
if ((ActiveFrame = Num) >= 0) {
F = Frames [ActiveFrame];
/* Clear the frame if requested */
if (Clear) {
for (y = F->fd_y1+1; y < F->fd_y2; ++y) {
cclearxy (F->fd_x1+1, y, F->fd_width);
}
}
DrawFrame (F, 1);
}
/* Redraw the current prompt line */
DisplayPrompt (ActivePrompt);
}
}
/*****************************************************************************/
/* Prompt line */
/*****************************************************************************/
static void DisplayPrompt (char* s)
/* Display a prompt */
{
unsigned char OldColor;
/* Remember the current color */
OldColor = textcolor (COLOR_TEXTHIGH);
/* Clear the old prompt if there is one */
if (ActivePrompt) {
(void) textcolor (PromptColor);
chlinexy ((MAX_X - PromptLength) / 2, MAX_Y-1, PromptLength);
}
/* Get the new prompt data */
ActivePrompt = s;
PromptColor = OldColor;
PromptLength = strlen (ActivePrompt);
/* Display the new prompt */
(void) textcolor (COLOR_TEXTHIGH);
cputsxy ((MAX_X - PromptLength) / 2, MAX_Y-1, ActivePrompt);
/* Restore the old color */
(void) textcolor (PromptColor);
}
static void HelpPrompt (void)
/* Display a prompt line mentioning the help key */
{
DisplayPrompt ("Press F1 for help");
}
static void AnyKeyPrompt (void)
{
DisplayPrompt ("Press any key to continue");
}
static char IsAbortKey (char C)
/* Return true if C is an abort key */
{
#if defined(CH_ESC)
if (C == CH_ESC) {
return 1;
}
#endif
#if defined(CH_STOP)
if (C == CH_STOP) {
return 1;
}
#endif
#if !defined(CH_ESC) && !defined(CH_STOP)
/* Avoid compiler warning about unused parameter */
(void) C;
#endif
return 0;
}
static char Input (char* Prompt, char* Buf, unsigned char Count)
/* Read input from the user, return 1 on success, 0 if aborted */
{
int Frame;
unsigned char OldColor;
unsigned char OldCursor;
unsigned char x1;
unsigned char i;
unsigned char done;
char c;
/* Clear the current prompt line */
cclearxy (0, MAX_Y-1, MAX_X);
/* Display the new prompt */
OldColor = textcolor (COLOR_TEXTHIGH);
cputsxy (0, MAX_Y-1, Prompt);
(void) textcolor (COLOR_TEXTLOW);
/* Remember where we are, enable the cursor */
x1 = wherex ();
OldCursor = cursor (1);
/* Get input and handle it */
i = done = 0;
do {
c = cgetc ();
if (isalnum (c) && i < Count) {
Buf [i] = c;
cputcxy (x1 + i, MAX_Y-1, c);
++i;
} else if (i > 0 && c == CH_DEL) {
--i;
cputcxy (x1 + i, MAX_Y-1, ' ');
gotoxy (x1 + i, MAX_Y-1);
} else if (c == '\n') {
Buf [i] = '\0';
done = 1;
} else if (IsAbortKey (c)) {
/* Abort */
done = 2;
}
} while (!done);
/* Reset settings, display old prompt line */
cursor (OldCursor);
(void) textcolor (OldColor);
DrawFrames ();
Frame = ActiveFrame;
ActiveFrame = -1;
ActivateFrame (Frame, 0);
return (done == 1);
}
static char InputHex (char* Prompt, unsigned* Val)
/* Prompt for a hexadecimal value. Return 0 on failure. */
{
char Buf [5];
char* P;
char C;
unsigned V;
/* Read input from the user (4 digits max), check input */
if (Input (Prompt, Buf, sizeof (Buf)-1) && isxdigit (Buf [0])) {
/* Check the characters and convert to hex */
P = Buf;
V = 0;
while ((C = *P) && isxdigit (C)) {
V <<= 4;
if (isdigit (C)) {
C -= '0';
} else {
C = toupper (C) - ('A' - 10);
}
V += C;
++P;
}
/* Assign the value */
*Val = V;
/* Success */
return 1;
} else {
/* Failure */
return 0;
}
}
static void ErrorPrompt (char* Msg)
/* Display an error message and wait for a key */
{
/* Save the current prompt */
char* OldPrompt = ActivePrompt;
/* Display the new one */
DisplayPrompt (Msg);
/* Wait for a key and discard it */
cgetc ();
/* Restore the old prompt */
DisplayPrompt (OldPrompt);
}
static char InputGoto (unsigned* Addr)
/* Prompt "Goto" and read an address. Print an error and return 0 on failure. */
{
char Ok;
Ok = InputHex ("Goto: ", Addr);
if (!Ok) {
ErrorPrompt ("Invalid input - press a key");
}
return Ok;
}
static void BreakInRomError (void)
/* Print an error message if we cannot set a breakpoint */
{
ErrorPrompt ("Cannot set breakpoint - press a key");
}
/*****************************************************************************/
/* Breakpoint handling */
/*****************************************************************************/
static void DbgSetTmpBreak (unsigned Addr)
/* Set a breakpoint */
{
BreakPoint* B = DbgGetBreakSlot ();
B->bk_addr = Addr;
B->bk_use = BRK_TMP;
}
static void DbgToggleUserBreak (unsigned Addr)
/* Set a breakpoint */
{
register BreakPoint* B = DbgIsBreak (Addr);
if (B) {
/* We have a breakpoint, remove it */
B->bk_use = BRK_EMPTY;
--DbgBreakCount;
} else {
/* We don't have a breakpoint, set one */
if (DbgBreakCount >= MAX_USERBREAKS) {
ErrorPrompt ("Too many breakpoints - press a key");
} else {
/* Test if we can set a breakpoint at that address */
if (!DbgIsRAM (Addr)) {
BreakInRomError ();
} else {
/* Set the breakpoint */
B = DbgGetBreakSlot ();
B->bk_addr = Addr;
B->bk_use = BRK_USER;
++DbgBreakCount;
}
}
}
}
static void DbgResetTmpBreaks (void)
/* Reset all temporary breakpoints */
{
unsigned char i;
BreakPoint* B = DbgBreaks;
for (i = 0; i < MAX_USERBREAKS; ++i) {
if (B->bk_use == BRK_TMP) {
B->bk_use = BRK_EMPTY;
}
++B;
}
}
static unsigned char DbgTmpBreaksOk (void)
/* Check if the temporary breakpoints can be set, if so, return 1, if not,
* reset them all and return 0.
*/
{
unsigned char i;
BreakPoint* B = DbgBreaks;
for (i = 0; i < MAX_USERBREAKS; ++i) {
if (B->bk_use == BRK_TMP && !DbgIsRAM (B->bk_addr)) {
BreakInRomError ();
DbgResetTmpBreaks ();
return 0;
}
++B;
}
return 1;
}
/*****************************************************************************/
/* Assembler window stuff */
/*****************************************************************************/
static unsigned AsmBack (unsigned mem, unsigned char lines)
/* Go back in the assembler window the given number of lines (calculate
* new start address).
*/
{
unsigned cur;
unsigned adr [32];
unsigned char in;
unsigned offs = 6;
while (1) {
in = 0;
cur = mem - (lines * 3) - offs;
while (1) {
cur += DbgDisAsmLen (cur);
adr [in] = cur;
in = (in + 1) & 0x1F;
if (cur >= mem) {
if (cur == mem || offs == 12) {
/* Found */
return adr [(in - lines - 1) & 0x1F];
} else {
/* The requested address is inside an instruction, go back
* one more byte and try again.
*/
++offs;
break;
}
}
}
}
}
static unsigned UpdateAsm (void)
/* Update the assembler window starting at the given address */
{
char buf [MAX_X];
unsigned char len;
unsigned char y;
unsigned char width = AsmFrame.fd_width;
unsigned char x = AsmFrame.fd_x1 + 1;
unsigned m = AsmBack (AsmAddr, 2);
for (y = AsmFrame.fd_y1+1; y < AsmFrame.fd_y2; ++y) {
len = DbgDisAsm (m, buf, width);
if (m == brk_pc) {
buf [4] = '-';
buf [5] = '>';
}
if (DbgIsBreak (m)) {
buf [5] = '*';
}
if (m == AsmAddr) {
revers (1);
cputsxy (1, y, buf);
revers (0);
} else {
cputsxy (1, y, buf);
}
m += len;
}
return m;
}
static unsigned AsmArg16 (void)
/* Return a 16 bit argument */
{
return *(unsigned*)(AsmAddr+1);
}
static void AsmFollow (void)
/* Follow the current instruction */
{
switch (*(unsigned char*) AsmAddr) {
case OPC_JMP:
case OPC_JSR:
AsmAddr = AsmArg16 ();
break;
case OPC_JMPIND:
AsmAddr = *(unsigned*)AsmArg16 ();
break;
case OPC_BPL:
case OPC_BMI:
case OPC_BVC:
case OPC_BVS:
case OPC_BCC:
case OPC_BCS:
case OPC_BNE:
case OPC_BEQ:
AsmAddr = AsmAddr + 2 + *(signed char*)(AsmAddr+1);
break;
case OPC_RTS:
AsmAddr = (*(unsigned*) (DbgSP + 0x101) + 1);
break;
case OPC_RTI:
AsmAddr = *(unsigned*) (DbgSP + 0x102);
break;
}
}
static void AsmHome (void)
/* Set the cursor to home position */
{
AsmAddr = brk_pc;
}
static void InitAsm (void)
/* Initialize the asm window */
{
AsmHome ();
UpdateAsm ();
}
static char AsmHandler (void)
/* Get characters and handle them */
{
char c;
unsigned Last;
while (1) {
/* Update the window contents */
Last = UpdateAsm ();
/* Read and handle input */
switch (c = GetKeyUpdate ()) {
case '+':
AsmAddr = Last;
break;
case '-':
AsmAddr = AsmBack (AsmAddr, AsmFrame.fd_height);
break;
case 't':
#ifdef CH_F2
case CH_F2:
#endif
DbgToggleUserBreak (AsmAddr);
break;
case 'f':
AsmFollow ();
break;
case 'g':
InputGoto (&AsmAddr);
break;
case 'o':
AsmHome ();
break;
case 'p':
brk_pc = AsmAddr;
break;
case 'a':
#ifdef CH_CURS_UP
case CH_CURS_UP:
#endif
AsmAddr = AsmBack (AsmAddr, 1);
break;
case 'z':
#ifdef CH_CURS_DOWN
case CH_CURS_DOWN:
#endif
AsmAddr += DbgDisAsmLen (AsmAddr);
break;
default:
return c;
}
}
}
/*****************************************************************************/
/* Register window stuff */
/*****************************************************************************/
static unsigned UpdateReg (void)
/* Update the register window */
{
unsigned char x1 = RegFrame.fd_x1 + 5;
unsigned char x2 = x1 + 2;
unsigned char y = RegFrame.fd_y1;
/* Print the register contents */
gotoxy (x1, ++y); cputhex16 (brk_pc);
gotoxy (x2, ++y); cputhex8 (brk_sr);
gotoxy (x2, ++y); cputhex8 (brk_a);
gotoxy (x2, ++y); cputhex8 (brk_x);
gotoxy (x2, ++y); cputhex8 (brk_y);
gotoxy (x2, ++y); cputhex8 (DbgSP);
gotoxy (x1, ++y); cputhex16 (DbgCS);
gotoxy (x1, ++y); cputhex16 (DbgHI);
/* Not needed */
return 0;
}
static void InitReg (void)
/* Initialize the register window */
{
UpdateReg ();
}
static char RegHandler (void)
/* Get characters and handle them */
{
return GetKeyUpdate ();
}
/*****************************************************************************/
/* Stack window stuff */
/*****************************************************************************/
static unsigned UpdateStack (void)
/* Update the stack window */
{
unsigned char mem = StackAddr;
unsigned char x1 = StackFrame.fd_x1 + 1;
unsigned char x2 = x1 + 6;
unsigned char y;
for (y = StackFrame.fd_y2-1; y > StackFrame.fd_y1; --y) {
gotoxy (x1, y);
cputhex8 (mem);
gotoxy (x2, y);
cputhex8 (* (unsigned char*) (mem + 0x100));
++mem;
}
return mem;
}
static void StackHome (void)
/* Set the cursor to home position */
{
StackAddr = DbgSP + 1;
}
static void InitStack (void)
/* Initialize the stack window */
{
StackHome ();
UpdateStack ();
}
static char StackHandler (void)
/* Get characters and handle them */
{
char c;
unsigned char BytesPerPage = StackFrame.fd_height;
while (1) {
/* Read and handle input */
switch (c = GetKeyUpdate ()) {
case '+':
StackAddr += BytesPerPage;
break;
case '-':
StackAddr -= BytesPerPage;
break;
case 'o':
StackHome ();
break;
case 'a':
#ifdef CH_CURS_UP:
case CH_CURS_UP:
#endif
--StackAddr;
break;
case 'z':
#ifdef CH_CURS_DOWN
case CH_CURS_DOWN:
#endif
++StackAddr;
break;
default:
return c;
}
/* Update the window contents */
UpdateStack ();
}
}
/*****************************************************************************/
/* C Stack window stuff */
/*****************************************************************************/
static unsigned UpdateCStack (void)
/* Update the C stack window */
{
unsigned mem = CStackAddr;
unsigned char x = CStackFrame.fd_x1 + 5;
unsigned char y;
for (y = CStackFrame.fd_y2-1; y > CStackFrame.fd_y1; --y) {
gotoxy (x, y);
cputhex16 (* (unsigned*)mem);
mem += 2;
}
cputsxy (CStackFrame.fd_x1+1, CStackFrame.fd_y2-1, "->");
return mem;
}
static void CStackHome (void)
/* Set the cursor to home position */
{
CStackAddr = DbgCS;
}
static void InitCStack (void)
/* Initialize the C stack window */
{
CStackHome ();
UpdateCStack ();
}
static char CStackHandler (void)
/* Get characters and handle them */
{
char c;
unsigned char BytesPerPage = CStackFrame.fd_height * 2;
while (1) {
/* Read and handle input */
switch (c = GetKeyUpdate ()) {
case '+':
CStackAddr += BytesPerPage;
break;
case '-':
CStackAddr -= BytesPerPage;
break;
case 'o':
CStackHome ();
break;
case 'a':
#ifdef CH_CURS_UP
case CH_CURS_UP:
#endif
CStackAddr -= 2;
break;
case 'z':
#ifdef CH_CURS_DOWN
case CH_CURS_DOWN:
#endif
CStackAddr += 2;
break;
default:
return c;
}
/* Update the window contents */
UpdateCStack ();
}
}
/*****************************************************************************/
/* Dump window stuff */
/*****************************************************************************/
static unsigned UpdateDump (void)
/* Update the dump window */
{
char Buf [MAX_X];
unsigned char y;
unsigned mem = DumpAddr;
unsigned char x = DumpFrame.fd_x1 + 1;
unsigned char* p = (unsigned char*) mem;
for (y = DumpFrame.fd_y1+1; y < DumpFrame.fd_y2; ++y) {
cputsxy (x, y, DbgMemDump (mem, Buf, DUMP_BYTES));
mem += DUMP_BYTES;
}
return mem;
}
static void DumpHome (void)
/* Set the cursor to home position */
{
DumpAddr = 0;
}
static char DumpHandler (void)
/* Get characters and handle them */
{
char c;
unsigned BytesPerPage = DumpFrame.fd_height * 8;
while (1) {
/* Read and handle input */
switch (c = GetKeyUpdate ()) {
case '+':
DumpAddr += BytesPerPage;
break;
case '-':
DumpAddr -= BytesPerPage;
break;
case 'g':
InputGoto (&DumpAddr);
break;
case 'o':
DumpHome ();
break;
case 'a':
#ifdef CH_CURS_UP
case CH_CURS_UP:
#endif
DumpAddr -= 8;
break;
case 'z':
#ifdef CH_CURS_DOWN
case CH_CURS_DOWN:
#endif
DumpAddr += 8;
break;
default:
return c;
}
/* Update the window contents */
UpdateDump ();
}
}
/*****************************************************************************/
/* Help window stuff */
/*****************************************************************************/
static char HelpHandler (void)
/* Get characters and handle them */
{
/* Activate the frame */
int OldActive = ActiveFrame;
ActivateFrame (WIN_HELP, 1);
/* Say that we're waiting for a key */
AnyKeyPrompt ();
/* Get a character and discard it */
cgetc ();
/* Redraw the old stuff */
Redraw (OldActive);
/* Done, return no char */
return 0;
}
/*****************************************************************************/
/* Singlestep */
/*****************************************************************************/
static unsigned GetArg16 (void)
/* Read an argument */
{
return *(unsigned*)(brk_pc+1);
}
static unsigned GetStack16 (unsigned char Offs)
/* Fetch a 16 bit value from stack top */
{
return *(unsigned*)(DbgSP+Offs+0x101);
}
static void SetRTSBreak (void)
/* Set a breakpoint at the return target */
{
DbgSetTmpBreak (GetStack16 (0) + 1);
}
static void SingleStep (char StepInto)
{
signed char Offs;
switch (*(unsigned char*) brk_pc) {
case OPC_JMP:
/* Set breakpoint at target */
DbgSetTmpBreak (GetArg16 ());
return;
case OPC_JMPIND:
/* Indirect jump, ignore CPU error when crossing page */
DbgSetTmpBreak (*(unsigned*)GetArg16 ());
return;
case OPC_BPL:
case OPC_BMI:
case OPC_BVC:
case OPC_BVS:
case OPC_BCC:
case OPC_BCS:
case OPC_BNE:
case OPC_BEQ:
/* Be sure not to set the breakpoint twice if this is a jump to
* the following instruction.
*/
Offs = ((signed char*)brk_pc)[1];
if (Offs) {
DbgSetTmpBreak (brk_pc + Offs + 2);
}
break;
case OPC_RTS:
/* Set a breakpoint at the return target */
SetRTSBreak ();
return;
case OPC_RTI:
/* Set a breakpoint at the return target */
DbgSetTmpBreak (GetStack16 (1));
return;
case OPC_JSR:
if (StepInto) {
/* Set breakpoint at target */
DbgSetTmpBreak (GetArg16 ());
return;
}
break;
}
/* Place a breakpoint behind the instruction */
DbgSetTmpBreak (brk_pc + DbgDisAsmLen (brk_pc));
}
/*****************************************************************************/
/* High level window handling */
/*****************************************************************************/
static void RedrawStatic (char Frame)
/* Redraw static display stuff */
{
/* Reset the active frame */
ActiveFrame = -1;
/* Clear the screen hide the cursor */
(void) bordercolor (COLOR_BORDER);
(void) bgcolor (COLOR_BACKGROUND);
clrscr ();
cursor (0);
/* Build the frame layout of the screen */
(void) textcolor (COLOR_FRAMELOW);
DrawFrames ();
/* Draw the prompt line */
HelpPrompt ();
/* Activate the active frame */
ActivateFrame (Frame, 0);
}
static void Redraw (char Frame)
/* Redraw the display in case it's garbled */
{
/* Redraw the static stuff */
RedrawStatic (Frame);
/* Init the window contents */
UpdateAsm ();
UpdateReg ();
UpdateStack ();
UpdateCStack ();
UpdateDump ();
}
static char GetKeyUpdate (void)
/* Wait for a key updating the windows in the background */
{
static unsigned char Win;
/* While there are no keys... */
while (!kbhit ()) {
switch (Win) {
case 0:
UpdateAsm ();
break;
case 1:
UpdateStack ();
break;
case 2:
UpdateCStack ();
break;
case 3:
UpdateDump ();
break;
}
Win = (Win + 1) & 0x03;
}
/* We have a key - return it */
return cgetc ();
}
/*****************************************************************************/
/* Externally visible functions */
/*****************************************************************************/
void DbgEntry (void)
/* Start up the debugger */
{
static unsigned char FirstTime = 1;
char c;
char done;
/* If this is the first call, setup the display */
if (FirstTime) {
FirstTime = 0;
/* Draw the window, default active frame is ASM frame */
RedrawStatic (WIN_ASM);
InitAsm ();
InitReg ();
InitStack ();
InitCStack ();
UpdateDump ();
}
/* Only initialize variables here, don't do a display update. The actual
* display update will be done while waiting for user input.
*/
AsmHome ();
UpdateReg (); /* Must update this (static later) */
StackHome ();
CStackHome ();
/* Wait for user input */
done = 0;
while (!done) {
c = Frames [ActiveFrame]->fd_func ();
switch (c) {
case '1':
case '2':
case '3':
case '4':
case '5':
ActivateFrame (c - '1', 0);
break;
case '?':
#ifdef CH_F1
case CH_F1:
#endif
HelpHandler ();
break;
case 'u':
#ifdef CH_F3
case CH_F3:
#endif
/* Go until return */
SetRTSBreak ();
done = 1;
break;
case 'h':
#ifdef CH_F4
case CH_F4:
#endif
/* Go to cursor, only possible if cursor not at current PC */
if (AsmAddr != brk_pc) {
DbgSetTmpBreak (AsmAddr);
done = 1;
}
break;
case ' ':
#ifdef CH_F7
case CH_F7:
#endif
SingleStep (1);
if (DbgTmpBreaksOk ()) {
/* Could set breakpoints */
done = 1;
}
break;
case '\n':
#ifdef CH_F8
case CH_F8:
#endif
SingleStep (0);
if (DbgTmpBreaksOk ()) {
/* Could set breakpoints */
done = 1;
}
break;
case 'c':
case 0:
done = 1;
break;
case 's':
/* Skip instruction */
brk_pc += DbgDisAsmLen (brk_pc);
InitAsm ();
break;
case 'r':
/* Redraw screen */
Redraw (ActiveFrame);
break;
case 'q':
/* Quit program */
clrscr ();
exit (1);
}
}
}