summaryrefslogtreecommitdiff
path: root/arch/null
diff options
context:
space:
mode:
authorPaul Oliver <contact@pauloliver.dev>2026-07-14 17:29:02 +0200
committerPaul Oliver <contact@pauloliver.dev>2026-08-30 16:24:48 +0200
commit1961b4b237083f4cfac9ca6b249c1d6cb665d149 (patch)
treefd9fc8260360e2ac30be9747ca558bcfc824a4c4 /arch/null
Initial (refactor)HEADmaster
Diffstat (limited to 'arch/null')
-rw-r--r--arch/null/arch.c241
-rw-r--r--arch/null/arch_inst.c48
-rw-r--r--arch/null/arch_spec.h19
-rw-r--r--arch/null/client_plots.h32
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 = {};