diff options
author | Marvin Borner | 2023-01-30 17:07:20 +0100 |
---|---|---|
committer | Marvin Borner | 2023-01-30 17:07:20 +0100 |
commit | 9f770358c43ccf3730e85c3a6bbb00d0b492ecbb (patch) | |
tree | cb7b8aba63c25441891324b0abb2e4e9c0363a41 | |
parent | de450bfb4354f716fb43fae69d90ed513068d10b (diff) |
Basic GUI
-rw-r--r-- | inc/cpu.h | 14 | ||||
-rw-r--r-- | inc/err.h | 6 | ||||
-rw-r--r-- | inc/gui.h | 19 | ||||
-rw-r--r-- | inc/mem.h | 2 | ||||
-rw-r--r-- | makefile | 21 | ||||
-rw-r--r-- | src/cpu.c | 86 | ||||
-rw-r--r-- | src/gui.c | 112 | ||||
-rw-r--r-- | src/log.c | 6 | ||||
-rw-r--r-- | src/main.c | 25 | ||||
-rw-r--r-- | src/mem.c | 2 |
10 files changed, 256 insertions, 37 deletions
@@ -3,8 +3,13 @@ #include <stdint.h> -#define ERR 0 -#define OK 1 +#include <err.h> + +struct cpu_interface { + void (*reg_names)(const char *names, int n); + void (*reg_update)(int reg, uint64_t val); + void (*instr_done)(char *instr); +}; enum registers { RAX, @@ -50,8 +55,13 @@ enum registers { DIH = DIL + 4 }; +err cpu_next(void); +err cpu_prev(void); + void *cpu_get_reg(uint8_t reg); void cpu_set_reg(uint8_t reg, uint64_t val); +void cpu_register_interface(struct cpu_interface *cpu); void cpu_exec(const char *path); +void cpu_destroy(void); #endif diff --git a/inc/err.h b/inc/err.h new file mode 100644 index 0000000..c1ae3d9 --- /dev/null +++ b/inc/err.h @@ -0,0 +1,6 @@ +#ifndef ERR_H +#define ERR_H + +typedef enum { ERR, OK, END } err; + +#endif diff --git a/inc/gui.h b/inc/gui.h new file mode 100644 index 0000000..e8a583d --- /dev/null +++ b/inc/gui.h @@ -0,0 +1,19 @@ +#ifndef GUI_H +#define GUI_H + +#include <err.h> +#include <stdint.h> + +struct gui_interface { + err (*step_next)(void); + err (*step_prev)(void); +}; + +void gui_reg_names(const char *names, int n); +void gui_reg_update(int reg, uint64_t value); +void gui_instr_done(char *instr); + +void gui_register_interface(struct gui_interface *gui); +void gui_init(void); + +#endif @@ -8,6 +8,6 @@ typedef uint64_t vaddr; void *mem_alloc(size_t size, vaddr virt); void *mem_phys(vaddr virt); -void mem_free_all(void); +void mem_destroy(void); #endif @@ -14,23 +14,26 @@ ASMTESTSOBJS = $(patsubst $(TESTSDIR)/asm/%.asm, $(BUILDDIR)/test_asm_%.o, $(ASM CC = gcc AS = nasm LD = ld -WARNINGS = -Wall -Wextra -Wshadow -Wpointer-arith -Wwrite-strings -Wredundant-decls -Wnested-externs -Wformat=2 -Wmissing-declarations -Wstrict-prototypes -Wmissing-prototypes -Wcast-qual -Wswitch-default -Wswitch-enum -Wlogical-op -Wunreachable-code -Wundef -Wold-style-definition -Wvla -pedantic -Wno-pointer-arith -DEBUG = -fsanitize=undefined -fsanitize=address -fsanitize=leak -fstack-protector-strong -s -CFLAGS = -Ofast $(WARNINGS) -I$(INCDIR) $(DEBUG) +WARNINGS = -Wall -Wextra -Wshadow -Wpointer-arith -Wwrite-strings -Wredundant-decls -Wnested-externs -Wformat=2 -Wmissing-declarations -Wstrict-prototypes -Wmissing-prototypes -Wcast-qual -Wswitch-default -Wswitch-enum -Wunreachable-code -Wundef -Wold-style-definition -Wvla -pedantic -Wno-pointer-arith +DEBUG = -fsanitize=undefined,address,leak -fstack-protector-strong -s -Og +CFLAGS = -Ofast $(shell pkg-config --cflags --libs gtk4) $(WARNINGS) -I$(INCDIR) #$(DEBUG) ASFLAGS = -O2 -f elf64 # TODO: Use -O0 -all: out tests +all: $(BUILDDIR)/out tests -out: $(OBJS) - @$(CC) -o $(BUILDDIR)/out $(CFLAGS) $^ +$(BUILDDIR)/%.o: $(SOURCEDIR)/%.c + @$(CC) -c $< $(CFLAGS) -o $@ + +$(BUILDDIR)/out: $(OBJS) + @$(CC) $^ $(CFLAGS) -o $@ tests: $(CTESTSOBJS) $(ASMTESTSOBJS) -$(BUILDDIR)/test_asm_%.o: $(TESTSDIR)/asm/%.asm +$(ASMTESTSOBJS): $(ASMTESTS) @$(AS) $(ASFLAGS) $< -o $@ @$(LD) $@ -o $(basename $@) -$(BUILDDIR)/test_c_%.o: $(TESTSDIR)/c/%.c +$(CTESTSOBJS): $(CTESTS) @$(CC) $< -o $(basename $@) clean: @@ -40,7 +43,7 @@ run: all sync @$(BUILDDIR)/out $(BUILDDIR)/test_asm_yay sync: - @make --always-make --dry-run | grep -wE 'gcc|g\+\+' | grep -w '\-c' | jq -nR '[inputs|{directory:".", command:., file: match(" [^ ]+$$").string[1:]}]' >compile_commands.json + @$(MAKE) $(BUILDDIR)/out --always-make --dry-run | grep -wE 'gcc|g\+\+' | grep -w '\-c' | jq -nR '[inputs|{directory:".", command:., file: match(" [^ ]+$$").string[1:]}]' >compile_commands.json @ctags -R --exclude=.git --exclude=build . $(BUILDDIR)/%.o: $(SOURCEDIR)/%.c @@ -1,3 +1,5 @@ +#include <stdlib.h> + #include <cpu.h> #include <load.h> #include <log.h> @@ -89,10 +91,18 @@ #define GET_RM8() (MOD() == 3 ? GET_R8(RM()) : *(uint8_t *)mem_phys(ADDR())) #define GET_RM32() (MOD() == 3 ? GET_R32(RM()) : *(uint32_t *)mem_phys(ADDR())) +static struct cpu_interface *interface; + +struct rip_history { + uint64_t rip; + struct rip_history *prev; +}; + static uint64_t rip = 0; -static int (*pos_instructions[256])(void); -static int (*neg_instructions[256])(void); +static err (*pos_instructions[256])(void); +static err (*neg_instructions[256])(void); static uint64_t regs[REGISTERS_COUNT] = { 0 }; +static struct rip_history *rip_history; static void print_state(void) { @@ -102,19 +112,19 @@ static void print_state(void) regs[R10], regs[R11], regs[R12], regs[R13], regs[R14], regs[R15]); } -static int pos_unknown_instruction(void) +static err pos_unknown_instruction(void) { errln("unknown positive instruction at rip=%d", rip); return ERR; } -static int neg_unknown_instruction(void) +static err neg_unknown_instruction(void) { errln("unknown negative instruction at rip=%d", rip); return ERR; } -static int pos_opcode(void) +static err pos_opcode(void) { uint8_t op = U8(); // TODO: is_*, j* @@ -124,14 +134,14 @@ static int pos_opcode(void) return ERR; } -static int pos_mov_r32_rm32(void) +static err pos_mov_r32_rm32(void) { uint8_t modrm = U8(); SET_R32(REG(), GET_RM32()); return OK; } -static int pos_mov_r32_imm32(void) +static err pos_mov_r32_imm32(void) { rip--; uint8_t reg = U8() - 0xb8; @@ -139,12 +149,12 @@ static int pos_mov_r32_imm32(void) return OK; } -static int pos_nop(void) +static err pos_nop(void) { return OK; } -static int pos_int(void) +static err pos_int(void) { uint8_t op = U8(); if (op == 0x80) { @@ -182,6 +192,11 @@ void cpu_set_reg(uint8_t reg, uint64_t val) regs[reg] = val; } +void cpu_register_interface(struct cpu_interface *cpu) +{ + interface = cpu; +} + void cpu_exec(const char *path) { initialize(); @@ -193,14 +208,49 @@ void cpu_exec(const char *path) } rip = addr; - int ret = OK; - while (ret) { - uint8_t instr = U8(); - if (!instr) - return; - logln("%x", instr); - ret = pos_instructions[instr](); - print_state(); + rip_history = malloc(sizeof(*rip_history)); + rip_history->rip = rip; + rip_history->prev = 0; +} + +err cpu_next(void) +{ + uint8_t instr = U8(); + if (!instr) + return END; + logln("%x", instr); + err ret = pos_instructions[instr](); + print_state(); + + struct rip_history *next = malloc(sizeof(*next)); + next->rip = rip; + next->prev = rip_history; + rip_history = next; + return ret; +} + +err cpu_prev(void) +{ + struct rip_history *prev = rip_history->prev; + if (!prev) + return END; + rip = prev->rip; + uint8_t instr = U8(); + if (!instr) + return ERR; + err ret = neg_instructions[instr](); + print_state(); + + free(rip_history); + rip_history = prev; + return ret; +} + +void cpu_destroy(void) +{ + while (rip_history) { + struct rip_history *temp = rip_history->prev; + free(rip_history); + rip_history = temp; } - errln("error while executing"); } diff --git a/src/gui.c b/src/gui.c new file mode 100644 index 0000000..297ff6f --- /dev/null +++ b/src/gui.c @@ -0,0 +1,112 @@ +#include <gtk/gtk.h> + +#include <gui.h> +#include <log.h> + +enum stepper_response_type { + STEP_PREV, + STEP_NEXT, +}; + +static struct gui_interface *interface; + +static void error_dialog(GtkWindow *parent, const char *msg) +{ + GtkWidget *dialog = gtk_dialog_new_with_buttons( + msg, parent, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + "OK", GTK_RESPONSE_CLOSE, NULL); + GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + GtkWidget *label = gtk_label_new(msg); + g_signal_connect_swapped(dialog, "response", + G_CALLBACK(gtk_window_destroy), dialog); + + gtk_box_append(GTK_BOX(content), label); + gtk_widget_show(dialog); +} + +static void stepper_response(GtkWidget *widget, enum stepper_response_type type) +{ + err ret = OK; + + switch (type) { + case STEP_PREV: + ret = interface->step_prev(); + break; + case STEP_NEXT: + ret = interface->step_next(); + break; + default: + break; + } + + if (ret == END || ret == ERR) { + error_dialog(GTK_WINDOW(widget), + ret == END ? "Reached end" : "An error occured"); + } +} + +static void init_stepper_dialog(GtkWindow *parent) +{ + GtkWidget *stepper = gtk_dialog_new_with_buttons( + "Stepper", parent, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, "Previous", + 1, "Next", 2, NULL); + + GtkWidget *content = gtk_dialog_get_content_area(GTK_DIALOG(stepper)); + GtkWidget *label = gtk_label_new("Stepper"); + + g_signal_connect_swapped(stepper, "response", + G_CALLBACK(stepper_response), stepper); + + gtk_box_append(GTK_BOX(content), label); + gtk_widget_show(stepper); +} + +static void init_execution_window(GtkApplication *app) +{ + GtkWidget *execution = gtk_application_window_new(app); + gtk_window_set_title(GTK_WINDOW(execution), "Execution"); + gtk_window_set_default_size(GTK_WINDOW(execution), 200, 200); + gtk_widget_show(execution); + + init_stepper_dialog(GTK_WINDOW(execution)); +} + +static void activate(GtkApplication *app, gpointer user_data) +{ + (void)user_data; + init_execution_window(app); +} + +void gui_reg_names(const char *names, int n) +{ + (void)names; + (void)n; +} + +void gui_reg_update(int reg, uint64_t value) +{ + (void)reg; + (void)value; +} + +void gui_instr_done(char *instr) +{ + (void)instr; +} + +void gui_register_interface(struct gui_interface *gui) +{ + interface = gui; +} + +void gui_init(void) +{ + g_object_set(gtk_settings_get_default(), + "gtk-application-prefer-dark-theme", TRUE, NULL); + GtkApplication *app = gtk_application_new("de.melvars.simsalasim", + G_APPLICATION_DEFAULT_FLAGS); + g_signal_connect(app, "activate", G_CALLBACK(activate), NULL); + g_application_run(G_APPLICATION(app), 0, 0); + g_object_unref(app); +} @@ -9,7 +9,8 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -void __logln(const char *func, const char *format, ...) +__attribute__((__format__(__printf__, 2, 0))) void +__logln(const char *func, const char *format, ...) { pthread_mutex_lock(&mutex); @@ -25,7 +26,8 @@ void __logln(const char *func, const char *format, ...) pthread_mutex_unlock(&mutex); } -void __errln(const char *func, const char *format, ...) +__attribute__((__format__(__printf__, 2, 0))) void +__errln(const char *func, const char *format, ...) { pthread_mutex_lock(&mutex); @@ -1,19 +1,36 @@ #include <cpu.h> #include <mem.h> #include <log.h> +#include <gui.h> + +static struct cpu_interface cpu = { + .reg_names = gui_reg_names, + .reg_update = gui_reg_update, + .instr_done = gui_instr_done, +}; + +static struct gui_interface gui = { + .step_next = cpu_next, + .step_prev = cpu_prev, +}; int main(int argc, char *argv[]) { - (void)argc; - (void)argv; - if (argc != 2) { logln("invalid arguments"); return 1; } + cpu_register_interface(&cpu); cpu_exec(argv[1]); - mem_free_all(); + /* while (cpu_next() == OK) */ + /* ; */ + + gui_register_interface(&gui); + gui_init(); + + cpu_destroy(); + mem_destroy(); return 0; } @@ -46,7 +46,7 @@ void *mem_phys(vaddr virt) return &zero; } -void mem_free_all(void) +void mem_destroy(void) { struct memory *iterator = head; while (iterator) { |