1
0
mirror of https://github.com/pevans/erc-c.git synced 2024-09-28 04:57:44 +00:00

Add prompt; quit command; breakpoints

This commit is contained in:
Peter Evans 2018-02-25 14:25:02 -06:00
parent d4891a3fbf
commit 588362abee
4 changed files with 154 additions and 3 deletions

View File

@ -1,6 +1,8 @@
#ifndef _VM_DEBUG_H_
#define _VM_DEBUG_H_
#include <stdbool.h>
struct vm_debug_args;
typedef struct vm_debug_args vm_debug_args;
@ -64,14 +66,20 @@ struct vm_debug_args {
#define DEBUG_CMD(x) \
void vm_debug_cmd_##x (vm_debug_args *args)
extern bool vm_debug_broke(int);
extern char *vm_debug_prompt();
extern vm_debug_cmd *vm_debug_find_cmd(const char *);
extern void vm_debug_break(int);
extern void vm_debug_execute(const char *);
extern void vm_debug_quit();
extern DEBUG_CMD(help);
extern DEBUG_CMD(jump);
extern DEBUG_CMD(printaddr);
extern DEBUG_CMD(printstate);
extern DEBUG_CMD(quit);
extern DEBUG_CMD(resume);
extern DEBUG_CMD(writeaddr);
extern DEBUG_CMD(writestate);
#endif

View File

@ -15,7 +15,9 @@
#include "mos6502.dis.h"
#include "objstore.h"
#include "option.h"
#include "vm_debug.h"
#include "vm_di.h"
#include "vm_reflect.h"
#include "vm_segment.h"
/*
@ -346,11 +348,18 @@ apple2_run_loop(apple2 *mach)
}
out = (FILE *)vm_di_get(VM_OUTPUT);
vm_reflect_pause(NULL);
while (vm_screen_active(mach->screen)) {
// If we're paused, then just re-loop until we're not
if (mach->paused) {
usleep(100000); // but rest our weary head for a bit
char *input = vm_debug_prompt();
if (input != NULL) {
vm_debug_execute(input);
}
free(input);
continue;
}

View File

@ -2,6 +2,7 @@
* vm_debug.c
*/
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@ -12,6 +13,18 @@
#include "vm_di.h"
#include "vm_reflect.h"
/*
* The largest address size we can set a breakpoint for
*/
#define BREAKPOINTS_MAX 0x10000
/*
* A table of breakpoints, arranged by address in a CPU. If
* breakpoints[i] is zero, then there is no breakpoint. If it is
* non-zero, then there is a breakpoint at address i.
*/
static int breakpoints[BREAKPOINTS_MAX];
vm_debug_cmd cmdtable[] = {
{ "help", "h", vm_debug_cmd_help, 0, "",
"Print out this list of commands", },
@ -21,10 +34,14 @@ vm_debug_cmd cmdtable[] = {
"Print the value at memory address <addr>", },
{ "printstate", "ps", vm_debug_cmd_printstate, 0, "",
"Print the machine and CPU state", },
{ "quit", "q", vm_debug_cmd_quit, 0, "",
"Quit the emulator", },
{ "resume", "r", vm_debug_cmd_resume, 0, "",
"Resume execution", },
{ "writeaddr", "wa", vm_debug_cmd_writeaddr, 2, "<addr> <byte>",
"Write <byte> at <addr>", },
{ "writestate", "ws", vm_debug_cmd_writestate, 2, "<reg> <byte>",
"Write <byte> into <reg>", },
};
#define CMDTABLE_SIZE (sizeof(cmdtable) / sizeof(vm_debug_cmd))
@ -34,7 +51,7 @@ vm_debug_next_arg(char **str)
{
char *tok;
while ((tok = strsep(str, " "))) {
while ((tok = strsep(str, " "))){
if (tok == NULL) {
return NULL;
}
@ -46,7 +63,8 @@ vm_debug_next_arg(char **str)
break;
}
return tok; }
return tok;
}
int
vm_debug_addr(const char *str)
@ -65,6 +83,48 @@ vm_debug_addr(const char *str)
return addr;
}
void
vm_debug_break(int addr)
{
if (addr < 0 || addr >= BREAKPOINTS_MAX) {
return;
}
breakpoints[addr] = 1;
}
bool
vm_debug_broke(int addr)
{
if (addr < 0 || addr >= BREAKPOINTS_MAX) {
return false;
}
return breakpoints[addr] != 0;
}
char *
vm_debug_prompt()
{
char buf[256];
FILE *stream = (FILE *)vm_di_get(VM_OUTPUT);
if (feof(stdin)) {
return NULL;
}
fputs("erc> ", stream);
if (fgets(buf, 256, stdin) == NULL) {
return NULL;
}
// Cut off the newline character, if there is one
buf[strlen(buf)-1] = '\0';
return strdup(buf);
}
void
vm_debug_execute(const char *str)
{
@ -126,6 +186,8 @@ vm_debug_execute(const char *str)
}
cmd->handler(&args);
free(ebuf);
}
static int
@ -200,3 +262,21 @@ DEBUG_CMD(writeaddr)
mos6502 *cpu = (mos6502 *)vm_di_get(VM_CPU);
mos6502_set(cpu, args->addr1, args->addr2);
}
DEBUG_CMD(writestate)
{
mos6502 *cpu = (mos6502 *)vm_di_get(VM_CPU);
switch (tolower(*args->target)) {
case 'a': cpu->A = args->addr1; break;
case 'p': cpu->P = args->addr1; break;
case 's': cpu->S = args->addr1; break;
case 'x': cpu->X = args->addr1; break;
case 'y': cpu->Y = args->addr1; break;
}
}
DEBUG_CMD(quit)
{
exit(0);
}

View File

@ -124,3 +124,57 @@ Test(vm_debug, cmd_writeaddr)
vm_debug_cmd_writeaddr(&args);
cr_assert_eq(mos6502_get(mach->cpu, args.addr1), args.addr2);
}
Test(vm_debug, cmd_writestate)
{
args.addr1 = 111;
args.target = "a";
vm_debug_cmd_writestate(&args);
cr_assert_eq(mach->cpu->A, args.addr1);
args.addr1 = 112;
args.target = "x";
vm_debug_cmd_writestate(&args);
cr_assert_eq(mach->cpu->X, args.addr1);
args.addr1 = 113;
args.target = "y";
vm_debug_cmd_writestate(&args);
cr_assert_eq(mach->cpu->Y, args.addr1);
args.addr1 = 114;
args.target = "p";
vm_debug_cmd_writestate(&args);
cr_assert_eq(mach->cpu->P, args.addr1);
args.addr1 = 115;
args.target = "s";
vm_debug_cmd_writestate(&args);
cr_assert_eq(mach->cpu->S, args.addr1);
}
Test(vm_debug, break)
{
vm_debug_break(0x2);
mos6502_set(mach->cpu, 0, 0xEA);
mos6502_set(mach->cpu, 1, 0xEA);
mos6502_set(mach->cpu, 2, 0xEA);
mos6502_set(mach->cpu, 3, 0xEA);
mos6502_execute(mach->cpu);
cr_assert_eq(mach->cpu->PC, 1);
mos6502_execute(mach->cpu);
cr_assert_eq(mach->cpu->PC, 2);
mos6502_execute(mach->cpu);
cr_assert_eq(mach->cpu->PC, 2);
}
Test(vm_debug, broke)
{
cr_assert_eq(vm_debug_broke(0x23), false);
vm_debug_break(0x23);
cr_assert_eq(vm_debug_broke(0x23), true);
}
/* Test(vm_debug, quit) */