Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First implementation of TI-Basic debugging (Fix #286) #457

Merged
merged 19 commits into from
Jan 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 81 additions & 3 deletions core/debug/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "../mem.h"
#include "../emu.h"
#include "../cpu.h"
#include "../vat.h"

#include <stdio.h>
#include <string.h>
Expand All @@ -19,6 +20,7 @@ void debug_init(void) {
debug.port = (uint8_t*)calloc(DBG_PORT_SIZE, sizeof(uint8_t));
debug.bufPos = debug.bufErrPos = 0;
debug.open = false;
debug_disable_basic_mode();
gui_console_printf("[CEmu] Initialized Debugger...\n");
}

Expand All @@ -40,6 +42,37 @@ void debug_open(int reason, uint32_t data) {

debug_clear_step();

/* fixup reason for basic debugger */
if (debug.basicMode == true) {
if (reason == DBG_WATCHPOINT_WRITE) {
if (data == DBG_BASIC_CURPC) {
reason = DBG_BASIC_CURPC_WRITE;
}
else if (data == DBG_BASIC_BEGPC) {
reason = DBG_BASIC_BEGPC_WRITE;
}
else if (data == DBG_BASIC_ENDPC) {
reason = DBG_BASIC_ENDPC_WRITE;
}
}
if (reason == DBG_WATCHPOINT_READ) {
if (data == DBG_BASIC_SYSHOOKFLAG2) {

// verify basic program execution
if ((mem_peek_byte(DBG_BASIC_NEWDISPF) & DBG_BASIC_PROGEXECUTING_BIT) &&
(mem_peek_byte(DBG_BASIC_CMDFLAGS) & DBG_BASIC_CMDEXEC_BIT)) {

// check current pc for instruction "bit 1,(iy+$36)"
if(*(uint32_t*)phys_mem_ptr(cpu.registers.PC - 4, 4) == 0x4E36CBFD) {
reason = DBG_BASIC_CURPC_WRITE;
}
} else {
return;
}
}
}
}

debug.cpuCycles = cpu.cycles;
debug.cpuNext = cpu.next;
debug.cpuBaseCycles = cpu.baseCycles;
Expand Down Expand Up @@ -94,7 +127,8 @@ void debug_step(int mode, uint32_t addr) {
debug.step = true;
break;
case DBG_STEP_OVER:
debug.step = debug.stepOver = true;
debug.step = true;
debug.stepOver = true;
break;
case DBG_STEP_OUT:
gui_debug_close();
Expand All @@ -105,12 +139,20 @@ void debug_step(int mode, uint32_t addr) {
gui_debug_close();
debug.tempExec = addr;
break;
case DBG_BASIC_STEP:
gui_debug_close();
debug.stepBasic = true;
break;
case DBG_BASIC_STEP_NEXT:
debug.stepBasicNext = true;
debug.stepBasicNextAddr = addr;
break;
}
}

void debug_clear_step(void) {
debug.step = debug.stepOver = false;
debug.tempExec = debug.stepOut = ~0;
debug.tempExec = debug.stepOut = ~0u;
}

void debug_inst_start(void) {
Expand Down Expand Up @@ -184,12 +226,48 @@ void debug_record_ret(uint32_t retAddr, bool mode) {
}
if (found && stepOut) {
debug.step = true;
debug.stepOut = ~0;
debug.stepOut = ~0u;
}
}

void debug_set_pc(uint32_t addr) {
cpu_flush(addr, cpu.ADL);
}

/* internal breakpoints not visible in gui */
/* the gui should automatically update breakpoints, so it should be */
/* fine if asm or C also uses these addresses */
void debug_enable_basic_mode(bool fetches) {
debug_watch(DBG_BASIC_BEGPC, DBG_MASK_WRITE, fetches);
debug_watch(DBG_BASIC_CURPC, DBG_MASK_WRITE, fetches);
debug_watch(DBG_BASIC_ENDPC, DBG_MASK_WRITE, fetches);
debug_watch(DBG_BASIC_SYSHOOKFLAG2, DBG_MASK_READ, !fetches);
}

void debug_disable_basic_mode(void) {
debug_watch(DBG_BASIC_BEGPC, DBG_MASK_WRITE, false);
debug_watch(DBG_BASIC_CURPC, DBG_MASK_WRITE, false);
debug_watch(DBG_BASIC_ENDPC, DBG_MASK_WRITE, false);
debug_watch(DBG_BASIC_SYSHOOKFLAG2, DBG_MASK_READ, false);
}

bool debug_get_executing_basic_prgm(char *name) {
if (name == NULL) {
return false;
}

/* check if a basic program is executing */
if ((mem_peek_byte(DBG_BASIC_NEWDISPF) & DBG_BASIC_PROGEXECUTING_BIT) &&
(mem_peek_byte(DBG_BASIC_CMDFLAGS) & DBG_BASIC_CMDEXEC_BIT)) {

/* return the executing program */
virt_mem_cpy(name, DBG_BASIC_BASIC_PROG, 9);
name[9] = '\0';

return true;
} else {
return false;
}
}

#endif
56 changes: 43 additions & 13 deletions core/debug/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,27 @@ extern "C" {

/* reason for debug trigger */
enum {
DBG_USER, /* request to open the debugger externally */
DBG_READY, /* if reset, debugger ready for new commands */
DBG_FROZEN, /* di \ halt */
DBG_BREAKPOINT, /* hit a breakpoint */
DBG_WATCHPOINT_READ, /* hit a read watchpoint */
DBG_WATCHPOINT_WRITE, /* hit a write watchpoint */
DBG_PORT_READ, /* read a monitored port */
DBG_PORT_WRITE, /* wrote a monitored port */
DBG_NMI_TRIGGERED, /* triggered a non maskable interrupt */
DBG_WATCHDOG_TIMEOUT, /* watchdog timer reset */
DBG_MISC_RESET, /* miscellaneous reset */
DBG_STEP, /* step command executed */
DBG_USER, /* request to open the debugger externally */
DBG_READY, /* if reset, debugger ready for new commands */
DBG_FROZEN, /* di \ halt */
DBG_BREAKPOINT, /* hit a breakpoint */
DBG_WATCHPOINT_READ, /* hit a read watchpoint */
DBG_WATCHPOINT_WRITE, /* hit a write watchpoint */
DBG_PORT_READ, /* read a monitored port */
DBG_PORT_WRITE, /* wrote a monitored port */
DBG_NMI_TRIGGERED, /* triggered a non maskable interrupt */
DBG_WATCHDOG_TIMEOUT, /* watchdog timer reset */
DBG_MISC_RESET, /* miscellaneous reset */
DBG_STEP, /* step command executed */
DBG_BASIC_USER, /* user requested a basic debug session */
DBG_BASIC_LIVE_START,
DBG_BASIC_BEGPC_READ, /* begpc read */
DBG_BASIC_CURPC_READ, /* curpc read */
DBG_BASIC_ENDPC_READ, /* endpc read */
DBG_BASIC_BEGPC_WRITE, /* begpc write */
DBG_BASIC_CURPC_WRITE, /* curpc write */
DBG_BASIC_ENDPC_WRITE, /* endpc write */
DBG_BASIC_LIVE_END,
DBG_NUMBER
};

Expand Down Expand Up @@ -67,6 +76,9 @@ void debug_flag(int mask, bool set); /* configure setup of debug
void debug_step(int mode, uint32_t addr); /* set a step mode, addr points to the instruction after pc */
void debug_open(int reason, uint32_t data); /* open the debugger (Should only be called from gui_do_stuff) */
bool debug_is_open(void); /* returns the status of the core debugger */
void debug_enable_basic_mode(bool fetches);
void debug_disable_basic_mode(void);
bool debug_get_executing_basic_prgm(char *name);

/* masks */
#define DBG_MASK_NONE (0 << 0)
Expand Down Expand Up @@ -100,6 +112,18 @@ bool debug_is_open(void); /* returns the status of th
#define DBG_PORT_SIZE 0x10000
#define SIZEOF_DBG_BUFFER 0x1000

/* tios specific debugging locations */
#define DBG_BASIC_BEGPC 0xD02317
#define DBG_BASIC_CURPC 0xD0231A
#define DBG_BASIC_ENDPC 0xD0231D
#define DBG_BASIC_BASIC_PROG 0xD0230E
#define DBG_BASIC_NEWDISPF 0xD00088
#define DBG_BASIC_CMDFLAGS 0xD0008C
#define DBG_BASIC_SYSHOOKFLAG2 0xD000B6
#define DBG_BASIC_PARSER_ACTIVE_BIT (1 << 1)
#define DBG_BASIC_CMDEXEC_BIT (1 << 6)
#define DBG_BASIC_PROGEXECUTING_BIT (1 << 1)

typedef struct {
bool mode : 1;
bool popped : 1;
Expand Down Expand Up @@ -132,6 +156,10 @@ typedef struct {
_Atomic(bool) ignore;
_Atomic(bool) commands;
_Atomic(bool) openOnReset;
bool basicMode;
bool stepBasic;
bool stepBasicNext;
uint32_t stepBasicNextAddr;
} debug_state_t;

extern debug_state_t debug;
Expand All @@ -141,7 +169,9 @@ enum {
DBG_STEP_OUT,
DBG_STEP_OVER,
DBG_STEP_NEXT,
DBG_RUN_UNTIL
DBG_RUN_UNTIL,
DBG_BASIC_STEP,
DBG_BASIC_STEP_NEXT,
};

/* internal core functions */
Expand Down
5 changes: 3 additions & 2 deletions core/link.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ int EMSCRIPTEN_KEEPALIVE emu_send_variables(const char *const *files, int num, i
void *progress_context) {
static const char *locations[] = { "-r", "-a", "" };

char **argv = malloc((1+num) * sizeof(char *));
const size_t argv_size = (1+num) * sizeof(char *);
char **argv = malloc(argv_size);
if (!argv) {
gui_console_printf("[CEmu] Transfer Error: can't allocate transfer commands... wut\n");
return LINK_ERR;
Expand All @@ -37,7 +38,7 @@ int EMSCRIPTEN_KEEPALIVE emu_send_variables(const char *const *files, int num, i
argv[0] = name;
for(int i=0; i<num; i++) {
argv[i+1] = malloc(7+strlen(files[i])+1);
sprintf(argv[i+1], "send%s:%s", locations[location], files[i]);
snprintf(argv[i+1], argv_size, "send%s:%s", locations[location], files[i]);
}
int err = usb_init_device(1+num, (const char *const *)argv, progress_handler, progress_context);
if (err != 0) {
Expand Down
3 changes: 2 additions & 1 deletion gui/qt/CEmu.pro
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@ SOURCES += \
archive/extractor.c \
../../core/bus.c \
keyhistorywidget.cpp \
tablewidget.cpp
tablewidget.cpp \
basicdebugger.cpp

linux|macx: SOURCES += ../../core/os/os-linux.c
win32: SOURCES += ../../core/os/os-win32.c win32-console.cpp
Expand Down
46 changes: 13 additions & 33 deletions gui/qt/basiccodeviewerwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,26 @@
#include "utils.h"

#include "tivars_lib_cpp/src/TypeHandlers/TypeHandlers.h"
#include "tivars_lib_cpp/src/tivarslib_utils.h"

#include "../../core/mem.h"

#include <QtGui/QPainter>
#include <QtWidgets/QScrollBar>
#include <QtWidgets/QMessageBox>

BasicEditor::BasicEditor(QWidget *parent) : QPlainTextEdit(parent)
{
highlighter = new BasicHighlighter(document());

lineNumberArea = new LineNumberArea(this);

QFont font = QFont(QStringLiteral("TICELarge"), 11);
lineNumberArea->setFont(font);

connect(this, &QPlainTextEdit::blockCountChanged, this, &BasicEditor::updateLineNumberAreaWidth);
connect(this, &QPlainTextEdit::updateRequest, this, &BasicEditor::updateLineNumberArea);
connect(this, &QPlainTextEdit::cursorPositionChanged, this, &BasicEditor::highlightCurrentLine);

updateLineNumberAreaWidth(0);
highlightCurrentLine();
}

void BasicEditor::toggleHighlight()
Expand Down Expand Up @@ -80,25 +81,6 @@ void BasicEditor::resizeEvent(QResizeEvent *e)
lineNumberArea->setGeometry(QRect(cr.left(), cr.top(), lineNumberAreaWidth(), cr.height()));
}

void BasicEditor::highlightCurrentLine()
{
QList<QTextEdit::ExtraSelection> extraSelections;

if (!isReadOnly()) {
QTextEdit::ExtraSelection selection;

const QColor lineColor = isRunningInDarkMode() ? QColor(Qt::black) : QColor(Qt::yellow).lighter(180);

selection.format.setBackground(lineColor);
selection.format.setProperty(QTextFormat::FullWidthSelection, true);
selection.cursor = textCursor();
selection.cursor.clearSelection();
extraSelections.append(selection);
}

setExtraSelections(extraSelections);
}

void BasicEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
{
QPainter painter(lineNumberArea);
Expand All @@ -107,19 +89,17 @@ void BasicEditor::lineNumberAreaPaintEvent(QPaintEvent *event)

QTextBlock block = firstVisibleBlock();
int blockNumber = block.blockNumber();
int top = (int) blockBoundingGeometry(block).translated(contentOffset()).top();
int bottom = top + (int) blockBoundingRect(block).height();
int top = static_cast<int>(blockBoundingGeometry(block).translated(contentOffset()).top());
int bottom = top + static_cast<int>(blockBoundingRect(block).height());

while (block.isValid() && top <= event->rect().bottom())
{
if (block.isVisible() && bottom >= event->rect().top())
{
while (block.isValid() && top <= event->rect().bottom()) {
if (block.isVisible() && bottom >= event->rect().top()) {
QString number = QString::number(blockNumber + 1);
painter.drawText(-2, top, lineNumberArea->width(), fontMetrics().height(), Qt::AlignRight, number);
}
block = block.next();
top = bottom;
bottom = top + (int) blockBoundingRect(block).height();
bottom = top + static_cast<int>(blockBoundingRect(block).height());
++blockNumber;
}
}
Expand Down Expand Up @@ -298,19 +278,19 @@ void BasicCodeViewerWindow::setOriginalCode(const QString &code, bool reindent)
}

void BasicCodeViewerWindow::toggleHighlight() {
m_showingHighlighted ^= true;
m_showingHighlighted = !m_showingHighlighted;
ui->basicEdit->toggleHighlight();
showCode();
}

void BasicCodeViewerWindow::toggleWrap() {
m_showingWrapped ^= true;
m_showingWrapped = !m_showingWrapped;
ui->basicEdit->setWordWrapMode(m_showingWrapped ? QTextOption::WrapAtWordBoundaryOrAnywhere : QTextOption::NoWrap);
showCode();
}

void BasicCodeViewerWindow::toggleFormat() {
m_showingFormatted ^= true;
m_showingFormatted = !m_showingFormatted;
const int scrollValue = ui->basicEdit->verticalScrollBar()->value();
ui->basicEdit->document()->setPlainText(m_showingFormatted ? m_formattedCode : m_originalCode);
ui->basicEdit->verticalScrollBar()->setValue(scrollValue);
Expand All @@ -322,7 +302,7 @@ void BasicCodeViewerWindow::showCode() {
ui->basicEdit->document()->setPlainText(m_showingFormatted ? m_formattedCode : m_originalCode);
hasCodeYet = true;
} else {
ui->basicEdit->repaint();
ui->basicEdit->update();
}
}

Expand Down
2 changes: 1 addition & 1 deletion gui/qt/basiccodeviewerwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <QtCore/QString>
#include <QtCore/QRegularExpression>
#include <QtCore/QObject>
#include <QtCore/QTimer>
#include <QtWidgets/QDialog>
#include <QtWidgets/QPlainTextEdit>
#include <QtGui/QSyntaxHighlighter>
Expand Down Expand Up @@ -70,7 +71,6 @@ class BasicEditor : public QPlainTextEdit

private slots:
void updateLineNumberAreaWidth(int newBlockCount);
void highlightCurrentLine();
void updateLineNumberArea(const QRect &, int);

private:
Expand Down
Loading