diff options
Diffstat (limited to 'src/salis.c')
| -rw-r--r-- | src/salis.c | 811 |
1 files changed, 0 insertions, 811 deletions
diff --git a/src/salis.c b/src/salis.c deleted file mode 100644 index 348385f..0000000 --- a/src/salis.c +++ /dev/null @@ -1,811 +0,0 @@ -// Project: Salis -// Author: Paul Oliver -// Email: contact@pauloliver.dev - -/* - * Core of the Salis simulator. Can be built against different architectures - * and UI modules. - */ - -#include <assert.h> -#include <ctype.h> -#include <stdbool.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <threads.h> - -#ifdef COMPRESS -#include <zlib.h> -#endif - -#define ACT_BENCH (1) -#define ACT_LOAD (2) -#define ACT_NEW (3) - -#define ASM_LINE_LEN (0x100) - -#define MALL_FLAG (0x80) -#define IPCM_FLAG (0x80) -#define INST_CAPS (0x80) -#define INST_MASK (0x7f) - -#define U64_HALF (0x8000000000000000) - -typedef struct Core Core; -typedef struct Ipcm Ipcm; -typedef struct Proc Proc; -typedef thrd_t Thread; -typedef uint64_t u64; -typedef uint8_t u8; - -struct Core { - u64 mall; - u64 muta[4]; - u64 pnum; - u64 pcap; - u64 pfst; - u64 plst; - u64 pcur; - u64 psli; - u64 ncyc; - - Thread thread; - u64 tix; - - u64 ivpt; - u8 *iviv; - u64 *ivav; - - Proc *pvec; - u8 mvec[MVEC_SIZE]; - u8 tgap[TGAP_SIZE]; -}; - -Core g_cores[CORE_COUNT]; -u64 g_steps; -u64 g_syncs; -#if ACTION == ACT_LOAD || ACTION == ACT_NEW -char g_asav_pbuf[AUTO_SAVE_NAME_LEN]; -#endif -const Proc g_dead_proc; - -#include ARCH_SOURCE - -#if ACTION == ACT_BENCH || ACTION == ACT_NEW -char g_mnemo_table[0x100][MNEMONIC_BUFF_SIZE]; -#endif - -#ifdef MVEC_LOOP -u64 mvec_loop(u64 addr) { - return addr % MVEC_SIZE; -} -#endif - -bool mvec_is_alloc(const Core *core, u64 addr) { - assert(core); -#ifdef 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(Core *core, u64 addr) { - assert(core); - assert(!mvec_is_alloc(core, addr)); -#ifdef 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(Core *core, u64 addr) { - assert(core); - assert(mvec_is_alloc(core, addr)); -#ifdef MVEC_LOOP - core->mvec[mvec_loop(addr)] ^= MALL_FLAG; -#else - assert(addr < MVEC_SIZE); - core->mvec[addr] ^= MALL_FLAG; -#endif - core->mall--; -} - -u8 mvec_get_byte(const Core *core, u64 addr) { - assert(core); -#ifdef MVEC_LOOP - return core->mvec[mvec_loop(addr)]; -#else - if (addr < MVEC_SIZE) { - return core->mvec[addr]; - } else { - return 0; - } -#endif -} - -u8 mvec_get_inst(const Core *core, u64 addr) { - assert(core); -#ifdef 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(Core *core, u64 addr, u8 inst) { - assert(core); - assert(inst < INST_CAPS); -#ifdef 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 MUTA_FLIP_BIT == 1 -void mvec_flip_bit(Core *core, u64 addr, int bit) { - assert(core); - assert(bit < 8); - core->mvec[addr] ^= (1 << bit) & INST_MASK; -} -#endif - -bool mvec_is_proc_owner(const Core *core, u64 addr, u64 pix) { - assert(core); - assert(proc_is_live(core, pix)); - - u64 mb0a = arch_proc_mb0_addr(core, pix); - u64 mb0s = arch_proc_mb0_size(core, pix); - - if (((addr - mb0a) % MVEC_SIZE) < mb0s) { - return true; - } - - u64 mb1a = arch_proc_mb1_addr(core, pix); - u64 mb1s = arch_proc_mb1_size(core, pix); - - if (((addr - mb1a) % MVEC_SIZE) < mb1s) { - return true; - } - - return false; -} - -u64 mvec_get_owner(const Core *core, u64 addr) { - assert(core); - assert(mvec_is_alloc(core, addr)); - - for (u64 pix = core->pfst; pix <= core->plst; ++pix) { - if (mvec_is_proc_owner(core, addr, pix)) { - return pix; - } - } - - assert(false); - return -1; -} - -#if ACTION == ACT_BENCH || ACTION == ACT_NEW -u64 muta_smix(u64 *seed) { - assert(seed); - - u64 next = (*seed += 0x9e3779b97f4a7c15); - next = (next ^ (next >> 30)) * 0xbf58476d1ce4e5b9; - next = (next ^ (next >> 27)) * 0x94d049bb133111eb; - - return next ^ (next >> 31); -} -#endif - -u64 muta_ro64(u64 x, int k) { - return (x << k) | (x >> (64 - k)); -} - -u64 muta_next(Core *core) { - assert(core); - - u64 r = muta_ro64(core->muta[1] * 5, 7) * 9; - u64 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(Core *core) { - assert(core); - - u64 a = muta_next(core) % MUTA_RANGE; - u64 b = muta_next(core); - - if (a < MVEC_SIZE) { -#if MUTA_FLIP_BIT == 1 - mvec_flip_bit(core, a, (int)(b % 8)); -#else - mvec_set_inst(core, a, b & INST_MASK); -#endif - } -} - -void proc_new(Core *core, const Proc *proc) { - assert(core); - assert(proc); - - if (core->pnum == core->pcap) { - u64 new_pcap = core->pcap * 2; - Proc *new_pvec = calloc(new_pcap, sizeof(Proc)); - - for (u64 pix = core->pfst; pix <= core->plst; ++pix) { - u64 iold = pix % core->pcap; - u64 inew = pix % new_pcap; - memcpy(&new_pvec[inew], &core->pvec[iold], sizeof(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(Proc)); -} - -void proc_kill(Core *core) { - assert(core); - assert(core->pnum > 1); - - arch_on_proc_kill(core); - - core->pcur++; - core->pfst++; - core->pnum--; -} - -bool proc_is_live(const Core *core, u64 pix) { - assert(core); - - return pix >= core->pfst && pix <= core->plst; -} - -const Proc *proc_get(const Core *core, u64 pix) { - assert(core); - - if (proc_is_live(core, pix)) { - return &core->pvec[pix % core->pcap]; - } else { - return &g_dead_proc; - } -} - -Proc *proc_fetch(Core *core, u64 pix) { - assert(core); - assert(proc_is_live(core, pix)); - - return &core->pvec[pix % core->pcap]; -} - -#if ACTION == ACT_LOAD || ACTION == ACT_NEW -void core_save(FILE *f, const Core *core) { - assert(f); - assert(core); - - fwrite(&core->mall, sizeof(u64), 1, f); - fwrite( core->muta, sizeof(u64), 4, f); - fwrite(&core->pnum, sizeof(u64), 1, f); - fwrite(&core->pcap, sizeof(u64), 1, f); - fwrite(&core->pfst, sizeof(u64), 1, f); - fwrite(&core->plst, sizeof(u64), 1, f); - fwrite(&core->pcur, sizeof(u64), 1, f); - fwrite(&core->psli, sizeof(u64), 1, f); - fwrite(&core->ncyc, sizeof(u64), 1, f); - fwrite(&core->ivpt, sizeof(u64), 1, f); - - fwrite(core->iviv, sizeof(u8), SYNC_INTERVAL, f); - fwrite(core->ivav, sizeof(u64), SYNC_INTERVAL, f); - fwrite(core->pvec, sizeof(Proc), core->pcap, f); - fwrite(core->mvec, sizeof(u8), MVEC_SIZE, f); -} -#endif - -#if ACTION == ACT_BENCH || ACTION == ACT_NEW -u64 core_assemble_ancestor(int cix, const char *anc) { - assert(cix >= 0 && cix < CORE_COUNT); - assert(anc); - - if (anc[0] == '_') { - return 0; - } - - FILE *f = fopen(anc, "r"); - - assert(f); - -#if ANC_HALF == 1 - u64 addr = U64_HALF; -#else - u64 addr = 0; -#endif - - char line[ASM_LINE_LEN] = {0}; - Core *core = &g_cores[cix]; - - for (; fgets(line, ASM_LINE_LEN, f); ++addr) { -#ifndef NDEBUG - bool line_ok = false; -#endif - - line[strcspn(line, "\r\n")] = '\0'; - - for (int i = 0; i < 0x100; ++i) { - if (strcmp(line, g_mnemo_table[i]) == 0) { - for (u64 j = 0; j < ANC_CLONES; ++j) { - u64 addr_clone = addr + ((MVEC_SIZE / ANC_CLONES) * j); - - mvec_alloc(core, addr_clone); - mvec_set_inst(core, addr_clone, i); - } - -#ifndef NDEBUG - line_ok = true; -#endif - break; - } - } - - assert(line_ok); - } - - fclose(f); - - return addr; -} - -void core_init(int cix, u64 *seed, const char *anc) { - assert(cix >= 0 && cix < CORE_COUNT); - assert(seed); - assert(anc); - - Core *core = &g_cores[cix]; - - 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 = ANC_CLONES; - core->pcap = ANC_CLONES; - core->plst = ANC_CLONES - 1; - core->iviv = calloc(SYNC_INTERVAL, sizeof(u8)); - core->ivav = calloc(SYNC_INTERVAL, sizeof(u64)); - core->pvec = calloc(core->pcap, sizeof(Proc)); - - assert(core->iviv); - assert(core->ivav); - assert(core->pvec); - - u64 anc_size = core_assemble_ancestor(cix, anc); - -#if ANC_HALF == 1 - anc_size -= U64_HALF; -#endif - - arch_anc_init(core, anc_size); -} -#endif - -#if ACTION == ACT_LOAD -void core_load(FILE *f, Core *core) { - assert(f); - assert(core); - - fread(&core->mall, sizeof(u64), 1, f); - fread( core->muta, sizeof(u64), 4, f); - fread(&core->pnum, sizeof(u64), 1, f); - fread(&core->pcap, sizeof(u64), 1, f); - fread(&core->pfst, sizeof(u64), 1, f); - fread(&core->plst, sizeof(u64), 1, f); - fread(&core->pcur, sizeof(u64), 1, f); - fread(&core->psli, sizeof(u64), 1, f); - fread(&core->ncyc, sizeof(u64), 1, f); - fread(&core->ivpt, sizeof(u64), 1, f); - - core->iviv = calloc(SYNC_INTERVAL, sizeof(u8)); - core->ivav = calloc(SYNC_INTERVAL, sizeof(u64)); - core->pvec = calloc(core->pcap, sizeof(Proc)); - - assert(core->iviv); - assert(core->ivav); - assert(core->pvec); - - fread(core->iviv, sizeof(u8), SYNC_INTERVAL, f); - fread(core->ivav, sizeof(u64), SYNC_INTERVAL, f); - fread(core->pvec, sizeof(Proc), core->pcap, f); - fread(core->mvec, sizeof(u8), MVEC_SIZE, f); -} -#endif - -void core_pull_ipcm(Core *core) { - assert(core); - assert(core->ivpt < SYNC_INTERVAL); - - u8 *iinst = &core->iviv[core->ivpt]; - u64 *iaddr = &core->ivav[core->ivpt]; - - if ((*iinst & IPCM_FLAG) != 0) { - mvec_set_inst(core, *iaddr, *iinst & INST_MASK); - - *iinst = 0; - *iaddr = 0; - } - - assert(*iinst == 0); - assert(*iaddr == 0); -} - -void core_push_ipcm(Core *core, u8 inst, u64 addr) { - assert(core); - assert(core->ivpt < SYNC_INTERVAL); - assert((inst & IPCM_FLAG) == 0); - - u8 *iinst = &core->iviv[core->ivpt]; - u64 *iaddr = &core->ivav[core->ivpt]; - - assert(*iinst == 0); - assert(*iaddr == 0); - - *iinst = inst | IPCM_FLAG; - *iaddr = addr; -} - -void core_step(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->ncyc++; - - while (core->mall > MVEC_SIZE / 2 && core->pnum > 1) { - proc_kill(core); - } - - muta_cosmic_ray(core); - core_step(core); -} - -#if ACTION == ACT_LOAD || ACTION == ACT_NEW -void salis_save(const char *path) { -#ifdef 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 < CORE_COUNT; ++i) { - core_save(f, &g_cores[i]); - } - - fwrite(&g_steps, sizeof(u64), 1, f); - fwrite(&g_syncs, sizeof(u64), 1, f); - fclose(f); - -#ifdef 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 (g_steps % AUTO_SAVE_INTERVAL != 0) { - return; - } - -#ifndef NDEBUG - 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); - - salis_save(g_asav_pbuf); -} -#endif - -#if ACTION == ACT_BENCH || ACTION == ACT_NEW -void salis_init() { - for (int i = 0; i < 0x100; ++i) { - arch_mnemonic(i, g_mnemo_table[i]); - } - - u64 seed = SEED; - char anc_list[] = ANC_LIST; - - assert(anc_list); - - for (int i = 0; i < CORE_COUNT; ++i) { - core_init(i, &seed, strtok(i ? NULL : anc_list, ",")); - } - -#if ACTION == ACT_NEW - salis_auto_save(); -#endif -} -#endif - -#if ACTION == ACT_LOAD -void salis_load() { -#ifdef 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; - -#ifdef NDEBUG - inflate(&strm, Z_FINISH); -#else - assert(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 < CORE_COUNT; ++i) { - core_load(f, &g_cores[i]); - } - - fread(&g_steps, sizeof(u64), 1, f); - fread(&g_syncs, sizeof(u64), 1, f); - fclose(f); - -#ifdef COMPRESS - free(in); - free(out); -#endif -} -#endif - -int salis_thread(Core *core) { - assert(core); - - for (u64 i = 0; i < core->tix; ++i) { - core_step(core); - } - - return 0; -} - -void salis_run_thread(u64 ns) { - for (int i = 0; i < CORE_COUNT; ++i) { - g_cores[i].tix = ns; - - thrd_create( - &g_cores[i].thread, - (thrd_start_t)salis_thread, - &g_cores[i] - ); - } - - for (int i = 0; i < CORE_COUNT; ++i) { - thrd_join(g_cores[i].thread, NULL); - } - - g_steps += ns; -} - -void salis_sync() { - u8 *iviv0 = g_cores[0].iviv; - u64 *ivav0 = g_cores[0].ivav; - - for (int i = 1; i < CORE_COUNT; ++i) { - g_cores[i - 1].iviv = g_cores[i].iviv; - g_cores[i - 1].ivav = g_cores[i].ivav; - } - - g_cores[CORE_COUNT - 1].iviv = iviv0; - g_cores[CORE_COUNT - 1].ivav = ivav0; - - for (int i = 0; i < CORE_COUNT; ++i) { - g_cores[i].ivpt = 0; - } - - g_syncs++; -} - -void salis_loop(u64 ns, u64 dt) { - assert(dt); - - if (ns < dt) { - salis_run_thread(ns); - return; - } - - salis_run_thread(dt); - salis_sync(); -#if ACTION == ACT_LOAD || ACTION == ACT_NEW - salis_auto_save(); -#endif - salis_loop(ns - dt, SYNC_INTERVAL); -} - -#ifndef NDEBUG -void salis_validate_core(const Core *core) { - 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); - assert(core->ncyc <= g_steps); - - u64 mall = 0; - - for (u64 i = 0; i < MVEC_SIZE; ++i) { - mall += mvec_is_alloc(core, i) ? 1 : 0; - } - - assert(core->mall == mall); - - for (u64 i = core->pfst; i <= core->plst; ++i) { - arch_validate_proc(core, i); - } - - for (u64 i = 0; i < SYNC_INTERVAL; ++i) { - u8 iinst = core->iviv[i]; - - if ((iinst & IPCM_FLAG) == 0) { - u64 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 < CORE_COUNT; ++i) { - salis_validate_core(&g_cores[i]); - } -} -#endif - -void salis_step(u64 ns) { - assert(ns); - salis_loop(ns, SYNC_INTERVAL - (g_steps % SYNC_INTERVAL)); - -#ifndef NDEBUG - salis_validate(); -#endif -} - -void salis_free() { - for (int i = 0; i < CORE_COUNT; ++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; - } -} - -#include UI |
