diff options
Diffstat (limited to 'arch/v1/arch.c')
| -rw-r--r-- | arch/v1/arch.c | 989 |
1 files changed, 989 insertions, 0 deletions
diff --git a/arch/v1/arch.c b/arch/v1/arch.c new file mode 100644 index 0000000..ea6ff36 --- /dev/null +++ b/arch/v1/arch.c @@ -0,0 +1,989 @@ +// file : arch/v1/arch.c +// project : Salis-VM +// author : Paul Oliver <contact@pauloliver.dev> +// +// Based on the original VM architecture from Salis-V1. +// The only addition are the extra core-fields used for data aggregation. + +// index: +// [section] includes +// [section] getters +// [section] statics +// [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] statics +// ---------------------------------------------------------------------------- +static void increment_ip(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + proc->ip++; + proc->sp = proc->ip; +} + +static bool is_between(uint8_t inst, uint8_t lo, uint8_t hi) { + assert(inst < ARCH_INST_COUNT); + assert(lo < ARCH_INST_COUNT); + assert(hi < ARCH_INST_COUNT); + assert(lo < hi); + return (inst >= lo) && (inst <= hi); +} + +static bool is_key(uint8_t inst) { + assert(inst < ARCH_INST_COUNT); + return is_between(inst, keya, keyp); +} + +#if !defined(NDEBUG) +static bool is_lock(uint8_t inst) { + assert(inst < ARCH_INST_COUNT); + return is_between(inst, loka, lokp); +} +#endif + +static bool is_rmod(uint8_t inst) { + assert(inst < ARCH_INST_COUNT); + return is_between(inst, nop0, nop3); +} + +static bool key_lock_match(uint8_t key, uint8_t lock) { + assert(key < ARCH_INST_COUNT); + assert(lock < ARCH_INST_COUNT); + assert(is_key(key)); + return (key - keya) == (lock - loka); +} + +static bool seek(struct Core *core, uint64_t pix, bool fwrd) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + + if (proc->ip + 1 >= MVEC_SIZE) { + increment_ip(core, pix); + return false; + } + + uint8_t next = mvec_get_inst(core, proc->ip + 1); + + if (!is_key(next)) { + increment_ip(core, pix); + return false; + } + + if (proc->sp >= MVEC_SIZE) { + // HALT: process SP address is invalid + core->hlts++; + return false; + } + + uint8_t spin = mvec_get_inst(core, proc->sp); + + if (key_lock_match(next, spin)) { + return true; + } + + if (fwrd) { + proc->sp++; + } else { + proc->sp--; + } + + return false; +} + +static void jump(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + +#if !defined(NDEBUG) + uint8_t next = mvec_get_inst(core, proc->ip + 1); + uint8_t spin = mvec_get_inst(core, proc->sp); + assert(is_key(next)); + assert(is_lock(spin)); + assert(key_lock_match(next, spin)); +#endif + + proc->ip = proc->sp; +} + +static void get_reg_addr_list(struct Core *core, uint64_t pix, uint64_t **rlist, int rcount, bool offset) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + assert(rlist); + assert(rcount); + assert(rcount < 4); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + uint64_t madr = proc->ip + (offset ? 2 : 1); + + for (int i = 0; i < rcount; i++) { + rlist[i] = &proc->r0x; + } + + for (int i = 0; i < rcount; i++) { + uint64_t mnxt = madr + i; + + if (mnxt >= MVEC_SIZE) { + break; + } + + uint8_t mins = mvec_get_inst(core, mnxt); + + if (!is_rmod(mins)) { + break; + } + + switch (mins) { + case nop0: + rlist[i] = &proc->r0x; + break; + case nop1: + rlist[i] = &proc->r1x; + break; + case nop2: + rlist[i] = &proc->r2x; + break; + case nop3: + rlist[i] = &proc->r3x; + break; + } + } +} + +static void address(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + uint64_t *reg; + +#if !defined(NDEBUG) + uint8_t next = mvec_get_inst(core, proc->ip + 1); + uint8_t spin = mvec_get_inst(core, proc->sp); + assert(is_key(next)); + assert(is_lock(spin)); + assert(key_lock_match(next, spin)); +#endif + + get_reg_addr_list(core, pix, ®, 1, true); + *reg = proc->sp; + increment_ip(core, pix); +} + +static void free_memory_block(struct Core *core, uint64_t addr, uint64_t size) { + assert(core); + assert(size); + + for (uint64_t i = 0; i < size; i++) { + mvec_free(core, addr + i); + } +} + +static void free_child_memory_of(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + assert(proc->mb1s); + free_memory_block(core, proc->mb1a, proc->mb1s); + proc->mb1a = 0; + proc->mb1s = 0; +} + +static void alloc(struct Core *core, uint64_t pix, bool fwrd) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + uint64_t *regs[2]; + get_reg_addr_list(core, pix, regs, 2, false); + uint64_t bsize = *regs[0]; + + // Do nothing if block-size is zero + if (!bsize) { + increment_ip(core, pix); + return; + } + + // Do nothing if seek pointer is not adjacent to allocated memory block + if (proc->mb1s) { + uint64_t exp_addr = proc->mb1a; + + if (fwrd) { + exp_addr += proc->mb1s; + } else { + exp_addr--; + } + + if (proc->sp != exp_addr) { + increment_ip(core, pix); + return; + } + } + + // HALT: process SP address is invalid + // Discard allocated memory if any... + if (proc->sp >= MVEC_SIZE) { + if (proc->mb1s) { + free_child_memory_of(core, pix); + } + + core->hlts++; + return; + } + + // Allocation was successful, store block address on register + if (proc->mb1s == bsize) { + increment_ip(core, pix); + *regs[1] = proc->mb1a; + return; + } + + // Seek pointer collided with another allocated block. + // Discard and keep looking... + if (mvec_is_alloc(core, proc->sp)) { + if (proc->mb1s) { + free_child_memory_of(core, pix); + } + + if (fwrd) { + proc->sp++; + } else { + proc->sp--; + } + + return; + } + + // Free (non-allocated) byte found, enlarge child block 1 byte + mvec_alloc(core, proc->sp); + + if (!proc->mb1s || !fwrd) { + proc->mb1a = proc->sp; + } + + proc->mb1s++; + + // Advance seek pointer + if (fwrd) { + proc->sp++; + } else { + proc->sp--; + } +} + +static void if_not_zero(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + uint64_t *reg; + get_reg_addr_list(core, pix, ®, 1, false); + uint64_t jmod = ((proc->ip + 1 < MVEC_SIZE) && is_rmod(mvec_get_inst(core, proc->ip + 1))) ? 1 : 0; + uint64_t rmod = *reg ? 1 : 2; + proc->ip += jmod + rmod; + proc->sp = proc->ip; +} + +static void mem_block_swap(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + + if (proc->mb1s) { + uint64_t tmpa = proc->mb0a; + uint64_t tmps = proc->mb0s; + proc->mb0a = proc->mb1a; + proc->mb0s = proc->mb1s; + proc->mb1a = tmpa; + proc->mb1s = tmps; + + // Memory block swap events mark all addresses within both blocks + for (uint64_t i = 0; i < proc->mb0s; i++) { + core->xeva.data[proc->mb0a + i]++; + } + + for (uint64_t i = 0; i < proc->mb1s; i++) { + core->xeva.data[proc->mb1a + i]++; + } + } + + increment_ip(core, pix); +} + +static void mem_block_clear(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + + if (proc->mb1s) { + free_child_memory_of(core, pix); + } + + increment_ip(core, pix); +} + +static void mem_block_split(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + + if (proc->mb1s) { + struct Proc child = { 0 }; + child.ip = proc->mb1a; + child.sp = proc->mb1a; + child.mb0a = proc->mb1a; + child.mb0s = proc->mb1s; + proc->mb1a = 0; + proc->mb1s = 0; + + // A new organism is born :) + proc_new(core, &child); + } else { + assert(!proc->mb1a); + } + + increment_ip(core, pix); +} + +static void three_regs_op(struct Core *core, uint64_t pix, uint8_t inst) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + uint64_t *regs[3]; + get_reg_addr_list(core, pix, regs, 3, false); + + // Organisms can do arithmetic using any sequence of 3 registers + switch (inst) { + case addn: + *regs[0] = *regs[1] + *regs[2]; + break; + case subn: + *regs[0] = *regs[1] - *regs[2]; + break; + case muln: + *regs[0] = *regs[1] * *regs[2]; + break; + case divn: + if (*regs[2]) { + *regs[0] = *regs[1] / *regs[2]; + } else { + // HALT: division by zero + core->hlts++; + return; + } + + break; + default: + assert(false); + } + + increment_ip(core, pix); +} + +static void one_reg_op(struct Core *core, uint64_t pix, uint8_t inst) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + uint64_t *reg; + get_reg_addr_list(core, pix, ®, 1, false); + + switch (inst) { + case incn: + (*reg)++; + break; + case decn: + (*reg)--; + break; + case notn: + *reg = !(*reg); + break; + case shfl: + *reg <<= 1; + break; + case shfr: + *reg >>= 1; + break; + case zero: + *reg = 0; + break; + case unit: + *reg = 1; + break; + default: + assert(false); + } + + increment_ip(core, pix); +} + +static int get_sp_dir(uint64_t src, uint64_t dst) { + if (src == dst) { + return 0; + } else if (src - dst <= dst - src) { + return -1; + } else { + return 1; + } +} + +static void load_reg(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + uint64_t *regs[2]; + get_reg_addr_list(core, pix, regs, 2, false); + int sp_dir = get_sp_dir(proc->sp, *regs[0]); + + if (*regs[0] >= MVEC_SIZE) { + // Target address is invalid + increment_ip(core, pix); + } else if (sp_dir == 1) { + proc->sp++; + } else if (sp_dir == -1) { + proc->sp--; + } else { + *regs[1] = mvec_get_inst(core, *regs[0]); + increment_ip(core, pix); + } +} + +static bool is_writeable_by(const struct Core *core, uint64_t addr, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + return addr < MVEC_SIZE && (!mvec_is_alloc(core, addr) || mvec_is_proc_owner(core, addr, pix)); +} + +static void write_reg(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + uint64_t *regs[2]; + get_reg_addr_list(core, pix, regs, 2, false); + int sp_dir = get_sp_dir(proc->sp, *regs[0]); + + if (sp_dir == 1) { + proc->sp++; + } else if (sp_dir == -1) { + proc->sp--; + } else { + if (is_writeable_by(core, *regs[0], pix)) { + uint64_t addr = *regs[0]; + uint8_t inst = *regs[1] & ARCH_INST_MASK; + + // Store write event + core->iwrt[inst]++; + core->weva.data[addr]++; + + if (mvec_is_in_mb0_of_proc(core, addr, pix)) { + core->wmb0++; + } else if (mvec_is_in_mb1_of_proc(core, addr, pix)) { + core->wmb1++; + } else { + core->wdea++; + } + + // Write instruction + mvec_set_inst(core, addr, inst); + } + + increment_ip(core, pix); + } +} + +static void two_reg_op(struct Core *core, uint64_t pix, uint8_t inst) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + uint64_t *regs[2]; + get_reg_addr_list(core, pix, regs, 2, false); + + switch (inst) { + case rdup: + *regs[1] = *regs[0]; + break; + case rswp: + { + uint64_t tmp = *regs[0]; + *regs[0] = *regs[1]; + *regs[1] = tmp; + } + + break; + default: + assert(false); + } + + increment_ip(core, pix); +} + +static void push_to_stack(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + uint64_t *reg; + get_reg_addr_list(core, pix, ®, 1, false); + proc->s7 = proc->s6; + proc->s6 = proc->s5; + proc->s5 = proc->s4; + proc->s4 = proc->s3; + proc->s3 = proc->s2; + proc->s2 = proc->s1; + proc->s1 = proc->s0; + proc->s0 = *reg; + increment_ip(core, pix); +} + +static void pop_from_stack(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + assert(proc->ip < MVEC_SIZE); + uint64_t *reg; + get_reg_addr_list(core, pix, ®, 1, false); + *reg = proc->s0; + proc->s0 = proc->s1; + proc->s1 = proc->s2; + proc->s2 = proc->s3; + proc->s3 = proc->s4; + proc->s4 = proc->s5; + proc->s5 = proc->s6; + proc->s6 = proc->s7; + proc->s7 = 0; + increment_ip(core, pix); +} + +// ---------------------------------------------------------------------------- +// [section] callbacks +// ---------------------------------------------------------------------------- +void arch_on_proc_step(struct Core *core, uint64_t pix) { + assert(core); + assert(mvec_proc_is_live(core, pix)); + struct Proc *proc = proc_fetch(core, pix); + + if (proc->ip >= MVEC_SIZE) { + // HALT: process IP address is invalid + core->hlts++; + return; + } + + // Fetch instruction + uint8_t inst = mvec_get_inst(core, proc->ip); + core->iexe[inst]++; + + // Execute instruction + switch (inst) { + case jmpb: + if (seek(core, pix, false)) { + jump(core, pix); + } + + break; + case jmpf: + if (seek(core, pix, true)) { + jump(core, pix); + } + + break; + case adrb: + if (seek(core, pix, false)) { + address(core, pix); + } + + break; + case adrf: + if (seek(core, pix, true)) { + address(core, pix); + } + + break; + case malb: + alloc(core, pix, false); + break; + case malf: + alloc(core, pix, true); + break; + case ifnz: + if_not_zero(core, pix); + break; + case bswp: + mem_block_swap(core, pix); + break; + case bclr: + mem_block_clear(core, pix); + break; + case bspl: + mem_block_split(core, pix); + break; + case addn: + case subn: + case muln: + case divn: + three_regs_op(core, pix, inst); + break; + case incn: + case decn: + case notn: + case shfl: + case shfr: + case zero: + case unit: + one_reg_op(core, pix, inst); + break; + case rloa: + load_reg(core, pix); + break; + case rwrt: + write_reg(core, pix); + break; + case rdup: + case rswp: + two_reg_op(core, pix, inst); + break; + case rpsh: + push_to_stack(core, pix); + break; + case rpop: + pop_from_stack(core, pix); + break; + default: + increment_ip(core, pix); + break; + } +} + +void arch_on_proc_kill(struct Core *core) { + assert(core); + assert(core->pnum > 1); + struct Proc *pfst = proc_fetch(core, core->pfst); + free_memory_block(core, pfst->mb0a, pfst->mb0s); + + if (pfst->mb1s) { + free_memory_block(core, pfst->mb1a, pfst->mb1s); + } + + memcpy(pfst, &g_null_proc, sizeof(struct Proc)); +} + +// ---------------------------------------------------------------------------- +// [section] validation +// ---------------------------------------------------------------------------- +#if !defined(NDEBUG) +void arch_validate_core(struct Core *core) { + assert(core); + + for (uint64_t pix = core->pfst; pix <= core->plst; pix++) { + const struct Proc *proc = proc_get(core, pix); + assert(proc->mb0s); + + if (proc->mb1a) { + assert(proc->mb1s); + } + + for (uint64_t i = 0; i < proc->mb0s; i++) { + uint64_t addr = proc->mb0a + i; + assert(mvec_is_alloc(core, addr)); + assert(mvec_is_proc_owner(core, addr, pix)); + } + + for (uint64_t i = 0; i < proc->mb1s; i++) { + uint64_t addr = proc->mb1a + i; + assert(mvec_is_alloc(core, addr)); + assert(mvec_is_proc_owner(core, addr, pix)); + } + } +} +#endif + +// ---------------------------------------------------------------------------- +// [section] data +// ---------------------------------------------------------------------------- +void arch_push_data_header(void) { + assert(g_sim_db); + log_info("Creating arch table in SQLite database"); + + // Empty blob columns help the data-server stay agnostic of DB schema. + // These represent EVA data that will be appended by data server. + sql_exec( + NULL, NULL, + "create table arch (" +#define ARCH_SPEC_INST(label, symbol, core) \ + #label "_pop_" #core " int not null, " \ + #label "_exe_" #core " int not null, " \ + #label "_wrt_" #core " int not null, " +#define FOR_CORE(i) \ + ARCH_SPEC_INST_SET(i) \ + "wmb0_" #i " int not null, " \ + "wmb1_" #i " int not null, " \ + "wdea_" #i " int not null, " \ + "hlts_" #i " int not null, " \ + "wev" SALIS_EVENT_ARRAY_SIZE_COL_MARKER #i " int not null, wev_" #i " blob, " \ + "xev" SALIS_EVENT_ARRAY_SIZE_COL_MARKER #i " int not null, xev_" #i " blob, " + FOR_CORES +#undef FOR_CORE +#undef ARCH_SPEC_INST + "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 and compress event-arrays 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); + thrd_create(&core->weva.thrd, (thrd_start_t)comp_deflate, &core->weva.params); + thrd_create(&core->xeva.thrd, (thrd_start_t)comp_deflate, &core->xeva.params); + } + + for (int i = 0; i < CORES; i++) { + struct Core *core = &g_cores[i]; + thrd_join(core->ipop_thrd, NULL); + thrd_join(core->weva.thrd, NULL); + thrd_join(core->xeva.thrd, NULL); + core->weva.blob_size = core->weva.params.strm.total_out; + core->xeva.blob_size = core->xeva.params.strm.total_out; + } +} + +void arch_push_data_line(FILE *eva_file) { + assert(g_sim_db); + assert(eva_file); + assert(g_step % DATA_PUSH_INTERVAL == 0); + log_info("Pushing row to arch table in SQLite database"); + sql_exec( + NULL, NULL, + "insert into arch (" +#define ARCH_SPEC_INST(label, symbol, core) \ + #label "_pop_" #core ", " \ + #label "_exe_" #core ", " \ + #label "_wrt_" #core ", " +#define FOR_CORE(i) \ + ARCH_SPEC_INST_SET(i) \ + "wmb0_" #i ", " \ + "wmb1_" #i ", " \ + "wdea_" #i ", " \ + "hlts_" #i ", " \ + "wev" SALIS_EVENT_ARRAY_SIZE_COL_MARKER #i ", " \ + "xev" SALIS_EVENT_ARRAY_SIZE_COL_MARKER #i ", " + FOR_CORES +#undef FOR_CORE +#undef ARCH_SPEC_INST + "step" + ") values (" +#define ARCH_SPEC_INST(label, symbol, core) \ + "%ld, " \ + "%ld, " \ + "%ld, " +#define FOR_CORE(i) \ + ARCH_SPEC_INST_SET(i) \ + "%ld, " \ + "%ld, " \ + "%ld, " \ + "%ld, " \ + "%ld, " \ + "%ld, " + FOR_CORES +#undef FOR_CORE +#undef ARCH_SPEC_INST + "%ld" + ");", +#define ARCH_SPEC_INST(label, symbol, core) \ + g_cores[core].ipop[label], \ + g_cores[core].iexe[label], \ + g_cores[core].iwrt[label], +#define FOR_CORE(i) \ + ARCH_SPEC_INST_SET(i) \ + g_cores[i].wmb0, \ + g_cores[i].wmb1, \ + g_cores[i].wdea, \ + g_cores[i].hlts, \ + g_cores[i].weva.blob_size, \ + g_cores[i].xeva.blob_size, + FOR_CORES +#undef FOR_CORE +#undef ARCH_SPEC_INST + g_step + ); + + for (int i = 0; i < CORES; i++) { + struct Core *core = &g_cores[i]; + fwrite(core->weva.comp, sizeof(Bytef), core->weva.blob_size, eva_file); + fwrite(core->xeva.comp, sizeof(Bytef), core->xeva.blob_size, eva_file); + comp_deflate_end(&core->weva.params); + comp_deflate_end(&core->xeva.params); + } + + // 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); + memset(core->iexe, 0, sizeof(uint64_t) * ARCH_INST_COUNT); + memset(core->iwrt, 0, sizeof(uint64_t) * ARCH_INST_COUNT); + core->wmb0 = 0; + core->wmb1 = 0; + core->wdea = 0; + core->hlts = 0; + memset(core->weva.data, 0, sizeof(uint64_t) * MVEC_SIZE); + memset(core->xeva.data, 0, sizeof(uint64_t) * MVEC_SIZE); + } +} + +// ---------------------------------------------------------------------------- +// [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; + } + + core_event_array_init(&core->weva); + core_event_array_init(&core->xeva); +} +#endif + +#if defined(COMMAND_LOAD) +void arch_core_load(struct Core *core, FILE *f) { + assert(core); + assert(f); + + fread(core->ipop, sizeof(uint64_t), ARCH_INST_COUNT, f); + fread(core->iexe, sizeof(uint64_t), ARCH_INST_COUNT, f); + fread(core->iwrt, sizeof(uint64_t), ARCH_INST_COUNT, f); + fread(&core->wmb0, sizeof(uint64_t), 1, f); + fread(&core->wmb1, sizeof(uint64_t), 1, f); + fread(&core->wdea, sizeof(uint64_t), 1, f); + fread(core->weva.data, sizeof(uint64_t), MVEC_SIZE, f); + fread(core->xeva.data, sizeof(uint64_t), MVEC_SIZE, f); + + core_event_array_init(&core->weva); + core_event_array_init(&core->xeva); +} +#endif + +void arch_core_save(const struct Core *core, FILE *f) { + assert(core); + assert(f); + + fwrite(core->ipop, sizeof(uint64_t), ARCH_INST_COUNT, f); + fwrite(core->iexe, sizeof(uint64_t), ARCH_INST_COUNT, f); + fwrite(core->iwrt, sizeof(uint64_t), ARCH_INST_COUNT, f); + fwrite(&core->wmb0, sizeof(uint64_t), 1, f); + fwrite(&core->wmb1, sizeof(uint64_t), 1, f); + fwrite(&core->wdea, sizeof(uint64_t), 1, f); + fwrite(core->weva.data, sizeof(uint64_t), MVEC_SIZE, f); + fwrite(core->xeva.data, sizeof(uint64_t), MVEC_SIZE, f); +} + +void arch_core_free(struct Core *core) { + assert(core); + (void)core; +} |
