diff --git a/Makefile b/Makefile index c1bcd5b..e24ee69 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ CCFLAGS += -std=c11 -D_POSIX_C_SOURCE=200809L CCFLAGS += -I$(SRC_DIR) CCFLAGS += -I/usr/include/glib-2.0/ -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -LDFLAGS += -lglib-2.0 +LDFLAGS += -lglib-2.0 -lreadline CCFLAGS += $(CCFLAGS_EXTRA) LDFLAGS += $(LDFLAGS_EXTRA) diff --git a/src/apps/gbdb.c b/src/apps/gbdb.c index a68f228..090bf4b 100644 --- a/src/apps/gbdb.c +++ b/src/apps/gbdb.c @@ -15,6 +15,9 @@ #include #include +#include +#include + #include "common/common.h" #include "gb_disas.h" #include "gbemu/cpu.h" @@ -24,14 +27,14 @@ #define INPUT_MAX_LEN 512 #define MAX_BREAKPTS 16 /* Should be plenty for anyone */ -typedef void (gbdb_cmd)(struct tokens **tokens); +typedef int (gbdb_cmd)(struct tokens **tokens); static void breakpoint_addr_hit(uint16_t id); static void breakpoint_cb(struct lr35902_state *lr); static void reset_breakpoints(void); static int64_t parse_val(const char *str); -static const char prompt[] = "gbdb >"; +static const char prompt[] = "gbdb > "; static const char usage[] = "Available commands:\n" "load : loads the given file as the gameboy cartridge\n" @@ -146,13 +149,7 @@ static void cycle() gb_video_cycle(&video, cycles); } -static void show_prompt() -{ - printf("%s ", prompt); - fflush(stdout); -} - -static void call_next_cmd(struct tokens** tokens, +static int call_next_cmd(struct tokens** tokens, struct tri *commands, const char *cmdname) { @@ -162,23 +159,23 @@ static void call_next_cmd(struct tokens** tokens, char *token = token_next(tokens); if (!token) { - return; + return -1; } cmd = tri_get_string_autocomplete(commands, token, &ambiguous); if (ambiguous) { gb_error("ambiguous %s command: '%s'\n", cmdname, token); - return; + return -1; } if (cmd == NULL) { gb_error("unrecognized %s command: '%s'\n", cmdname, token); - return; + return -1; } - cmd(tokens); + return cmd(tokens); } -static void set_logfile(struct tokens **tokens) +static int set_logfile(struct tokens **tokens) { char *token = token_next(tokens); int fd; @@ -189,7 +186,7 @@ static void set_logfile(struct tokens **tokens) close(config.log_fd); } config.log_fd = -1; - return; + return -1; } fd = open(token, @@ -197,7 +194,7 @@ static void set_logfile(struct tokens **tokens) S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) { gb_error("Failed to open logfile %s, %s\n", token, strerror(errno)); - return; + return -1; } if (config.log_fd != -1) { @@ -205,9 +202,11 @@ static void set_logfile(struct tokens **tokens) } config.log_fd = fd; + + return 0; } -static void set_tracefile(struct tokens **tokens) +static int set_tracefile(struct tokens **tokens) { char *token = token_next(tokens); int fd; @@ -218,7 +217,7 @@ static void set_tracefile(struct tokens **tokens) close(config.trace_fd); } config.trace_fd = -1; - return; + return -1; } fd = open(token, @@ -226,7 +225,7 @@ static void set_tracefile(struct tokens **tokens) S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) { gb_error("Failed to open tracefile %s, %s\n", token, strerror(errno)); - return; + return -1; } if (config.trace_fd != -1) { @@ -235,19 +234,22 @@ static void set_tracefile(struct tokens **tokens) config.trace_fd = fd; gb_log("Trace fd=%d\n", config.trace_fd); + return 0; } -static void set_quiet_on(struct tokens **tokens) +static int set_quiet_on(struct tokens **tokens) { config.quiet = true; + return 0; } -static void set_quiet_off(struct tokens **tokens) +static int set_quiet_off(struct tokens **tokens) { config.quiet = false; + return 0; } -static void set_quiet(struct tokens **tokens) +static int set_quiet(struct tokens **tokens) { static bool init = false; static struct tri commands; @@ -261,15 +263,16 @@ static void set_quiet(struct tokens **tokens) init = true; } - call_next_cmd(tokens, &commands, "set quiet"); + return call_next_cmd(tokens, &commands, "set quiet"); } -static void set_video_debug(struct tokens **tokens) +static int set_video_debug(struct tokens **tokens) { video.debug_logging = true; + return 0; } -static void set(struct tokens **tokens) +static int set(struct tokens **tokens) { static bool init = false; static struct tri commands; @@ -283,10 +286,10 @@ static void set(struct tokens **tokens) init = true; } - call_next_cmd(tokens, &commands, "set"); + return call_next_cmd(tokens, &commands, "set"); } -static void echo(struct tokens **tokens) +static int echo(struct tokens **tokens) { char *token; while ((token = token_next(tokens)) != NULL) { @@ -294,6 +297,7 @@ static void echo(struct tokens **tokens) } gb_log("\n"); + return 0; } static void breakpoint_cb(struct lr35902_state *lr) @@ -307,7 +311,7 @@ static void breakpoint_cb(struct lr35902_state *lr) } -static void step(struct tokens **tokens) +static int step(struct tokens **tokens) { uint64_t steps, end_steps; char *token; @@ -342,9 +346,11 @@ static void step(struct tokens **tokens) paused = 0; paused_signal = 0; paused_breakpoint = 0; + + return 0; } -static void regs(struct tokens **tokens) +static int regs(struct tokens **tokens) { 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); @@ -355,6 +361,8 @@ static void regs(struct tokens **tokens) gb_log("HL: 0x%04x H: 0x%02x L: 0x%02x\n", cpu.hl, cpu.h, cpu.l); gb_log("PC: 0x%04x\n", cpu.pc); gb_log("SP: 0x%04x\n", cpu.sp); + + return 0; } static uint8_t decode_fetch_mem(void *opaque, uint16_t addr) @@ -362,14 +370,13 @@ static uint8_t decode_fetch_mem(void *opaque, uint16_t addr) return gb_mem_read(memory, addr); } -static void disas(struct tokens **tokens) +static int disas(struct tokens **tokens) { uint16_t pc = lr35902_get_reg_16(&cpu, LR35902_REG_PC); uint16_t old_pc = pc; const char *disas_cnt_str; int64_t num_disas, i; - if (tokens) { disas_cnt_str = token_next(tokens); if (disas_cnt_str == NULL) { @@ -388,32 +395,45 @@ static void disas(struct tokens **tokens) gb_log("0x%04x:%s\n", old_pc, opcode); free((void *) opcode); } + + return 0; } -static void vstep(struct tokens **tokens) +static int vstep(struct tokens **tokens) { + int ret; + disas(NULL); - step(tokens); + ret = step(tokens); regs(NULL); + + return ret; } -static void stats(struct tokens **tokens) +static int stats(struct tokens **tokens) { gb_log("Cycles: %" PRId64 "\n", cpu.metrics.cycles); gb_log("Retired Insructions %" PRId64 "\n", cpu.metrics.retired_instrs); gb_log("Memory Reads: %" PRId64 " \n", cpu.metrics.mem_reads); gb_log("Memory Writes: %" PRId64 "\n", cpu.metrics.mem_writes); + + return 0; } -static void comment(struct tokens **tokens) +static int comment(struct tokens **tokens) { /* Gobble up everything */ do {} while (token_next(tokens)); + + // Return an error so it does not get stored in the history + return -1; } -static void help(struct tokens **tokens) +static int help(struct tokens **tokens) { gb_log(usage); + + return 0; } static int64_t parse_reg_str(const char *str) @@ -602,7 +622,7 @@ static __attribute__((hot)) void do_run(void) { paused_signal = 0; } -static void run(struct tokens **tokens ) +static void run(struct tokens **tokens) { do_run(); } @@ -652,41 +672,45 @@ static int do_set_breakpoint(uint16_t addr, bool temp) num_breakpoints++; } else { gb_error("maximum number of breakpoints reached\n"); + return -1; } + + return 0; } -static void set_breakpoint(struct tokens **tokens) +static int set_breakpoint(struct tokens **tokens) { uint16_t addr, i; char *token = token_next(tokens); if (token == NULL) { gb_error("usage: breakpoint add \n"); - return; + return -1; } addr = parse_val(token); - do_set_breakpoint(addr, false); + return do_set_breakpoint(addr, false); } -static void runto(struct tokens **tokens) +static int runto(struct tokens **tokens) { uint16_t addr, i, rc; char *token = token_next(tokens); if (token == NULL) { gb_error("usage: runto \n"); - return; + return -1; } addr = parse_val(token); rc = do_set_breakpoint(addr, true); if (rc < 0) { gb_error("failed to set breakpoint\n"); - return; + return -1; } do_run(); + return 0; } static int do_delete_breakpoint(int id) @@ -729,24 +753,28 @@ static void breakpoint_addr_hit(uint16_t addr) if (bkpt->temp) { do_delete_breakpoint(bkpt->id); } + + return; } -static void delete_breakpoint(struct tokens **tokens) +static int delete_breakpoint(struct tokens **tokens) { char *token = token_next(tokens); - int rc, bkpt; + int ret, bkpt; if (token == NULL) { gb_error("usage: breakpoint rm \n"); - return; + return -1; } bkpt = parse_val(token); - rc = do_delete_breakpoint(bkpt); - if (rc < 0) { + ret = do_delete_breakpoint(bkpt); + if (ret < 0) { gb_error("%d is not a valid breakpoint number\n", bkpt); } + + return ret; } static void display_breakpoints(struct tokens **tokens) @@ -762,7 +790,7 @@ static void display_breakpoints(struct tokens **tokens) } } -static void breakpoint(struct tokens **tokens) +static int breakpoint(struct tokens **tokens) { static bool init = false; static struct tri commands; @@ -780,7 +808,7 @@ static void breakpoint(struct tokens **tokens) init = true; } - call_next_cmd(tokens, &commands, "breakpoint"); + return call_next_cmd(tokens, &commands, "breakpoint"); } static bool breakpoint_is_at_addr(uint16_t addr) { @@ -795,15 +823,16 @@ static bool breakpoint_is_at_addr(uint16_t addr) { return false; } -static void process_cmd(const char *cmd_str, struct tri *commands) +static int process_cmd(const char *cmd_str, struct tri *commands) { struct tokens *statements; struct tokens *tokens; char *statement, *token; + int ret = -1; statements = tokenize(cmd_str, ";\n"); if (!statements) { - return; + return -1; } while ((statement = token_next(&statements)) != NULL) { @@ -812,12 +841,13 @@ static void process_cmd(const char *cmd_str, struct tri *commands) continue; } - call_next_cmd(&tokens, commands, ""); + ret = call_next_cmd(&tokens, commands, ""); /* Ensure there are no leftover tokens to leak */ do {} while (token_next(&tokens)); } + return ret; } static int load_initfile(const char *initfile_path, struct tri *commands) @@ -842,11 +872,6 @@ static int load_initfile(const char *initfile_path, 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 */ - - line_buffer[0] = '\0'; - old_buffer[0] = '\0'; tri_init(&commands); tri_add_string(&commands, "#", comment); @@ -883,23 +908,20 @@ int main(int argc, char **argv) while (1) { /* String to use for input (line_buffer or * old_buffer) */ - char *cmd_str; + char *cmd_str = readline(prompt); + int ret; - 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; + ret = process_cmd(cmd_str, &commands); + if (ret == 0) { + add_history(cmd_str); } - process_cmd(cmd_str, &commands); + free(cmd_str); } if (config.log_fd != -1) {