365 lines
13 KiB
C++
365 lines
13 KiB
C++
#include "debug.h"
|
|
#include <SDL.h>
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
#include "stb_image.h"
|
|
#include "parser.h"
|
|
|
|
typedef unsigned char byte;
|
|
typedef unsigned short word;
|
|
|
|
static SDL_Window* debug_window = nullptr;
|
|
static Uint32 debug_window_id;
|
|
static SDL_Renderer* debug_renderer = nullptr;
|
|
static SDL_Texture* debug_texture = nullptr;
|
|
static SDL_Rect src, dst;
|
|
static Uint8 ink[4];
|
|
static Uint8 paper[4];
|
|
static unsigned char* debug_mem = nullptr;
|
|
|
|
static bool breakpoints[65536] {false};
|
|
|
|
static unsigned short* rX;
|
|
static unsigned char* rY;
|
|
static unsigned char* rZ;
|
|
static unsigned short* pc;
|
|
|
|
static char* program = nullptr;
|
|
static word* lines = nullptr;
|
|
|
|
static void debug_set_ink(const unsigned char r, const unsigned char g, const unsigned char b) {
|
|
ink[0] = r; ink[1] = g; ink[2] = b; ink[3] = 255;
|
|
SDL_SetRenderDrawColor(debug_renderer, ink[0], ink[1], ink[2], ink[3]);
|
|
SDL_SetTextureColorMod(debug_texture, ink[0], ink[1], ink[2]);
|
|
}
|
|
|
|
static void debug_set_paper(const unsigned char r, const unsigned char g, const unsigned char b) {
|
|
paper[0] = r; paper[1] = g; paper[2] = b; paper[3] = 255;
|
|
}
|
|
|
|
static void debug_draw_char(int x, int y, int c) {
|
|
src.x = (c & 0xf) << 3; src.y = (c >> 4) << 3;
|
|
dst.x = x << 3; dst.y = y << 3;
|
|
src.w = src.h = dst.w = dst.h = 8;
|
|
SDL_RenderCopy(debug_renderer, debug_texture, &src, &dst);
|
|
}
|
|
|
|
static void debug_print(int x, int y, const char* text) {
|
|
while (*text != 0) {
|
|
debug_draw_char(x, y, *text);
|
|
x++;
|
|
text++;
|
|
}
|
|
}
|
|
|
|
static void debug_print_ex(int x, int y, const unsigned char* text, int len) {
|
|
while (len != 0) {
|
|
debug_draw_char(x, y, *text);
|
|
x++; text++; len--;
|
|
}
|
|
}
|
|
|
|
static void debug_draw_outset(int x, int y, int w, int h) {
|
|
x = (x << 3) - 1; y = (y << 3) - 1; w = (w << 3) + 2; h = (h << 3) + 2;
|
|
SDL_SetRenderDrawColor(debug_renderer, 255, 255, 255, 255);
|
|
SDL_RenderDrawLine(debug_renderer, x, y, x, y + h);
|
|
SDL_RenderDrawLine(debug_renderer, x, y, x + w, y);
|
|
SDL_SetRenderDrawColor(debug_renderer, 0, 0, 0, 255);
|
|
SDL_RenderDrawLine(debug_renderer, x + w, y, x + w, y + h);
|
|
SDL_RenderDrawLine(debug_renderer, x, y + h, x + w, y + h);
|
|
SDL_SetRenderDrawColor(debug_renderer, ink[0], ink[1], ink[2], ink[3]);
|
|
}
|
|
|
|
static void debug_draw_inset(int x, int y, int w, int h) {
|
|
x = (x << 3) - 1; y = (y << 3) - 1; w = (w << 3) + 1; h = (h << 3) + 1;
|
|
SDL_SetRenderDrawColor(debug_renderer, 0, 0, 0, 255);
|
|
SDL_RenderDrawLine(debug_renderer, x, y, x, y + h);
|
|
SDL_RenderDrawLine(debug_renderer, x, y, x + w, y);
|
|
SDL_SetRenderDrawColor(debug_renderer, 255, 255, 255, 255);
|
|
SDL_RenderDrawLine(debug_renderer, x + w, y, x + w, y + h);
|
|
SDL_RenderDrawLine(debug_renderer, x, y + h, x + w, y + h);
|
|
SDL_SetRenderDrawColor(debug_renderer, ink[0], ink[1], ink[2], ink[3]);
|
|
}
|
|
|
|
static void debug_draw_rect(int x, int y, int w, int h) {
|
|
dst.x = (x << 3) - 1; dst.y = (y << 3) - 1; dst.w = (w << 3) + 2; dst.h = (h << 3) + 2;
|
|
SDL_RenderDrawRect(debug_renderer, &dst);
|
|
}
|
|
|
|
static void debug_fill_rect(int x, int y, int w, int h) {
|
|
dst.x = x << 3; dst.y = y << 3; dst.w = w << 3; dst.h = h << 3;
|
|
SDL_RenderFillRect(debug_renderer, &dst);
|
|
}
|
|
|
|
static void debug_clear() {
|
|
SDL_SetRenderDrawColor(debug_renderer, paper[0], paper[1], paper[2], paper[3]);
|
|
SDL_RenderClear(debug_renderer);
|
|
SDL_SetRenderDrawColor(debug_renderer, ink[0], ink[1], ink[2], ink[3]);
|
|
}
|
|
|
|
static void debug_draw_space(int x, int y, int w, int h, const char* title) {
|
|
debug_set_ink(64, 64, 64);
|
|
debug_fill_rect(x, y, w, h);
|
|
debug_draw_inset(x, y, w, h);
|
|
debug_set_ink(0, 0, 0);
|
|
debug_print(x, y-1, title);
|
|
}
|
|
|
|
static void debug_print_memory(word offset) {
|
|
debug_draw_space(1, 39, 37, 20, "MEMORY:");
|
|
debug_set_ink(255, 255, 255);
|
|
char cadena[255];
|
|
for (int i = 0; i < 20; i++) {
|
|
sprintf(cadena, "%.4X %.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X", offset, debug_mem[offset], debug_mem[offset + 1], debug_mem[offset + 2], debug_mem[offset + 3], debug_mem[offset + 4], debug_mem[offset + 5], debug_mem[offset + 6], debug_mem[offset + 7]);
|
|
debug_print(1, 39+i, cadena); debug_print_ex(30, 39+i, &debug_mem[offset], 8);
|
|
offset += 8;
|
|
}
|
|
}
|
|
|
|
static void debug_print_datastack(byte offset) {
|
|
debug_draw_space(72, 2, 3, 20, "DS:");
|
|
char cadena[10];
|
|
for (int i = 0; i < 20; i++) {
|
|
sprintf(cadena, "%.2X", debug_mem[0x8800 + i + offset]);
|
|
if (i + offset == 0) { debug_set_ink(255, 0, 0); }
|
|
else if(debug_mem[0x8800] == i + offset) { debug_set_ink(255, 255, 0); }
|
|
else { debug_set_ink(255, 255, 255); }
|
|
debug_print(72, 2 + i, cadena); debug_print_ex(74, 2 + i, &debug_mem[0x8800 + i + offset], 1);
|
|
}
|
|
}
|
|
|
|
static void debug_print_callstack(byte offset) {
|
|
debug_draw_space(76, 2, 3, 20, "CS:");
|
|
char cadena[10];
|
|
for (int i = 0; i < 20; i++) {
|
|
sprintf(cadena, "%.2X", debug_mem[0x8900 + i + offset]);
|
|
if (i + offset == 0) { debug_set_ink(255, 0, 0); }
|
|
else if (debug_mem[0x8900] == i + offset) { debug_set_ink(255, 255, 0); }
|
|
else { debug_set_ink(255, 255, 255); }
|
|
debug_print(76, 2 + i, cadena); debug_print_ex(78, 2 + i, &debug_mem[0x8900 + i + offset], 1);
|
|
}
|
|
}
|
|
|
|
static void debug_print_basic(byte offset) {
|
|
debug_draw_space(1, 2, 70, 35, "CODE:");
|
|
debug_set_ink(255, 255, 255);
|
|
if (*pc >= 0x8000) {
|
|
debug_print(17, 17, "No source code for this memory region");
|
|
return;
|
|
}
|
|
int line = offset;
|
|
int l = 0;
|
|
if (lines[*pc] >= 35) line = lines[*pc] + 30;
|
|
int row = 0;
|
|
char* prog = program;
|
|
if (lines[*pc] == line) { debug_set_ink(0, 0, 0); debug_fill_rect(1, 2 + l, 70, 1); debug_set_ink(255, 255, 0); }
|
|
else debug_set_ink(255, 255, 255);
|
|
while (line < 35 && *prog != 0) {
|
|
if (*prog == '\t') {
|
|
row += 4;
|
|
} else if (*prog == '\n') {
|
|
row = 0; line++; l++;
|
|
int bm = 0; while (lines[bm] < line) { bm++; }
|
|
if (breakpoints[bm]) { debug_set_ink(64, 0, 0); debug_fill_rect(1, 2 + l, 70, 1); }
|
|
if (lines[*pc] == line) { debug_set_ink(0, 0, 0); debug_fill_rect(1, 2 + l, 70, 1); debug_set_ink(255, 255, 0); }
|
|
else debug_set_ink(255, 255, 255);
|
|
} else if (*prog == 13) {
|
|
// row++;
|
|
} else {
|
|
if (row < 70) debug_draw_char(1 + row, 2 + l, *prog);
|
|
row++;
|
|
}
|
|
prog++;
|
|
}
|
|
}
|
|
|
|
static void debug_print_registers() {
|
|
debug_draw_space(72, 23, 6, 1, "rX:");
|
|
debug_draw_space(72, 25, 3, 1, "rY:");
|
|
debug_draw_space(72, 27, 3, 1, "rZ:");
|
|
debug_draw_space(72, 29, 6, 1, "PC:");
|
|
debug_set_ink(255, 255, 255);
|
|
char cadena[10];
|
|
sprintf(cadena, "%.4X", *rX);
|
|
debug_print(72, 23, cadena); debug_print_ex(76, 23, &debug_mem[0xFFFA], 2);
|
|
sprintf(cadena, "%.2X", *rY);
|
|
debug_print(72, 25, cadena); debug_print_ex(74, 25, &debug_mem[0xFFFC], 1);
|
|
sprintf(cadena, "%.2X", *rZ);
|
|
debug_print(72, 27, cadena); debug_print_ex(74, 27, &debug_mem[0xFFFD], 1);
|
|
sprintf(cadena, "%.4X", *pc);
|
|
debug_print(72, 29, cadena); debug_print_ex(76, 29, &debug_mem[0xFFFE], 2);
|
|
}
|
|
|
|
char asm_line[255];
|
|
static void get_op1(word& offset, const char* op) { sprintf(asm_line, "%.4X: %.2X %s", offset, debug_mem[offset], op); offset += 1; }
|
|
static void get_op2(word& offset, const char* op) { sprintf(asm_line, "%.4X: %.2X%.2X %s %.2X", offset, debug_mem[offset], debug_mem[offset + 1], op, debug_mem[offset + 1]); offset += 2; }
|
|
static void get_op3(word& offset, const char* op) { sprintf(asm_line, "%.4X: %.2X%.2X%.2X %s %.4X", offset, debug_mem[offset], debug_mem[offset + 1], debug_mem[offset + 2], op, debug_mem[offset + 1] + (debug_mem[offset + 2] << 8));; offset += 3; }
|
|
static char* get_asm_line(word& offset) {
|
|
|
|
//sprintf(asm_line, "%.4X ", offset);
|
|
switch (debug_mem[offset]) {
|
|
case OP_NOP: get_op1(offset, "NOP"); break;
|
|
case OP_PUSH: get_op2(offset, "PUSH"); break;
|
|
case OP_POP: get_op1(offset, "POP"); break;
|
|
case OP_DUP: get_op1(offset, "DUP"); break;
|
|
case OP_SWAP: get_op1(offset, "SWAP"); break;
|
|
|
|
case OP_LOAD: get_op3(offset, "LOAD"); break;
|
|
case OP_LOADI: get_op3(offset, "LOADI"); break;
|
|
case OP_STORE: get_op3(offset, "STORE"); break;
|
|
case OP_STOREI: get_op3(offset, "STOREI"); break;
|
|
|
|
case OP_LOADXY: get_op1(offset, "LOADXY"); break;
|
|
case OP_STOREXY: get_op1(offset, "STOREXY"); break;
|
|
case OP_SETX: get_op3(offset, "SETX"); break;
|
|
case OP_SETY: get_op1(offset, "SETY"); break;
|
|
case OP_SETZ: get_op1(offset, "SETZ"); break;
|
|
case OP_GETY: get_op1(offset, "GETY"); break;
|
|
case OP_GETZ: get_op1(offset, "GETZ"); break;
|
|
case OP_INCX: get_op1(offset, "INCX"); break;
|
|
case OP_DECX: get_op1(offset, "DECX"); break;
|
|
case OP_INCY: get_op1(offset, "INCY"); break;
|
|
case OP_DECY: get_op1(offset, "DECY"); break;
|
|
case OP_INCZ: get_op1(offset, "INCZ"); break;
|
|
case OP_DECZ: get_op1(offset, "DECZ"); break;
|
|
|
|
case OP_JMP: get_op3(offset, "JMP"); break;
|
|
case OP_JNT: get_op3(offset, "JNT"); break;
|
|
case OP_JTR: get_op3(offset, "JTR"); break;
|
|
case OP_JSR: get_op3(offset, "JSR"); break;
|
|
case OP_RET: get_op1(offset, "RET"); break;
|
|
case OP_CALL: get_op1(offset, "CALL"); break;
|
|
|
|
case OP_RJ: get_op2(offset, "RJ"); break;
|
|
case OP_RB: get_op2(offset, "RB"); break;
|
|
case OP_RJZ: get_op2(offset, "RJZ"); break;
|
|
case OP_RJN: get_op2(offset, "RJN"); break;
|
|
case OP_RBZ: get_op2(offset, "RBZ"); break;
|
|
case OP_RBN: get_op2(offset, "RBN"); break;
|
|
|
|
case OP_RJYZ: get_op2(offset, "RJYZ"); break;
|
|
case OP_RJYN: get_op2(offset, "RJYN"); break;
|
|
case OP_RBYZ: get_op2(offset, "RBYZ"); break;
|
|
case OP_RBYN: get_op2(offset, "RBYN"); break;
|
|
case OP_RJZZ: get_op2(offset, "RJZZ"); break;
|
|
case OP_RJZN: get_op2(offset, "RJZN"); break;
|
|
case OP_RBZZ: get_op2(offset, "RBZZ"); break;
|
|
case OP_RBZN: get_op2(offset, "RBZN"); break;
|
|
|
|
case OP_ADD: get_op1(offset, "ADD"); break;
|
|
case OP_SUB: get_op1(offset, "SUB"); break;
|
|
case OP_MUL: get_op1(offset, "MUL"); break;
|
|
case OP_DIV: get_op1(offset, "DIV"); break;
|
|
case OP_MOD: get_op1(offset, "MOD"); break;
|
|
case OP_AND: get_op1(offset, "AND"); break;
|
|
case OP_OR: get_op1(offset, "OR"); break;
|
|
case OP_NOT: get_op1(offset, "NOT"); break;
|
|
case OP_NEG: get_op1(offset, "NEG"); break;
|
|
case OP_INC: get_op1(offset, "INC"); break;
|
|
case OP_DEC: get_op1(offset, "DEC"); break;
|
|
case OP_CONCAT: get_op1(offset, "CONCAT"); break;
|
|
|
|
case OP_EQ: get_op1(offset, "EQ"); break;
|
|
case OP_NEQ: get_op1(offset, "NEQ"); break;
|
|
case OP_LT: get_op1(offset, "LT"); break;
|
|
case OP_GT: get_op1(offset, "GT"); break;
|
|
case OP_LEQ: get_op1(offset, "LEQ"); break;
|
|
case OP_GEQ: get_op1(offset, "GEQ"); break;
|
|
|
|
case OP_IN: get_op2(offset, "IN"); break;
|
|
case OP_OUT: get_op2(offset, "OUT"); break;
|
|
case OP_SLEEP: get_op1(offset, "SLEEP"); break;
|
|
default: sprintf(asm_line, "%.4X: ERROR: Unknown opcode: %.2X", offset, debug_mem[offset-1]); break;
|
|
}
|
|
return asm_line;
|
|
}
|
|
|
|
void debug_print_asm(byte offset) {
|
|
word pointer = *pc + offset;// if (pointer >= 10) pointer -= 10;
|
|
debug_draw_space(39, 39, 40, 20, "ASM:");
|
|
debug_set_ink(255, 255, 255);
|
|
char cadena[255];
|
|
for (int i = 0; i < 20; i++) {
|
|
if (*pc == pointer) { debug_set_ink(0, 0, 0); debug_fill_rect(39, 39 + i, 40, 1); debug_set_ink(255, 255, 0); }
|
|
else debug_set_ink(255, 255, 255);
|
|
debug_print(39, 39+i, get_asm_line(pointer));
|
|
//sprintf(cadena, "%.4X %.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X", offset, debug_mem[offset], debug_mem[offset + 1], debug_mem[offset + 2], debug_mem[offset + 3], debug_mem[offset + 4], debug_mem[offset + 5], debug_mem[offset + 6], debug_mem[offset + 7]);
|
|
//debug_print(1, 39 + i, cadena); debug_print_ex(30, 39 + i, &debug_mem[offset], 8);
|
|
//offset += 8;
|
|
}
|
|
|
|
}
|
|
|
|
void debug_init(unsigned char* mem) {
|
|
debug_mem = mem;
|
|
lines = parser_get_lines();
|
|
|
|
rX = (unsigned short*)&debug_mem[0xFFFA];
|
|
rY = &debug_mem[0xFFFC];
|
|
rZ = &debug_mem[0xFFFD];
|
|
pc = (unsigned short*)&debug_mem[0xFFFE];
|
|
|
|
debug_window = SDL_CreateWindow("Definitely PaCo Debugger", 1120, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
|
|
debug_renderer = SDL_CreateRenderer(debug_window, -1, SDL_RENDERER_PRESENTVSYNC);
|
|
debug_window_id = SDL_GetWindowID(debug_window);
|
|
SDL_SetRenderDrawColor(debug_renderer, 128, 128, 128, 255);
|
|
|
|
FILE* f = fopen("font.png", "rb");
|
|
int x = 128, y = 128, c;
|
|
Uint8* buffer = stbi_load_from_file(f, &x, &y, &c, 4);
|
|
debug_texture = SDL_CreateTexture(debug_renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, 128, 128);
|
|
SDL_UpdateTexture(debug_texture, NULL, buffer, 128 * sizeof(Uint32));
|
|
SDL_SetTextureBlendMode(debug_texture, SDL_BLENDMODE_BLEND);
|
|
stbi_image_free(buffer);
|
|
fclose(f);
|
|
|
|
f = fopen("test.bas", "rb");
|
|
fseek(f, 0, SEEK_END);
|
|
long fsize = ftell(f);
|
|
fseek(f, 0, SEEK_SET); //same as rewind(f);
|
|
program = (char*)malloc(fsize + 1);
|
|
fread(program, fsize, 1, f);
|
|
fclose(f);
|
|
program[fsize] = 0;
|
|
|
|
debug_update();
|
|
}
|
|
|
|
void debug_update() {
|
|
debug_set_paper(128, 128, 128);
|
|
debug_clear();
|
|
|
|
debug_print_memory(0);
|
|
debug_print_asm(0);
|
|
debug_print_datastack(0);
|
|
debug_print_callstack(0);
|
|
debug_print_registers();
|
|
debug_print_basic(0);
|
|
|
|
SDL_RenderPresent(debug_renderer);
|
|
}
|
|
|
|
void debug_hide() {
|
|
debug_set_paper(128, 128, 128);
|
|
debug_clear();
|
|
SDL_RenderPresent(debug_renderer);
|
|
}
|
|
|
|
void debug_mouse_event(SDL_Event& event) {
|
|
if (event.window.windowID != debug_window_id) return;
|
|
if (event.type == SDL_MOUSEBUTTONDOWN) {
|
|
int x, y;
|
|
Uint32 buttons = SDL_GetMouseState(&x, &y);
|
|
if (x >= 8 && x <= 568 && y >= 16 && y <= 296) {
|
|
int l = (y - 16) >> 3;
|
|
int bm = 0; while (lines[bm] < l) { bm++; }
|
|
breakpoints[bm] = !breakpoints[bm];
|
|
}
|
|
debug_update();
|
|
}
|
|
|
|
}
|
|
|
|
const bool* debug_get_breakpoints() {
|
|
return breakpoints;
|
|
}
|