diff options
| author | Paul Oliver <contact@pauloliver.dev> | 2026-07-14 17:29:02 +0200 |
|---|---|---|
| committer | Paul Oliver <contact@pauloliver.dev> | 2026-08-30 16:24:48 +0200 |
| commit | 1961b4b237083f4cfac9ca6b249c1d6cb665d149 (patch) | |
| tree | fd9fc8260360e2ac30be9747ca558bcfc824a4c4 /arch/null | |
Diffstat (limited to 'arch/null')
| -rw-r--r-- | arch/null/arch.c | 241 | ||||
| -rw-r--r-- | arch/null/arch_inst.c | 48 | ||||
| -rw-r--r-- | arch/null/arch_spec.h | 19 | ||||
| -rw-r--r-- | arch/null/client_plots.h | 32 |
4 files changed, 340 insertions, 0 deletions
diff --git a/arch/null/arch.c b/arch/null/arch.c new file mode 100644 index 0000000..f9e7ef4 --- /dev/null +++ b/arch/null/arch.c @@ -0,0 +1,241 @@ +// file : arch/null/arch.c +// project : Salis-VM +// author : Paul Oliver <contact@pauloliver.dev> +// +// 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 <assert.h> +#include <sqlite3.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <threads.h> +#include <zlib.h> + +#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; +} diff --git a/arch/null/arch_inst.c b/arch/null/arch_inst.c new file mode 100644 index 0000000..4744382 --- /dev/null +++ b/arch/null/arch_inst.c @@ -0,0 +1,48 @@ +// file : arch/null/arch_inst.c +// project : Salis-VM +// author : Paul Oliver <contact@pauloliver.dev> + +#include <assert.h> +#include <stdbool.h> +#include <stdint.h> +#include <wchar.h> + +#define ARCH_EXPORT_INST_COUNT +#include "arch_spec.h" +#include "arch_inst.h" + +wchar_t arch_inst_symbol(uint8_t inst) { + assert(inst < ARCH_INST_COUNT); + + switch (inst) { + case 0: + return L'⢀'; + case 1: + return L'⢁'; + case 2: + return L'⢂'; + case 3: + return L'⢃'; + } + + assert(false); + return L'\0'; +} + +const char *arch_inst_mnemonic(uint8_t inst) { + assert(inst < ARCH_INST_COUNT); + + switch (inst) { + case 0: + return "null 0"; + case 1: + return "null 1"; + case 2: + return "null 2"; + case 3: + return "null 3"; + } + + assert(false); + return NULL; +} diff --git a/arch/null/arch_spec.h b/arch/null/arch_spec.h new file mode 100644 index 0000000..466e69f --- /dev/null +++ b/arch/null/arch_spec.h @@ -0,0 +1,19 @@ +// file : arch/null/arch_spec.h +// project : Salis-VM +// author : Paul Oliver <contact@pauloliver.dev> + +#pragma once + +#define ARCH_SPEC_INST_BITS 2 + +#define ARCH_SPEC_CORE_FIELDS \ + ARCH_SPEC_CORE_FIELD(thrd_t, ipop_thrd) \ + ARCH_SPEC_CORE_FIELD(uint64_t, ipop[ARCH_INST_COUNT]) \ + +#define ARCH_SPEC_PROC_FIELDS \ + ARCH_SPEC_PROC_FIELD(uint64_t, ip) \ + ARCH_SPEC_PROC_FIELD(uint64_t, sp) \ + ARCH_SPEC_PROC_FIELD(uint64_t, mb0a) \ + ARCH_SPEC_PROC_FIELD(uint64_t, mb0s) \ + ARCH_SPEC_PROC_FIELD(uint64_t, mb1a) \ + ARCH_SPEC_PROC_FIELD(uint64_t, mb1s) diff --git a/arch/null/client_plots.h b/arch/null/client_plots.h new file mode 100644 index 0000000..72cd052 --- /dev/null +++ b/arch/null/client_plots.h @@ -0,0 +1,32 @@ +// file : arch/null/client_plots.h +// project : Salis-VM +// author : Paul Oliver <contact@pauloliver.dev> + +#pragma once + +static std::array g_arch_traces = std::to_array<TraceNamed<ImS64>>({ +#define FOR_CORE(i) \ + {"null_0_pop_" #i, "null_0_pop_" #i}, \ + {"null_1_pop_" #i, "null_1_pop_" #i}, \ + {"null_2_pop_" #i, "null_2_pop_" #i}, \ + {"null_3_pop_" #i, "null_3_pop_" #i}, + FOR_CORES +#undef FOR_CORE +}); + +static std::array<TraceHeatmap<ImS64>, 0> g_arch_traces_heatmaps = {}; +static std::array<PlotLines, 0> g_arch_plots = {}; + +static std::array g_arch_plots_stacked = std::to_array<PlotStacked>({ +#define FOR_CORE(i) \ + {"ipop%_" #i, "population", { \ + "null_0_pop_" #i, \ + "null_1_pop_" #i, \ + "null_2_pop_" #i, \ + "null_3_pop_" #i, \ + }}, + FOR_CORES +#undef FOR_CORE +}); + +static std::array<PlotHeatmap, 0> g_arch_plots_heatmaps = {}; |
