/* */ #ifndef __DEBUGGER_H__ #define __DEBUGGER_H__ #include "memory.h" #include "centry.h" void debugger_init(void); void debugger_enable(bool enable); INLINE bool debugger_enabled(void) { return !!(stateflag & ST_DEBUG); } void debugger(void); // operands for instructions typedef enum { OP_NONE=-1, // no operand // from ts/td field of opcode, don't change order OP_REG=0, // register Rx OP_IND=1, // indirect *Rx OP_ADDR=2, // address @>xxxx OP_INC=3, // register increment *Rx+ OP_IMMED, // immediate >xxxx OP_CNT, // shift count x (4 bits) OP_JUMP, // jump target >xxxx OP_OFFS, // offset >xxxx or ->xxxx OP_STATUS, // status word >xxxx OP_INST, // instruction for X } OperandType; #define OP_DEST_KILLED 2 typedef struct Operand { OperandType type; // type of operand u16 val; // value in opcode u16 immed; // immediate word u16 ea; // effective address of operand bool byteop; // for OP_REG...OP_INC bool dest; // operand changes (OP_DEST_KILLED=killed) bool ignore; // operand is not meaningful to display } Operand; #define OP_IS_MEMORY(op) \ (((op).type == OP_IND || (op).type == OP_ADDR || (op).type == OP_INC) \ && !(op).ignore) /* * Print out an operand into a disassembler operand */ char * debugger_instruction_operand_print(Operand *op, char *buffer); typedef struct Instruction { const char *name; // name of instruction u16 pc; // PC of opcode u16 wp; // current WP u16 status; // current status u16 opcode; // opcode Operand op1, op2; // operands of instruction } Instruction; /* * Print value of operand to buffer * * verbose==true means to print extra info * dest==true means print this operand as the result of * a previous instruction */ char * debugger_operand_value_print(Instruction *inst, Operand *op, bool verbose, bool dest, char *buffer); // memory views typedef enum { MEMORY_VIEW_CPU_1, MEMORY_VIEW_CPU_2, MEMORY_VIEW_VIDEO, MEMORY_VIEW_GRAPHICS, MEMORY_VIEW_SPEECH, MEMORY_VIEW_COUNT } MemoryView; // Struct keeps track of active addresses in the // areas of memory so frontend can maintain views typedef struct Memory { MemoryView which; // MEMORY_VIEW_xxx u16 base; // base address u16 addr; // last accessed addr int len; // last accessed length of memory u8 *mem; // pointer to that memory int coverage; // amount of times selected } Memory; // Size of area Memory is expected to cover (changed by frontend) extern int debugger_memory_view_size[MEMORY_VIEW_COUNT]; // Send verbose operand views (changed by frontend) extern bool debugger_operand_view_verbose; #define DOMAIN_TOKEN(dmn) ((dmn) == md_cpu ? '>' : \ (dmn) == md_graphics ? 'G' : \ (dmn) == md_video ? 'V' : \ (dmn) == md_speech ? 'S' : '?') #define MEMORY_VIEW_TOKEN(v) ((v) == MEMORY_VIEW_CPU_1 ? '>' : \ (v) == MEMORY_VIEW_CPU_2 ? '>' : \ (v) == MEMORY_VIEW_GRAPHICS ? 'G' : \ (v) == MEMORY_VIEW_VIDEO ? 'V' : \ (v) == MEMORY_VIEW_SPEECH ? 'S' : '?') /* * Utility for status reporters. Given the slot, it writes a one-line hex dump to * the given buffer, and sets start/astart and end/aend to point to the extent * of the last memory access within the buffer. (These will be spaces.) * * addr_separator: char appearing between address and bytes * byte_separator: char appearing between each hex byte * ascii_separator: char appearing between hex field and ascii field */ void debugger_hex_dump_line(Memory * slot, int offset, int length, char addr_separator, char byte_separator, char ascii_separator, char line_separator, char *buffer, int bufsz, char **start, char **end, char **astart, char **aend); /* * How long will this text be? */ int debugger_hex_dump_bytes_to_chars(int bytes); /* * How many bytes fit in this length? */ int debugger_hex_dump_chars_to_bytes(int chars); /* * Force updates of these items by sending system_report_status() messages */ void debugger_register_clear_view(void); void debugger_memory_clear_views(void); void debugger_instruction_clear_view(void); /* * Force next update to refresh all status items */ void debugger_refresh(void); /* * Check current PC to see if it's breakpointed */ int debugger_check_breakpoint(u16 pc); #include "cexit.h" #endif