// file : arch/null/arch.c // project : Salis-VM // author : Paul Oliver // // Example of a minimal viable VM architecture. Useful for testing. // Also works as a placeholder when creating new VM architectures. // index: // [section] includes // [section] getters // [section] callbacks // [section] validation // [section] data // [section] main // ---------------------------------------------------------------------------- // [section] includes // ---------------------------------------------------------------------------- #include #include #include #include #include #include #include #include #include "arch.h" #include "arch_spec.h" #include "arch_inst.h" #include "compress.h" #include "logger.h" #include "salis.h" #include "sql.h" // ---------------------------------------------------------------------------- // [section] getters // ---------------------------------------------------------------------------- uint64_t arch_proc_get_ip_addr(const struct Core *core, uint64_t pix) { assert(core); assert(mvec_proc_is_live(core, pix)); return proc_get(core, pix)->ip; } uint64_t arch_proc_get_sp_addr(const struct Core *core, uint64_t pix) { assert(core); assert(mvec_proc_is_live(core, pix)); return proc_get(core, pix)->sp; } uint64_t arch_proc_get_mb0_addr(const struct Core *core, uint64_t pix) { assert(core); assert(mvec_proc_is_live(core, pix)); return proc_get(core, pix)->mb0a; } uint64_t arch_proc_get_mb0_size(const struct Core *core, uint64_t pix) { assert(core); assert(mvec_proc_is_live(core, pix)); return proc_get(core, pix)->mb0s; } uint64_t arch_proc_get_mb1_addr(const struct Core *core, uint64_t pix) { assert(core); assert(mvec_proc_is_live(core, pix)); return proc_get(core, pix)->mb1a; } uint64_t arch_proc_get_mb1_size(const struct Core *core, uint64_t pix) { assert(core); assert(mvec_proc_is_live(core, pix)); return proc_get(core, pix)->mb1s; } uint64_t arch_proc_get_slice(const struct Core *core, uint64_t pix) { assert(core); assert(mvec_proc_is_live(core, pix)); (void)core; (void)pix; return 1; } // ---------------------------------------------------------------------------- // [section] callbacks // ---------------------------------------------------------------------------- void arch_on_proc_step(struct Core *core, uint64_t pix) { assert(core); assert(mvec_proc_is_live(core, pix)); (void)core; (void)pix; return; } void arch_on_proc_kill(struct Core *core) { assert(core); assert(core->pnum > 1); (void)core; } // ---------------------------------------------------------------------------- // [section] validation // ---------------------------------------------------------------------------- #if !defined(NDEBUG) void arch_validate_core(struct Core *core) { assert(core); (void)core; } #endif // ---------------------------------------------------------------------------- // [section] data // ---------------------------------------------------------------------------- void arch_push_data_header(void) { log_info("Creating arch table in SQLite database"); sql_exec( NULL, NULL, "create table arch (" #define FOR_CORE(i) \ "null_0_pop_" #i " int not null, " \ "null_1_pop_" #i " int not null, " \ "null_2_pop_" #i " int not null, " \ "null_3_pop_" #i " int not null, " FOR_CORES #undef FOR_CORE "step int not null" ");" ); } static int arch_count_inst_pop(struct Core *core) { assert(core); for (uint64_t i = 0; i < MVEC_SIZE; i++) { core->ipop[mvec_get_inst(core, i)]++; } #if !defined(NDEBUG) uint64_t pop_total = 0; for (uint64_t i = 0; i < ARCH_INST_COUNT; i++) { pop_total += core->ipop[i]; } assert(pop_total == MVEC_SIZE); #endif return 0; } void arch_prepare_data_line(void) { assert(g_sim_db); // Measure instruction population in parallel for (int i = 0; i < CORES; i++) { struct Core *core = &g_cores[i]; thrd_create(&core->ipop_thrd, (thrd_start_t)arch_count_inst_pop, core); } for (int i = 0; i < CORES; i++) { struct Core *core = &g_cores[i]; thrd_join(core->ipop_thrd, NULL); } } void arch_push_data_line(FILE *eva_file) { assert(eva_file); (void)eva_file; log_info("Pushing row to arch table in SQLite database"); sql_exec( NULL, NULL, "insert into arch (" #define FOR_CORE(i) \ "null_0_pop_" #i ", " \ "null_1_pop_" #i ", " \ "null_2_pop_" #i ", " \ "null_3_pop_" #i ", " FOR_CORES #undef FOR_CORE "step" ") values (" #define FOR_CORE(i) \ "%ld, %ld, %ld, %ld, " FOR_CORES #undef FOR_CORE "%ld" ");", #define FOR_CORE(i) \ g_cores[i].ipop[0], \ g_cores[i].ipop[1], \ g_cores[i].ipop[2], \ g_cores[i].ipop[3], FOR_CORES #undef FOR_CORE g_step ); // Reset data aggregation fields for (int i = 0; i < CORES; i++) { struct Core *core = &g_cores[i]; memset(core->ipop, 0, sizeof(uint64_t) * ARCH_INST_COUNT); } } // ---------------------------------------------------------------------------- // [section] main // ---------------------------------------------------------------------------- #if defined(COMMAND_NEW) void arch_core_init(struct Core *core) { assert(core); for (uint64_t i = 0; i < CLONES; i++) { uint64_t addr_clone = (MVEC_SIZE / CLONES) * i; struct Proc *panc = proc_fetch(core, i); panc->mb0a = addr_clone; panc->mb0s = ANC_SIZE; panc->ip = addr_clone; panc->sp = addr_clone; } } #endif #if defined(COMMAND_LOAD) void arch_core_load(struct Core *core, FILE *f) { assert(core); assert(f); (void)core; (void)f; } #endif void arch_core_save(const struct Core *core, FILE *f) { assert(core); assert(f); (void)core; (void)f; } void arch_core_free(struct Core *core) { assert(core); (void)core; }