aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2023-01-30 17:07:20 +0100
committerMarvin Borner2023-01-30 17:07:20 +0100
commit9f770358c43ccf3730e85c3a6bbb00d0b492ecbb (patch)
treecb7b8aba63c25441891324b0abb2e4e9c0363a41
parentde450bfb4354f716fb43fae69d90ed513068d10b (diff)
Basic GUI
-rw-r--r--inc/cpu.h14
-rw-r--r--inc/err.h6
-rw-r--r--inc/gui.h19
-rw-r--r--inc/mem.h2
-rw-r--r--makefile21
-rw-r--r--src/cpu.c86
-rw-r--r--src/gui.c112
-rw-r--r--src/log.c6
-rw-r--r--src/main.c25
-rw-r--r--src/mem.c2
10 files changed, 256 insertions, 37 deletions
diff --git a/inc/cpu.h b/inc/cpu.h
index 1a9a989..ca85a2f 100644
--- a/inc/cpu.h
+++ b/inc/cpu.h
@@ -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
diff --git a/inc/mem.h b/inc/mem.h
index e2d7a18..2485aee 100644
--- a/inc/mem.h
+++ b/inc/mem.h
@@ -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
diff --git a/makefile b/makefile
index a416726..1dd0644 100644
--- a/makefile
+++ b/makefile
@@ -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
diff --git a/src/cpu.c b/src/cpu.c
index 9c7c2a2..21b9f19 100644
--- a/src/cpu.c
+++ b/src/cpu.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);
+}
diff --git a/src/log.c b/src/log.c
index a5ad2a0..8ca70a3 100644
--- a/src/log.c
+++ b/src/log.c
@@ -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);
diff --git a/src/main.c b/src/main.c
index b8bbe93..244b715 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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;
}
diff --git a/src/mem.c b/src/mem.c
index 1581bdc..f7ac9d0 100644
--- a/src/mem.c
+++ b/src/mem.c
@@ -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) {