aboutsummaryrefslogtreecommitdiff
path: root/core.j2.c
diff options
context:
space:
mode:
Diffstat (limited to 'core.j2.c')
-rw-r--r--core.j2.c935
1 files changed, 0 insertions, 935 deletions
diff --git a/core.j2.c b/core.j2.c
deleted file mode 100644
index a7bd9cc..0000000
--- a/core.j2.c
+++ /dev/null
@@ -1,935 +0,0 @@
-// Author: Paul Oliver <contact@pauloliver.dev>
-// Project: salis-v3
-
-// Core template of the salis simulator.
-// Different architectures and UIs can be attached in order to
-// create a streamlined source file.
-
-{% for include in includes|sort %}
-#include <{{ include }}>
-{% endfor %}
-
-// Each architecture defines its own process type
-struct Proc {
- {% for type, val in arch_vars.proc_fields %}
- {{ type }} {{ val }};
- {% endfor %}
-};
-
-// Simulation core
-// Each core runs on a separate thread
-// Core synchronization and IPC occurs at set intervals
-struct Core {
- uint64_t cycl;
- uint64_t mall;
- uint64_t muta[4];
-
- uint64_t pnum;
- uint64_t pcap;
- uint64_t pfst;
- uint64_t plst;
- uint64_t pcur;
- uint64_t psli;
-
- thrd_t thrd;
- uint64_t thrd_idx;
-
- uint64_t ivpt;
- uint64_t *ivav;
- uint8_t *iviv;
-
- // Architecture specific custom fields
- {% for type, val, _ in arch_vars.core_fields %}
- {{ type }} {{ val }};
- {% endfor %}
-
- struct Proc *pvec;
- uint8_t mvec[{{ mvec_size }}];
- uint8_t tgap[{{ thread_gap }}];
-};
-
-// Globals
-struct Core g_cores[{{ args.cores }}];
-uint64_t g_steps;
-uint64_t g_syncs;
-const struct Proc g_dead_proc;
-
-{% if args.command in ["load", "new"] %}
-char g_asav_pbuf[{{ auto_save_name_len }}];
-{% endif %}
-
-{% if data_push_path is defined %}
-sqlite3 *g_sim_data;
-{% endif %}
-
-// Before invoking salis_init(),
-// each UI must install its own logger functions
-void (*g_info)(const char *fmt, ...);
-void (*g_warn)(const char *fmt, ...);
-
-// Forward declarations
-// Each architecture must define these
-{% if args.command in ["bench", "new"] and anc_bytes is defined %}
-void arch_core_init(struct Core *core);
-{% endif %}
-
-void arch_core_free(struct Core *core);
-
-{% if args.command in ["load", "new"] %}
-void arch_core_save(FILE *f, const struct Core *core);
-{% endif %}
-
-{% if args.command in ["load"] %}
-void arch_core_load(FILE *f, struct Core *core);
-{% endif %}
-
-uint64_t arch_proc_mb0_addr(const struct Core *core, uint64_t pix);
-uint64_t arch_proc_mb0_size(const struct Core *core, uint64_t pix);
-uint64_t arch_proc_mb1_addr(const struct Core *core, uint64_t pix);
-uint64_t arch_proc_mb1_size(const struct Core *core, uint64_t pix);
-uint64_t arch_proc_ip_addr(const struct Core *core, uint64_t pix);
-uint64_t arch_proc_sp_addr(const struct Core *core, uint64_t pix);
-uint64_t arch_proc_slice(const struct Core *core, uint64_t pix);
-void arch_on_proc_kill(struct Core *core);
-void arch_proc_step(struct Core *core, uint64_t pix);
-
-{% if not args.optimized %}
-void arch_validate_proc(const struct Core *core, uint64_t pix);
-{% endif %}
-
-wchar_t arch_symbol(uint8_t inst);
-const char *arch_mnemonic(uint8_t inst);
-
-{% if data_push_path is defined %}
-void arch_push_data_header();
-void arch_push_data_line();
-{% endif %}
-
-// ----------------------------------------------------------------------------
-// Memory vector functions
-// ----------------------------------------------------------------------------
-{% if arch_vars.mvec_loop %}
-uint64_t mvec_loop(uint64_t addr) {
- return addr % {{ mvec_size }};
-}
-{% endif %}
-
-bool mvec_is_alloc(const struct Core *core, uint64_t addr) {
- assert(core);
-
- {% if arch_vars.mvec_loop %}
- return core->mvec[mvec_loop(addr)] & {{ mall_flag }} ? true : false;
- {% else %}
- if (addr < {{ mvec_size }}) {
- return core->mvec[addr] & {{ mall_flag }} ? true : false;
- } else {
- return true;
- }
- {% endif %}
-}
-
-void mvec_alloc(struct Core *core, uint64_t addr) {
- assert(core);
- assert(!mvec_is_alloc(core, addr));
- {% if arch_vars.mvec_loop %}
- core->mvec[mvec_loop(addr)] |= {{ mall_flag }};
- {% else %}
- assert(addr < {{ mvec_size }});
- core->mvec[addr] |= {{ mall_flag }};
- {% endif %}
- core->mall++;
-}
-
-void mvec_free(struct Core *core, uint64_t addr) {
- assert(core);
- assert(mvec_is_alloc(core, addr));
- {% if arch_vars.mvec_loop %}
- core->mvec[mvec_loop(addr)] ^= {{ mall_flag }};
- {% else %}
- assert(addr < {{ mvec_size }});
- core->mvec[addr] ^= {{ mall_flag }};
- {% endif %}
- core->mall--;
-}
-
-uint8_t mvec_get_byte(const struct Core *core, uint64_t addr) {
- assert(core);
- {% if arch_vars.mvec_loop %}
- return core->mvec[mvec_loop(addr)];
- {% else %}
- if (addr < {{ mvec_size }}) {
- return core->mvec[addr];
- } else {
- return 0;
- }
- {% endif %}
-}
-
-uint8_t mvec_get_inst(const struct Core *core, uint64_t addr) {
- assert(core);
- {% if arch_vars.mvec_loop %}
- return core->mvec[mvec_loop(addr)] & {{ inst_mask }};
- {% else %}
- if (addr < {{ mvec_size }}) {
- return core->mvec[addr] & {{ inst_mask }};
- } else {
- return 0;
- }
- {% endif %}
-}
-
-void mvec_set_inst(struct Core *core, uint64_t addr, uint8_t inst) {
- assert(core);
- assert(inst < {{ inst_cap}});
- {% if arch_vars.mvec_loop %}
- core->mvec[mvec_loop(addr)] &= {{ mall_flag }};
- core->mvec[mvec_loop(addr)] |= inst;
- {% else %}
- assert(addr < {{ mvec_size }});
- core->mvec[addr] &= {{ mall_flag }};
- core->mvec[addr] |= inst;
- {% endif %}
-}
-
-{% if args.muta_flip %}
-void mvec_flip_bit(struct Core *core, uint64_t addr, int bit) {
- assert(core);
- assert(bit < 8);
- core->mvec[addr] ^= (1 << bit) & {{ inst_mask }};
-}
-{% endif %}
-
-bool mvec_proc_is_live(const struct Core *core, uint64_t pix) {
- assert(core);
-
- return pix >= core->pfst && pix <= core->plst;
-}
-
-bool mvec_is_in_mb0_of_proc(const struct Core *core, uint64_t addr, uint64_t pix) {
- assert(core);
- assert(mvec_proc_is_live(core, pix));
-
- uint64_t mb0a = arch_proc_mb0_addr(core, pix);
- uint64_t mb0s = arch_proc_mb0_size(core, pix);
-
- return ((addr - mb0a) % {{ mvec_size }}) < mb0s;
-}
-
-bool mvec_is_in_mb1_of_proc(const struct Core *core, uint64_t addr, uint64_t pix) {
- assert(core);
- assert(mvec_proc_is_live(core, pix));
-
- uint64_t mb1a = arch_proc_mb1_addr(core, pix);
- uint64_t mb1s = arch_proc_mb1_size(core, pix);
-
- return ((addr - mb1a) % {{ mvec_size }}) < mb1s;
-}
-
-bool mvec_is_proc_owner(const struct Core *core, uint64_t addr, uint64_t pix) {
- assert(core);
- assert(mvec_proc_is_live(core, pix));
- return mvec_is_in_mb0_of_proc(core, addr, pix) || mvec_is_in_mb1_of_proc(core, addr, pix);
-}
-
-uint64_t mvec_get_owner(const struct Core *core, uint64_t addr) {
- assert(core);
- assert(mvec_is_alloc(core, addr));
-
- for (uint64_t pix = core->pfst; pix <= core->plst; ++pix) {
- if (mvec_is_proc_owner(core, addr, pix)) {
- return pix;
- }
- }
-
- assert(false);
- return -1;
-}
-
-// ----------------------------------------------------------------------------
-// Mutator functions
-// ----------------------------------------------------------------------------
-{% if args.command in ["bench", "new"] %}
-uint64_t muta_smix(uint64_t *seed) {
- assert(seed);
-
- uint64_t next = (*seed += 0x9e3779b97f4a7c15);
- next = (next ^ (next >> 30)) * 0xbf58476d1ce4e5b9;
- next = (next ^ (next >> 27)) * 0x94d049bb133111eb;
-
- return next ^ (next >> 31);
-}
-{% endif %}
-
-uint64_t muta_ro64(uint64_t x, int k) {
- return (x << k) | (x >> (64 - k));
-}
-
-uint64_t muta_next(struct Core *core) {
- assert(core);
-
- uint64_t r = muta_ro64(core->muta[1] * 5, 7) * 9;
- uint64_t t = core->muta[1] << 17;
-
- core->muta[2] ^= core->muta[0];
- core->muta[3] ^= core->muta[1];
- core->muta[1] ^= core->muta[2];
- core->muta[0] ^= core->muta[3];
-
- core->muta[2] ^= t;
- core->muta[3] = muta_ro64(core->muta[3], 45);
-
- return r;
-}
-
-void muta_cosmic_ray(struct Core *core) {
- assert(core);
-
- uint64_t a = muta_next(core) % {{ muta_range }};
- uint64_t b = muta_next(core);
-
- if (a < {{ mvec_size }}) {
- {% if args.muta_flip %}
- mvec_flip_bit(core, a, (int)(b % 8));
- {% else %}
- mvec_set_inst(core, a, b & {{ inst_mask }});
- {% endif %}
- }
-}
-
-// ----------------------------------------------------------------------------
-// Process functions
-// ----------------------------------------------------------------------------
-void proc_new(struct Core *core, const struct Proc *proc) {
- assert(core);
- assert(proc);
-
- if (core->pnum == core->pcap) {
- // Reallocate dynamic array
- uint64_t new_pcap = core->pcap * 2;
- struct Proc *new_pvec = calloc(new_pcap, sizeof(struct Proc));
-
- for (uint64_t pix = core->pfst; pix <= core->plst; ++pix) {
- uint64_t iold = pix % core->pcap;
- uint64_t inew = pix % new_pcap;
- memcpy(&new_pvec[inew], &core->pvec[iold], sizeof(struct Proc));
- }
-
- free(core->pvec);
- core->pcap = new_pcap;
- core->pvec = new_pvec;
- }
-
- core->pnum++;
- core->plst++;
- memcpy(&core->pvec[core->plst % core->pcap], proc, sizeof(struct Proc));
-}
-
-void proc_kill(struct Core *core) {
- assert(core);
- assert(core->pnum > 1);
-
- arch_on_proc_kill(core);
-
- core->pcur++;
- core->pfst++;
- core->pnum--;
-}
-
-const struct Proc *proc_get(const struct Core *core, uint64_t pix) {
- assert(core);
-
- if (mvec_proc_is_live(core, pix)) {
- return &core->pvec[pix % core->pcap];
- } else {
- return &g_dead_proc;
- }
-}
-
-struct Proc *proc_fetch(struct Core *core, uint64_t pix) {
- assert(core);
- assert(mvec_proc_is_live(core, pix));
-
- return &core->pvec[pix % core->pcap];
-}
-
-// ----------------------------------------------------------------------------
-// Core functions
-// ----------------------------------------------------------------------------
-{% if args.command in ["load", "new"] %}
-void core_save(FILE *f, const struct Core *core) {
- assert(f);
- assert(core);
-
- fwrite(&core->cycl, sizeof(uint64_t), 1, f);
- fwrite(&core->mall, sizeof(uint64_t), 1, f);
- fwrite( core->muta, sizeof(uint64_t), 4, f);
- fwrite(&core->pnum, sizeof(uint64_t), 1, f);
- fwrite(&core->pcap, sizeof(uint64_t), 1, f);
- fwrite(&core->pfst, sizeof(uint64_t), 1, f);
- fwrite(&core->plst, sizeof(uint64_t), 1, f);
- fwrite(&core->pcur, sizeof(uint64_t), 1, f);
- fwrite(&core->psli, sizeof(uint64_t), 1, f);
- fwrite(&core->ivpt, sizeof(uint64_t), 1, f);
-
- fwrite(core->iviv, sizeof(uint8_t), {{ sync_interval }}, f);
- fwrite(core->ivav, sizeof(uint64_t), {{ sync_interval }}, f);
- fwrite(core->pvec, sizeof(struct Proc), core->pcap, f);
- fwrite(core->mvec, sizeof(uint8_t), {{ mvec_size }}, f);
-
- arch_core_save(f, core);
-}
-{% endif %}
-
-{% if args.command in ["bench", "new"] %}
-{% if anc_bytes is defined %}
-void core_assemble_ancestor(struct Core *core) {
- assert(core);
-
- {% if arch_vars.mvec_loop %}
- uint64_t addr = {{ uint64_half }};
- {% else %}
- uint64_t addr = 0;
- {% endif %}
-
- uint8_t anc_bytes[] = {
- {{ anc_bytes|join(",") }}
- };
-
- for (uint64_t i = 0; i < sizeof(anc_bytes); ++i, ++addr) {
- for (uint64_t j = 0; j < {{ args.clones }}; ++j) {
- uint64_t addr_clone = addr + (({{ mvec_size }} / {{ args.clones }})) * j;
-
- mvec_alloc(core, addr_clone);
- mvec_set_inst(core, addr_clone, anc_bytes[i]);
- }
- }
-}
-{% endif %}
-
-void core_init(struct Core *core, uint64_t *seed) {
- assert(core);
- assert(seed);
-
- if (*seed) {
- core->muta[0] = muta_smix(seed);
- core->muta[1] = muta_smix(seed);
- core->muta[2] = muta_smix(seed);
- core->muta[3] = muta_smix(seed);
- }
-
- core->pnum = {{ args.clones }};
- core->pcap = {{ args.clones }};
- core->plst = {{ args.clones }} - 1;
- core->iviv = calloc({{ sync_interval }}, sizeof(uint8_t));
- core->ivav = calloc({{ sync_interval }}, sizeof(uint64_t));
- core->pvec = calloc(core->pcap, sizeof(struct Proc));
-
- assert(core->iviv);
- assert(core->ivav);
- assert(core->pvec);
-
- {% if anc_bytes is defined %}
- core_assemble_ancestor(core);
- arch_core_init(core);
- {% endif %}
-}
-{% endif %}
-
-{% if args.command in ["load"] %}
-void core_load(FILE *f, struct Core *core) {
- assert(f);
- assert(core);
-
- fread(&core->cycl, sizeof(uint64_t), 1, f);
- fread(&core->mall, sizeof(uint64_t), 1, f);
- fread( core->muta, sizeof(uint64_t), 4, f);
- fread(&core->pnum, sizeof(uint64_t), 1, f);
- fread(&core->pcap, sizeof(uint64_t), 1, f);
- fread(&core->pfst, sizeof(uint64_t), 1, f);
- fread(&core->plst, sizeof(uint64_t), 1, f);
- fread(&core->pcur, sizeof(uint64_t), 1, f);
- fread(&core->psli, sizeof(uint64_t), 1, f);
- fread(&core->ivpt, sizeof(uint64_t), 1, f);
-
- core->iviv = calloc({{ sync_interval }}, sizeof(uint8_t));
- core->ivav = calloc({{ sync_interval }}, sizeof(uint64_t));
- core->pvec = calloc(core->pcap, sizeof(struct Proc));
-
- assert(core->iviv);
- assert(core->ivav);
- assert(core->pvec);
-
- fread(core->iviv, sizeof(uint8_t), {{ sync_interval }}, f);
- fread(core->ivav, sizeof(uint64_t), {{ sync_interval }}, f);
- fread(core->pvec, sizeof(struct Proc), core->pcap, f);
- fread(core->mvec, sizeof(uint8_t), {{ mvec_size }}, f);
-
- arch_core_load(f, core);
-}
-{% endif %}
-
-void core_pull_ipcm(struct Core *core) {
- assert(core);
- assert(core->ivpt < {{ sync_interval }});
-
- uint8_t *iinst = &core->iviv[core->ivpt];
- uint64_t *iaddr = &core->ivav[core->ivpt];
-
- if ((*iinst & {{ ipc_flag }}) != 0) {
- mvec_set_inst(core, *iaddr, *iinst & {{ inst_mask }});
-
- *iinst = 0;
- *iaddr = 0;
- }
-
- assert(*iinst == 0);
- assert(*iaddr == 0);
-}
-
-void core_push_ipcm(struct Core *core, uint8_t inst, uint64_t addr) {
- assert(core);
- assert(core->ivpt < {{ sync_interval }});
- assert((inst & {{ ipc_flag }}) == 0);
-
- uint8_t *iinst = &core->iviv[core->ivpt];
- uint64_t *iaddr = &core->ivav[core->ivpt];
-
- assert(*iinst == 0);
- assert(*iaddr == 0);
-
- *iinst = inst | {{ ipc_flag }};
- *iaddr = addr;
-}
-
-void core_step(struct Core *core) {
- assert(core);
-
- if (core->psli != 0) {
- core_pull_ipcm(core);
- arch_proc_step(core, core->pcur);
-
- core->psli--;
- core->ivpt++;
-
- return;
- }
-
- if (core->pcur != core->plst) {
- core->psli = arch_proc_slice(core, ++core->pcur);
- core_step(core);
- return;
- }
-
- core->pcur = core->pfst;
- core->psli = arch_proc_slice(core, core->pcur);
- core->cycl++;
-
- // TODO: Implement day-night cycle
- while (core->mall > {{ mvec_size }} / 2 && core->pnum > 1) {
- proc_kill(core);
- }
-
- muta_cosmic_ray(core);
- core_step(core);
-}
-
-// ----------------------------------------------------------------------------
-// Main salis functions
-// ----------------------------------------------------------------------------
-{% if args.command in ["load", "new"] %}
-void salis_save(const char *path) {
- {% if args.compress %}
- size_t size = 0;
- char *in = NULL;
- FILE *f = open_memstream(&in, &size);
- {% else %}
- FILE *f = fopen(path, "wb");
- {% endif %}
-
- assert(f);
-
- for (int i = 0; i < {{ args.cores }}; ++i) {
- core_save(f, &g_cores[i]);
- }
-
- fwrite(&g_steps, sizeof(uint64_t), 1, f);
- fwrite(&g_syncs, sizeof(uint64_t), 1, f);
- fclose(f);
-
- {% if args.compress %}
- assert(size);
-
- char *out = malloc(size);
- assert(out);
-
- z_stream strm = { 0 };
- strm.zalloc = NULL,
- strm.zfree = NULL,
- strm.opaque = NULL,
-
- deflateInit(&strm, Z_DEFAULT_COMPRESSION);
-
- strm.avail_in = size;
- strm.avail_out = size;
- strm.next_in = (Bytef *)in;
- strm.next_out = (Bytef *)out;
-
- deflate(&strm, Z_FINISH);
-
- FILE *fx = fopen(path, "wb");
- assert(fx);
-
- fwrite(&size, sizeof(size_t), 1, fx);
- fwrite(out, sizeof(char), strm.total_out, fx);
- fclose(fx);
-
- deflateEnd(&strm);
-
- free(in);
- free(out);
- {% endif %}
-}
-
-void salis_auto_save() {
- {% if not args.optimized %}
- int rem = snprintf(
- {% else %}
- snprintf(
- {% endif %}
- g_asav_pbuf,
- {{ auto_save_name_len }},
- "%s-%#018lx",
- "{{ sim_path }}",
- g_steps
- );
-
- assert(rem >= 0);
- assert(rem < {{ auto_save_name_len }});
-
- g_info("Saving simulation state on step '%#lx'", g_steps);
- salis_save(g_asav_pbuf);
-}
-{% endif %}
-
-{% if data_push_path is defined %}
-void salis_exec_sql(int blob_cnt, const void **blobs, const int *blob_sizes, const char *sql_format, ...) {
- assert(sql_format);
-
- va_list args;
- va_start(args, sql_format);
- int sql_len = vsnprintf(NULL, 0, sql_format, args) + 1;
- char *sql_str = malloc(sql_len);
- assert(sql_str);
- va_end(args);
-
- va_start(args, sql_format);
- vsprintf(sql_str, sql_format, args);
- va_end(args);
-
- // Prepare statement
- int sql_res;
- sqlite3_stmt *sql_stmt;
-
- sql_res = sqlite3_prepare_v2(g_sim_data, sql_str, -1, &sql_stmt, NULL);
- assert(sql_res == SQLITE_OK);
- free(sql_str);
-
- // Caller may pass multiple binary blobs to the query
- for (int i = 0; i < blob_cnt; ++i) {
- assert(blobs[i]);
- sql_res = sqlite3_bind_blob(sql_stmt, i + 1, blobs[i], blob_sizes[i], SQLITE_STATIC);
- assert(sql_res == SQLITE_OK);
- }
-
- // Execute the statement
- // Only handle SQLITE_BUSY error, in which case we retry the query.
- // In principle, setting 'journal_mode=wal;' should help prevent busy database errors.
- while (true) {
- sql_res = sqlite3_step(sql_stmt);
-
- if (sql_res == SQLITE_DONE || sql_res == SQLITE_ROW) {
- break;
- }
-
- g_warn("SQLite database returned error '%d' with message:", sql_res);
- g_warn(sqlite3_errmsg(g_sim_data));
-
- if (sql_res == SQLITE_BUSY) {
- g_info("Will retry query...");
- continue;
- }
-
- // Fail on unhandled error
- assert(false);
- }
-
- sqlite3_finalize(sql_stmt);
-}
-{% endif %}
-
-{% if args.command in ["bench", "new"] %}
-void salis_init() {
- assert(g_info);
- assert(g_warn);
-
- uint64_t seed = {{ args.seed }};
-
- for (int i = 0; i < {{ args.cores }}; ++i) {
- core_init(&g_cores[i], &seed);
- }
-
- {% if args.command in ["new"] %}
- salis_auto_save();
- {% endif %}
-
- {% if data_push_path is defined %}
- sqlite3_open("{{ data_push_path }}", &g_sim_data);
- assert(g_sim_data);
-
- // Install busy handler to retry transactions if DB is locked
- sqlite3_busy_timeout(g_sim_data, {{ data_push_busy_timeout }});
-
- // Enable Write-Ahead Logging (WAL)
- // This seems to help prevent DB locks when displaying live data
- // See: https://sqlite.org/wal.html
- salis_exec_sql(0, NULL, NULL, "pragma journal_mode=wal;");
-
- arch_push_data_header();
- arch_push_data_line();
- {% endif %}
-}
-{% endif %}
-
-{% if args.command in ["load"] %}
-void salis_load() {
- {% if args.compress %}
- FILE *fx = fopen("{{ sim_path }}", "rb");
- assert(fx);
-
- fseek(fx, 0, SEEK_END);
- size_t x_size = ftell(fx) - sizeof(size_t);
- char *in = malloc(x_size);
- rewind(fx);
- assert(x_size);
- assert(in);
-
- size_t size = 0;
- fread(&size, sizeof(size_t), 1, fx);
- fread(in, 1, x_size, fx);
- fclose(fx);
- assert(size);
-
- char *out = malloc(size);
- assert(out);
-
- z_stream strm = { 0 };
- strm.next_in = (Bytef *)in;
- strm.avail_in = x_size;
- strm.zalloc = NULL;
- strm.zfree = NULL;
- strm.opaque = NULL;
-
- inflateInit(&strm);
-
- strm.avail_out = size;
- strm.next_out = (Bytef *)out;
-
- {% if not args.optimized %}
- assert(inflate(&strm, Z_FINISH));
- {% else %}
- inflate(&strm, Z_FINISH);
- {% endif %}
-
- inflateEnd(&strm);
-
- FILE *f = fmemopen(out, size, "rb");
- {% else %}
- FILE *f = fopen("{{ sim_path }}", "rb");
- {% endif %}
-
- assert(f);
-
- for (int i = 0; i < {{ args.cores }}; ++i) {
- core_load(f, &g_cores[i]);
- }
-
- fread(&g_steps, sizeof(uint64_t), 1, f);
- fread(&g_syncs, sizeof(uint64_t), 1, f);
- fclose(f);
-
- {% if args.compress %}
- free(in);
- free(out);
- {% endif %}
-
- {% if data_push_path is defined %}
- sqlite3_open("{{ data_push_path }}", &g_sim_data);
- assert(g_sim_data);
-
- // Install busy handler to retry transactions if DB is locked
- sqlite3_busy_timeout(g_sim_data, {{ data_push_busy_timeout }});
- {% endif %}
-}
-{% endif %}
-
-int salis_thread(struct Core *core) {
- assert(core);
-
- for (uint64_t i = 0; i < core->thrd_idx; ++i) {
- core_step(core);
- }
-
- return 0;
-}
-
-void salis_run_thread(uint64_t ns) {
- for (int i = 0; i < {{ args.cores }}; ++i) {
- g_cores[i].thrd_idx = ns;
-
- thrd_create(
- &g_cores[i].thrd,
- (thrd_start_t)salis_thread,
- &g_cores[i]
- );
- }
-
- for (int i = 0; i < {{ args.cores }}; ++i) {
- thrd_join(g_cores[i].thrd, NULL);
- }
-
- g_steps += ns;
-}
-
-void salis_sync() {
- uint8_t *iviv0 = g_cores[0].iviv;
- uint64_t *ivav0 = g_cores[0].ivav;
-
- for (int i = 1; i < {{ args.cores }}; ++i) {
- g_cores[i - 1].iviv = g_cores[i].iviv;
- g_cores[i - 1].ivav = g_cores[i].ivav;
- }
-
- g_cores[{{ args.cores }} - 1].iviv = iviv0;
- g_cores[{{ args.cores }} - 1].ivav = ivav0;
-
- for (int i = 0; i < {{ args.cores }}; ++i) {
- g_cores[i].ivpt = 0;
- }
-
- g_syncs++;
-}
-
-void salis_loop(uint64_t ns, uint64_t dt) {
- assert(dt);
-
- if (ns < dt) {
- salis_run_thread(ns);
- return;
- }
-
- salis_run_thread(dt);
- salis_sync();
-
- {% if args.command in ["load", "new"] %}
- if (g_steps % {{ auto_save_interval }} == 0) {
- salis_auto_save();
- }
- {% endif %}
-
- {% if data_push_path is defined %}
- if (g_steps % {{ data_push_interval }} == 0) {
- arch_push_data_line();
- }
- {% endif %}
-
- salis_loop(ns - dt, {{ sync_interval }});
-}
-
-{% if not args.optimized %}
-void salis_validate_core(const struct Core *core) {
- assert(core->cycl <= g_steps);
- assert(core->plst >= core->pfst);
- assert(core->pnum == core->plst + 1 - core->pfst);
- assert(core->pnum <= core->pcap);
- assert(core->pcur >= core->pfst && core->pcur <= core->plst);
-
- uint64_t mall = 0;
-
- for (uint64_t i = 0; i < {{ mvec_size }}; ++i) {
- mall += mvec_is_alloc(core, i) ? 1 : 0;
- }
-
- assert(core->mall == mall);
-
- for (uint64_t i = core->pfst; i <= core->plst; ++i) {
- arch_validate_proc(core, i);
- }
-
- for (uint64_t i = 0; i < {{ sync_interval }}; ++i) {
- uint8_t iinst = core->iviv[i];
-
- if ((iinst & {{ ipc_flag }}) == 0) {
- uint64_t iaddr = core->ivav[i];
-
- assert(iinst == 0);
- assert(iaddr == 0);
- }
- }
-
- assert(core->ivpt == g_steps % {{ sync_interval }});
-}
-
-void salis_validate() {
- assert(g_steps / {{ sync_interval }} == g_syncs);
-
- for (int i = 0; i < {{ args.cores }}; ++i) {
- salis_validate_core(&g_cores[i]);
- }
-}
-{% endif %}
-
-void salis_step(uint64_t ns) {
- assert(ns);
- salis_loop(ns, {{ sync_interval }} - (g_steps % {{ sync_interval }}));
-
- {% if not args.optimized %}
- salis_validate();
- {% endif %}
-}
-
-void salis_free() {
- {% if data_push_path is defined %}
- assert(g_sim_data);
- sqlite3_close(g_sim_data);
- {% endif %}
-
- for (int i = 0; i < {{ args.cores }}; ++i) {
- arch_core_free(&g_cores[i]);
-
- assert(g_cores[i].pvec);
- assert(g_cores[i].iviv);
- assert(g_cores[i].ivav);
-
- free(g_cores[i].pvec);
- free(g_cores[i].iviv);
- free(g_cores[i].ivav);
-
- g_cores[i].pvec = NULL;
- g_cores[i].iviv = NULL;
- g_cores[i].ivav = NULL;
- }
-}
-
-// ----------------------------------------------------------------------------
-// Architecture
-// ----------------------------------------------------------------------------
-{% include "arch/" ~ args.arch ~ "/arch.j2.c" %}
-
-// ----------------------------------------------------------------------------
-// UI
-// ----------------------------------------------------------------------------
-{% if args.command in ["load", "new"] %}
- {% include "ui/" ~ args.ui ~ "/ui.j2.c" %}
-{% else %}
- {% include "bench.j2.c" %}
-{% endif %}