From 9f7e70904e6c0fa650323ac5e50ebf6003da333c Mon Sep 17 00:00:00 2001 From: Paul Oliver Date: Tue, 24 Feb 2026 01:33:45 +0100 Subject: Removes usage of Jinja templates Use CPP to pre-process C files instead --- core.j2.c | 935 -------------------------------------------------------------- 1 file changed, 935 deletions(-) delete mode 100644 core.j2.c (limited to 'core.j2.c') 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 -// 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 %} -- cgit v1.2.3-70-g09d2