mirror of
https://github.com/pevans/erc-c.git
synced 2025-02-17 07:32:05 +00:00
Add prompt; quit command; breakpoints
This commit is contained in:
parent
d4891a3fbf
commit
588362abee
@ -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
|
||||
|
11
src/apple2.c
11
src/apple2.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) */
|
||||
|
Loading…
x
Reference in New Issue
Block a user