gbdb: add scripting features for automatic testing
This commit is contained in:
164
gbdb_boot_test
Normal file
164
gbdb_boot_test
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
bootrom ../bootrom.gb
|
||||||
|
echo Running test...
|
||||||
|
set quiet 1
|
||||||
|
|
||||||
|
assert $pc == 0
|
||||||
|
step
|
||||||
|
|
||||||
|
# Executed LD SP, D16 (0xfffe)
|
||||||
|
assert $pc == 3
|
||||||
|
assert $sp == 0xfffe
|
||||||
|
step
|
||||||
|
|
||||||
|
# Executed XOR A
|
||||||
|
assert $pc == 4
|
||||||
|
assert $a == 0
|
||||||
|
step
|
||||||
|
|
||||||
|
assert $pc == 7
|
||||||
|
assert $hl == 0x9fff
|
||||||
|
step
|
||||||
|
|
||||||
|
assert $pc == 8
|
||||||
|
assert $hl == 0x9ffe
|
||||||
|
step
|
||||||
|
|
||||||
|
assert $pc == 10
|
||||||
|
assert $f == 0x2
|
||||||
|
step
|
||||||
|
|
||||||
|
breakpoint add 0xc
|
||||||
|
step 100000
|
||||||
|
breakpoint del 0
|
||||||
|
|
||||||
|
assert $pc == 0xc
|
||||||
|
assert $hl == 0x7fff
|
||||||
|
|
||||||
|
# TODO: There is a bug in GBDB where breakpoints fire at the start of an
|
||||||
|
# instruction and "step" stops at the end of an instruction
|
||||||
|
step; step
|
||||||
|
|
||||||
|
assert $pc == 0xf
|
||||||
|
assert $hl == 0xff26
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x11
|
||||||
|
assert $c == 0x11
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x13
|
||||||
|
assert $a == 0x80
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x14
|
||||||
|
assert $hl == 0xff25
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x15
|
||||||
|
# LD (0xFF00 + $C), A
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x16
|
||||||
|
assert $c == 0x12
|
||||||
|
|
||||||
|
|
||||||
|
break add 0x27
|
||||||
|
step 1000
|
||||||
|
assert $pc == 0x27
|
||||||
|
break del 0
|
||||||
|
|
||||||
|
step; step
|
||||||
|
assert $pc == 0x28
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x95
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x96
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x98
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x99
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x9b
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x9c
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x9d
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x9f
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0xa0
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0xa1
|
||||||
|
|
||||||
|
break add 0xa3
|
||||||
|
step 100000
|
||||||
|
break del 0
|
||||||
|
assert $pc == 0xa3
|
||||||
|
step #FIXME: bugs
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0xa4
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0xa5
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0xa6
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0xa7
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x2b
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x96
|
||||||
|
|
||||||
|
break add 0x34
|
||||||
|
step 10000
|
||||||
|
assert $pc == 0x34
|
||||||
|
break del 0
|
||||||
|
|
||||||
|
step; step
|
||||||
|
assert $pc == 0x37
|
||||||
|
assert $de == 0xd8
|
||||||
|
|
||||||
|
step;
|
||||||
|
assert $pc == 0x39
|
||||||
|
assert $b == 0x08
|
||||||
|
|
||||||
|
break add 0x40
|
||||||
|
step 10000
|
||||||
|
assert $pc == 0x40
|
||||||
|
assert $b == 0
|
||||||
|
break del 0
|
||||||
|
|
||||||
|
step; step
|
||||||
|
assert $pc == 0x42
|
||||||
|
assert $a == 0x19
|
||||||
|
|
||||||
|
step;
|
||||||
|
assert $pc == 0x45
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x48
|
||||||
|
assert $hl == 0x992f
|
||||||
|
|
||||||
|
step
|
||||||
|
assert $pc == 0x4a
|
||||||
|
assert $c == 0x0c
|
||||||
|
|
||||||
|
echo Test passed!
|
||||||
|
regs
|
||||||
|
|
||||||
|
# exit
|
||||||
369
src/apps/gbdb.c
369
src/apps/gbdb.c
@@ -7,8 +7,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
#include "gb_disas.h"
|
#include "gb_disas.h"
|
||||||
@@ -37,27 +39,6 @@ static const char usage[] =
|
|||||||
"peek: view the next instruction to run\n"
|
"peek: view the next instruction to run\n"
|
||||||
"exit: quit the program\n";
|
"exit: quit the program\n";
|
||||||
|
|
||||||
static const char *reg16_names[] = {
|
|
||||||
"AF",
|
|
||||||
"BC",
|
|
||||||
"DE",
|
|
||||||
"HL",
|
|
||||||
"SP",
|
|
||||||
"PC",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char *reg8_names[] = {
|
|
||||||
"B",
|
|
||||||
"C",
|
|
||||||
"D",
|
|
||||||
"E",
|
|
||||||
"H",
|
|
||||||
"L",
|
|
||||||
"N/A",
|
|
||||||
"A",
|
|
||||||
"F"
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct lr35902_state cpu;
|
static struct lr35902_state cpu;
|
||||||
static struct gb_video video;
|
static struct gb_video video;
|
||||||
|
|
||||||
@@ -66,17 +47,30 @@ static unsigned char bootrom[0x100] = {0};
|
|||||||
static int bootrom_mapped = 1;
|
static int bootrom_mapped = 1;
|
||||||
static volatile sig_atomic_t paused = 0;
|
static volatile sig_atomic_t paused = 0;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
bool quiet;
|
||||||
|
} config;
|
||||||
|
|
||||||
|
static void gb_log(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
|
||||||
|
if (config.quiet) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vprintf(fmt, args);
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void break_execution_handler(int signum)
|
static void break_execution_handler(int signum)
|
||||||
{
|
{
|
||||||
paused = 1;
|
paused = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* ram_{read,write} work easily because the cartridge is mapped to 0x0000
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void strip_newline(char *string)
|
static void strip_newline(char *string)
|
||||||
{
|
{
|
||||||
char *pos;
|
char *pos;
|
||||||
@@ -89,6 +83,10 @@ static void strip_newline(char *string)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ram_{read,write} work easily because the cartridge is mapped to 0x0000
|
||||||
|
*
|
||||||
|
*/
|
||||||
static uint8_t mem_read(struct lr35902_state *cpu, uint16_t addr)
|
static uint8_t mem_read(struct lr35902_state *cpu, uint16_t addr)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -113,7 +111,7 @@ static void mem_write(struct lr35902_state *cpu, uint16_t addr, uint8_t val)
|
|||||||
case UNMAP_BOOTROM_ADDR:
|
case UNMAP_BOOTROM_ADDR:
|
||||||
if (val == 1) {
|
if (val == 1) {
|
||||||
bootrom_mapped = 0;
|
bootrom_mapped = 0;
|
||||||
printf("bootrom unmapped\n");
|
gb_log("bootrom unmapped\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xFF40 ... 0xFF4B:
|
case 0xFF40 ... 0xFF4B:
|
||||||
@@ -137,13 +135,13 @@ static void mem_dump(char *filename)
|
|||||||
char *token = strtok(filename, " ");
|
char *token = strtok(filename, " ");
|
||||||
|
|
||||||
if (token == NULL) {
|
if (token == NULL) {
|
||||||
printf("usage: load <file>\n");
|
gb_log("usage: load <file>\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
strip_newline(token);
|
strip_newline(token);
|
||||||
dump_file = fopen(token, "w");
|
dump_file = fopen(token, "w");
|
||||||
if(dump_file == NULL) {
|
if(dump_file == NULL) {
|
||||||
printf("Failed to open mem dump file: %d\n", errno);
|
gb_log("Failed to open mem dump file: %d\n", errno);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fwrite(ram, MAX_RAM_LEN, 1, dump_file);
|
fwrite(ram, MAX_RAM_LEN, 1, dump_file);
|
||||||
@@ -170,10 +168,24 @@ static void show_prompt()
|
|||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set(char *arg_list)
|
||||||
|
{
|
||||||
|
/* TODO make this support other options */
|
||||||
|
config.quiet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void echo(char *arg_list)
|
||||||
|
{
|
||||||
|
if (arg_list != NULL) {
|
||||||
|
printf("%s\n", arg_list);
|
||||||
|
} else {
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void step(char *arg_list)
|
static void step(char *arg_list)
|
||||||
{
|
{
|
||||||
uint64_t steps;
|
uint64_t steps, init_steps;
|
||||||
int i = 0;
|
|
||||||
char *token;
|
char *token;
|
||||||
token = strtok(arg_list, " ");
|
token = strtok(arg_list, " ");
|
||||||
if (token == NULL) {
|
if (token == NULL) {
|
||||||
@@ -185,35 +197,36 @@ static void step(char *arg_list)
|
|||||||
|
|
||||||
paused = 0;
|
paused = 0;
|
||||||
signal(SIGINT, break_execution_handler);
|
signal(SIGINT, break_execution_handler);
|
||||||
|
init_steps = cpu.metrics.retired_instrs;
|
||||||
do {
|
do {
|
||||||
cycle();
|
cycle();
|
||||||
i++;
|
} while (init_steps + steps > cpu.metrics.retired_instrs &&
|
||||||
} while (i < steps && !cpu_at_breakpoint() && !cpu.halted && !paused);
|
!cpu_at_breakpoint() &&
|
||||||
|
!cpu.halted &&
|
||||||
|
!paused);
|
||||||
|
|
||||||
if (i == steps) {
|
if (init_steps + steps <= cpu.metrics.retired_instrs) {
|
||||||
printf("CPU stopped after %d cycles\n", i);
|
gb_log("CPU stopped after %" PRId64 " instructions\n", steps);
|
||||||
} else if (cpu_at_breakpoint()) {
|
} else if (cpu_at_breakpoint()) {
|
||||||
printf("Breakpoint hit\n");
|
gb_log("Breakpoint hit\n");
|
||||||
} else if (cpu.halted) {
|
} else if (cpu.halted) {
|
||||||
printf("CPU halted\n");
|
gb_log("CPU halted\n");
|
||||||
} else {
|
} else {
|
||||||
printf("Interrupted after %d cycles\n", i);
|
gb_log("Interrupted\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void regs(char *arg_list)
|
static void regs(char *arg_list)
|
||||||
{
|
{
|
||||||
int i;
|
uint8_t f = (cpu.nf << CPU_F_BIT_POS_N) | (cpu.zf << CPU_F_BIT_POS_Z) |
|
||||||
|
(cpu.cf << CPU_F_BIT_POS_C) | (cpu.hf << CPU_F_BIT_POS_H);
|
||||||
|
|
||||||
for(i = 0; i < NUM_LR35902_REGS_8; i++){
|
printf("AF: 0x%04x A: 0x%02x F: 0x%02x\n", (uint16_t) (cpu.a << 8) | f, cpu.a, f);
|
||||||
if (i != LR35902_REG_HL_DEREF) {
|
printf("BC: 0x%04x B: 0x%02x C: 0x%02x\n", cpu.bc, cpu.b, cpu.c);
|
||||||
printf("%s: 0x%02x\n", reg8_names[i], lr35902_get_reg_8(&cpu, i));
|
printf("DE: 0x%04x D: 0x%02x E: 0x%02x\n", cpu.de, cpu.d, cpu.e);
|
||||||
};
|
printf("HL: 0x%04x H: 0x%02x L: 0x%02x\n", cpu.hl, cpu.h, cpu.l);
|
||||||
}
|
printf("PC: 0x%04x\n", cpu.pc);
|
||||||
for(i = 0; i < NUM_LR35902_REGS_16; i++){
|
printf("SP: 0x%04x\n", cpu.sp);
|
||||||
printf("%s: 0x%04x\n", reg16_names[i], lr35902_get_reg_16(&cpu, i));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void peek(char *arg_list)
|
static void peek(char *arg_list)
|
||||||
@@ -236,6 +249,107 @@ static void help(char *arg_list)
|
|||||||
printf(usage);
|
printf(usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int64_t parse_reg_str(const char *str)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const struct {
|
||||||
|
const char *str;
|
||||||
|
int64_t value;
|
||||||
|
} entries[] = {
|
||||||
|
//{ "af", cpu,af },
|
||||||
|
{ "bc", cpu.bc },
|
||||||
|
{ "de", cpu.de },
|
||||||
|
{ "sp", cpu.sp },
|
||||||
|
{ "pc", cpu.pc },
|
||||||
|
{ "hl", cpu.hl },
|
||||||
|
{ "a", cpu.a },
|
||||||
|
{ "b", cpu.b },
|
||||||
|
{ "c", cpu.c },
|
||||||
|
{ "d", cpu.d },
|
||||||
|
{ "e", cpu.e },
|
||||||
|
{ "f", (cpu.zf << 3) | (cpu.nf << 2) | (cpu.hf << 1) | (cpu.cf << 0) },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(entries); i++) {
|
||||||
|
if (strncmp(str, entries[i].str, strlen(entries[i].str)) == 0) {
|
||||||
|
return entries[i].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t parse_val(const char *str)
|
||||||
|
{
|
||||||
|
if (str[0] == '$') {
|
||||||
|
return parse_reg_str(str + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return strtoll(str, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assert(char *arg_list)
|
||||||
|
{
|
||||||
|
char *val0_str, *val1_str, *operator_str;
|
||||||
|
const char *usage = "usage: assert <value> <operator> <value>\n";
|
||||||
|
int64_t val0, val1;
|
||||||
|
|
||||||
|
val0_str = strtok(arg_list, " ");
|
||||||
|
if (val0_str == NULL) {
|
||||||
|
printf("%s", usage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
val0 = parse_val(val0_str);
|
||||||
|
|
||||||
|
operator_str = strtok(NULL, " ");
|
||||||
|
if (operator_str == NULL) {
|
||||||
|
printf("%s", usage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
val1_str = strtok(NULL, " ");
|
||||||
|
if (val1_str == NULL) {
|
||||||
|
printf("%s", usage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
val1 = parse_val(val1_str);
|
||||||
|
|
||||||
|
if (strcmp(operator_str, "==") == 0) {
|
||||||
|
if (!(val0 == val1)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else if (strcmp(operator_str, "!=") == 0) {
|
||||||
|
if (!(val0 != val1)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else if (strcmp(operator_str, ">=") == 0) {
|
||||||
|
if (!(val0 >= val1)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else if (strcmp(operator_str, "<=") == 0) {
|
||||||
|
if (!(val0 <= val1)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else if (strcmp(operator_str, "<") == 0) {
|
||||||
|
if (!(val0 < val1)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else if (strcmp(operator_str, ">") == 0) {
|
||||||
|
if (!(val0 > val1)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("%s", usage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
fail:
|
||||||
|
printf("ASSERT: %s %s %s\n", val0_str, operator_str, val1_str);
|
||||||
|
printf("%s=%ld, %s=%ld\n", val0_str, val0, val1_str, val1);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
static void mem(char *arg_list)
|
static void mem(char *arg_list)
|
||||||
{
|
{
|
||||||
uint16_t addr, bytes, i;
|
uint16_t addr, bytes, i;
|
||||||
@@ -246,12 +360,12 @@ static void mem(char *arg_list)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = strtol(token, NULL, 0);
|
addr = parse_val(token);
|
||||||
token = strtok(NULL, " ");
|
token = strtok(NULL, " ");
|
||||||
if (token == NULL) {
|
if (token == NULL) {
|
||||||
bytes = 1;
|
bytes = 1;
|
||||||
} else {
|
} else {
|
||||||
bytes = strtol(token, NULL, 0);
|
bytes = parse_val(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
token = strtok(NULL, " ");
|
token = strtok(NULL, " ");
|
||||||
@@ -333,11 +447,11 @@ static void run(char *arg_list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cpu.halted) {
|
if (cpu.halted) {
|
||||||
printf("CPU halted after %ld cycles\n", cpu.metrics.cycles);
|
gb_log("CPU halted after %ld cycles\n", cpu.metrics.cycles);
|
||||||
} else if (paused) {
|
} else if (paused) {
|
||||||
printf("Interrupted.\n");
|
gb_log("Interrupted.\n");
|
||||||
} else {
|
} else {
|
||||||
printf("Breakpoint hit\n");
|
gb_log("Breakpoint hit\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,7 +470,7 @@ static void set_breakpoint(char *arg_string)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = strtol(token, NULL, 0);
|
addr = parse_val(token);
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(breakpoints); i++) {
|
for (i = 0; i < ARRAY_SIZE(breakpoints); i++) {
|
||||||
if (breakpoints[i].active == false) {
|
if (breakpoints[i].active == false) {
|
||||||
@@ -379,7 +493,7 @@ static void delete_breakpoint(char *arg_string)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bkpt = strtol(token, NULL, 0);
|
bkpt = parse_val(token);
|
||||||
|
|
||||||
if (bkpt < 0 || bkpt >= ARRAY_SIZE(breakpoints) || !breakpoints[bkpt].active) {
|
if (bkpt < 0 || bkpt >= ARRAY_SIZE(breakpoints) || !breakpoints[bkpt].active) {
|
||||||
printf("%d is not a valid breakpoint number\n", bkpt);
|
printf("%d is not a valid breakpoint number\n", bkpt);
|
||||||
@@ -465,70 +579,27 @@ static bool cpu_at_breakpoint(void)
|
|||||||
return breakpoint_is_at_addr(lr35902_get_reg_16(&cpu, LR35902_REG_PC));
|
return breakpoint_is_at_addr(lr35902_get_reg_16(&cpu, LR35902_REG_PC));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_cmd(char *cmd)
|
static void process_cmd(const char *cmd_str, struct tri *commands)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
struct tri commands;
|
|
||||||
char line_buffer[INPUT_MAX_LEN]; /* Buffer for input command */
|
|
||||||
char old_buffer[INPUT_MAX_LEN]; /* Buffer for previous input */
|
|
||||||
char cmd_buffer[INPUT_MAX_LEN]; /* Buffer for command parsing */
|
char cmd_buffer[INPUT_MAX_LEN]; /* Buffer for command parsing */
|
||||||
|
|
||||||
line_buffer[0] = '\0';
|
|
||||||
old_buffer[0] = '\0';
|
|
||||||
|
|
||||||
tri_init(&commands);
|
|
||||||
tri_add_string(&commands, "step", step);
|
|
||||||
tri_add_string(&commands, "run", run);
|
|
||||||
tri_add_string(&commands, "regs", regs);
|
|
||||||
tri_add_string(&commands, "stats", stats);
|
|
||||||
tri_add_string(&commands, "exit", quit);
|
|
||||||
tri_add_string(&commands, "quit", quit);
|
|
||||||
tri_add_string(&commands, "load", load);
|
|
||||||
tri_add_string(&commands, "bootrom", load_bootrom);
|
|
||||||
tri_add_string(&commands, "mem", mem);
|
|
||||||
tri_add_string(&commands, "dump", mem_dump);
|
|
||||||
tri_add_string(&commands, "peek", peek);
|
|
||||||
tri_add_string(&commands, "help", help);
|
|
||||||
tri_add_string(&commands, "?", help);
|
|
||||||
tri_add_string(&commands, "breakpoint", breakpoint);
|
|
||||||
tri_add_string(&commands, "reset", init);
|
|
||||||
|
|
||||||
init();
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
bool ambiguous;
|
bool ambiguous;
|
||||||
gbdb_cmd *cmd;
|
gbdb_cmd *cmd;
|
||||||
|
|
||||||
/* String to use for input (line_buffer or
|
|
||||||
* old_buffer) */
|
|
||||||
char *cmd_str;
|
|
||||||
|
|
||||||
/* Current point in the line (there may be more than
|
/* Current point in the line (there may be more than
|
||||||
* one command on a line) */
|
* one command on a line) */
|
||||||
char *process_str;
|
const char *process_str;
|
||||||
|
|
||||||
/* String containing the arguments following a command */
|
/* String containing the arguments following a command */
|
||||||
char *arg_str;
|
char *arg_str;
|
||||||
|
|
||||||
show_prompt();
|
|
||||||
cmd_str = fgets(line_buffer, INPUT_MAX_LEN, stdin);
|
|
||||||
if (cmd_str == NULL) {
|
|
||||||
printf("\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (line_buffer[0] != '\n') {
|
|
||||||
cmd_str = line_buffer;
|
|
||||||
strncpy(old_buffer, line_buffer, INPUT_MAX_LEN);
|
|
||||||
} else {
|
|
||||||
cmd_str = old_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
process_str = cmd_str;
|
process_str = cmd_str;
|
||||||
|
|
||||||
|
char *comment;
|
||||||
|
comment = strchr(process_str, '#');
|
||||||
|
if (comment != NULL) {
|
||||||
|
*comment = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -550,7 +621,11 @@ int main(int argc, char **argv)
|
|||||||
arg_str++;
|
arg_str++;
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = tri_get_string_autocomplete(&commands, cmd_buffer, &ambiguous);
|
if (strlen(cmd_buffer) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = tri_get_string_autocomplete(commands, cmd_buffer, &ambiguous);
|
||||||
|
|
||||||
if (ambiguous) {
|
if (ambiguous) {
|
||||||
printf("ambiguous command: '%s'\n", cmd_buffer);
|
printf("ambiguous command: '%s'\n", cmd_buffer);
|
||||||
@@ -571,5 +646,83 @@ int main(int argc, char **argv)
|
|||||||
} while (1);
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int load_initfile(const char *initfile_path, struct tri *commands)
|
||||||
|
{
|
||||||
|
FILE* file;
|
||||||
|
char buffer[INPUT_MAX_LEN];
|
||||||
|
|
||||||
|
file = fopen(initfile_path, "r");
|
||||||
|
|
||||||
|
if (file == NULL) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(fgets(buffer, sizeof(buffer), file)) {
|
||||||
|
process_cmd(buffer, commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct tri commands;
|
||||||
|
char line_buffer[INPUT_MAX_LEN]; /* Buffer for input command */
|
||||||
|
char old_buffer[INPUT_MAX_LEN]; /* Buffer for previous input */
|
||||||
|
|
||||||
|
line_buffer[0] = '\0';
|
||||||
|
old_buffer[0] = '\0';
|
||||||
|
|
||||||
|
tri_init(&commands);
|
||||||
|
tri_add_string(&commands, "step", step);
|
||||||
|
tri_add_string(&commands, "run", run);
|
||||||
|
tri_add_string(&commands, "regs", regs);
|
||||||
|
tri_add_string(&commands, "stats", stats);
|
||||||
|
tri_add_string(&commands, "exit", quit);
|
||||||
|
tri_add_string(&commands, "quit", quit);
|
||||||
|
tri_add_string(&commands, "load", load);
|
||||||
|
tri_add_string(&commands, "bootrom", load_bootrom);
|
||||||
|
tri_add_string(&commands, "mem", mem);
|
||||||
|
tri_add_string(&commands, "dump", mem_dump);
|
||||||
|
tri_add_string(&commands, "peek", peek);
|
||||||
|
tri_add_string(&commands, "help", help);
|
||||||
|
tri_add_string(&commands, "?", help);
|
||||||
|
tri_add_string(&commands, "breakpoint", breakpoint);
|
||||||
|
tri_add_string(&commands, "reset", init);
|
||||||
|
tri_add_string(&commands, "assert", assert);
|
||||||
|
tri_add_string(&commands, "set", set);
|
||||||
|
tri_add_string(&commands, "echo", echo);
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
if (load_initfile(argv[1], &commands)) {
|
||||||
|
printf("Failed to load initfile\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
/* String to use for input (line_buffer or
|
||||||
|
* old_buffer) */
|
||||||
|
char *cmd_str;
|
||||||
|
|
||||||
|
show_prompt();
|
||||||
|
cmd_str = fgets(line_buffer, INPUT_MAX_LEN, stdin);
|
||||||
|
if (cmd_str == NULL) {
|
||||||
|
printf("\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line_buffer[0] != '\n') {
|
||||||
|
cmd_str = line_buffer;
|
||||||
|
strncpy(old_buffer, line_buffer, INPUT_MAX_LEN);
|
||||||
|
} else {
|
||||||
|
cmd_str = old_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
process_cmd(cmd_str, &commands);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user