From c1c42834ed57c3a7ba6b5bd3020f4578cf105014 Mon Sep 17 00:00:00 2001 From: Peter Evans Date: Mon, 5 Feb 2018 20:31:05 -0600 Subject: [PATCH] Add reflect system to virtual machine --- include/vm_reflect.h | 69 +++++++++++++++++++++++++++++++++++++++ sources.cmake | 1 + src/vm_reflect.c | 62 +++++++++++++++++++++++++++++++++++ tests/vm_reflect.c | 78 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 210 insertions(+) create mode 100644 include/vm_reflect.h create mode 100644 src/vm_reflect.c create mode 100644 tests/vm_reflect.c diff --git a/include/vm_reflect.h b/include/vm_reflect.h new file mode 100644 index 0000000..8fa5485 --- /dev/null +++ b/include/vm_reflect.h @@ -0,0 +1,69 @@ +#ifndef _VM_REFLECT_H_ +#define _VM_REFLECT_H_ + +#include + +/* + * Some forward decls for vm_reflect + */ +struct vm_reflect; +typedef struct vm_reflect vm_reflect; + +/* + * A reflect function, mostly helpful in the struct definition itself as + * well as a function decls and defns. A reflect function would accept a + * reflect object and use that to figure out what it's talking about. + */ +typedef void (*vm_reflect_fn)(vm_reflect *); + +struct vm_reflect { + /* + * These are the machine and CPU objects that the reflect system + * would want to work with. + */ + void *machine; + void *cpu; + + /* + * Where information that we print will go to. + */ + FILE *stream; + + /* + * Print out information about the machine and CPU, respectively. + */ + vm_reflect_fn cpu_info; + vm_reflect_fn machine_info; + + /* + * These functions pause or resume operation of the virtual machine. + */ + vm_reflect_fn pause; + vm_reflect_fn resume; + + /* + * Turn on, or off, disassembly of the instructions being executed. + */ + vm_reflect_fn disasm_on; + vm_reflect_fn disasm_off; + + /* + * Eventually we will have the ability to load and save state to a + * file mechanism (probably not the one defined as `stream` above). + */ +#if 0 + vm_reflect_fn save_state; + vm_reflect_fn load_state; +#endif +}; + +extern int vm_reflect_cpu_info(vm_reflect *); +extern int vm_reflect_disasm_off(vm_reflect *); +extern int vm_reflect_disasm_on(vm_reflect *); +extern int vm_reflect_machine_info(vm_reflect *); +extern int vm_reflect_pause(vm_reflect *); +extern int vm_reflect_resume(vm_reflect *); +extern vm_reflect *vm_reflect_create(void *, void *, FILE *); +extern void vm_reflect_free(vm_reflect *); + +#endif diff --git a/sources.cmake b/sources.cmake index 2fdb3e0..9762e95 100644 --- a/sources.cmake +++ b/sources.cmake @@ -25,6 +25,7 @@ set(erc_sources vm_area.c vm_bitfont.c vm_event.c + vm_reflect.c vm_screen.c vm_segment.c ) diff --git a/src/vm_reflect.c b/src/vm_reflect.c new file mode 100644 index 0000000..399f7a9 --- /dev/null +++ b/src/vm_reflect.c @@ -0,0 +1,62 @@ +/* + * vm_reflect.c + */ + +#include + +#include "log.h" +#include "vm_reflect.h" + +/* + * Create a new vm_reflect struct with the given machine, cpu and + * stream. + */ +vm_reflect * +vm_reflect_create(void *mach, void *cpu, FILE *stream) +{ + vm_reflect *ref; + + ref = malloc(sizeof(vm_reflect)); + if (ref == NULL) { + log_critical("Could not allocate memory for vm_reflect"); + return NULL; + } + + ref->machine = mach; + ref->cpu = cpu; + ref->stream = stream; + + ref->cpu_info = NULL; + ref->machine_info = NULL; + ref->pause = NULL; + ref->resume = NULL; + ref->disasm_on = NULL; + ref->disasm_off = NULL; + + return ref; +} + +/* + * Free a vm_reflect struct that we created earlier + */ +void +vm_reflect_free(vm_reflect *ref) +{ + // Not much to this--just going to free the main memory chunk + free(ref); +} + +/* + * All of the reflect functions do essentially the same thing--at least, + * right now they do. + */ +#define REFLECT(x) \ + int vm_reflect_##x(vm_reflect *ref) { \ + if (ref->x == NULL) return ERR_INVALID; ref->x(ref); return OK; } + +REFLECT(cpu_info); +REFLECT(machine_info); +REFLECT(pause); +REFLECT(resume); +REFLECT(disasm_on); +REFLECT(disasm_off); diff --git a/tests/vm_reflect.c b/tests/vm_reflect.c new file mode 100644 index 0000000..b9e6bed --- /dev/null +++ b/tests/vm_reflect.c @@ -0,0 +1,78 @@ +#include + +#include "apple2.h" +#include "vm_reflect.h" + +static vm_reflect *ref; +static apple2 *mach; + +/* + * This is a tiny function we can use that will satisfy the + * vm_reflect_fn type so we can test that all of those are working in + * the vm_reflect struct. + */ +static void +fun(vm_reflect *ref) +{ + return; +} + +static void +have_fun() +{ + ref->cpu_info = fun; + ref->machine_info = fun; + ref->pause = fun; + ref->resume = fun; + ref->disasm_on = fun; + ref->disasm_off = fun; +} + +static void +setup() +{ + mach = apple2_create(100, 100); + ref = vm_reflect_create(mach, mach->cpu, stdout); +} + +static void +teardown() +{ + vm_reflect_free(ref); + apple2_free(mach); +} + +TestSuite(vm_reflect, .init = setup, .fini = teardown); + +Test(vm_reflect, create) +{ + cr_assert_neq(ref, NULL); + cr_assert_eq(ref->cpu_info, NULL); + cr_assert_eq(ref->machine_info, NULL); + cr_assert_eq(ref->pause, NULL); + cr_assert_eq(ref->resume, NULL); + cr_assert_eq(ref->disasm_on, NULL); + cr_assert_eq(ref->disasm_off, NULL); +} + +// Not much to do here +/* Test(vm_reflect, free) */ + +/* + * Because all of the reflect functions (aside from create/free) do the + * same thing, one test can stand in for all of them; hence the skips + * you see below. + */ +Test(vm_reflect, cpu_info) +{ + // We should always try to have fun + have_fun(); + + cr_assert_eq(vm_reflect_cpu_info(ref), OK); +} + +/* Test(vm_reflect, machine_info) */ +/* Test(vm_reflect, pause) */ +/* Test(vm_reflect, resume) */ +/* Test(vm_reflect, disasm_on) */ +/* Test(vm_reflect, disasm_off) */