From 2dc9d118efb64de6ea54a5a9eb4474f8e5ef3145 Mon Sep 17 00:00:00 2001 From: Paul Oliver Date: Thu, 29 Feb 2024 01:50:44 +0100 Subject: Initial commit --- src/evolver.c | 125 +++++++ src/instset.c | 56 +++ src/memory.c | 227 ++++++++++++ src/process.c | 1071 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/salis.c | 98 ++++++ 5 files changed, 1577 insertions(+) create mode 100644 src/evolver.c create mode 100644 src/instset.c create mode 100644 src/memory.c create mode 100644 src/process.c create mode 100644 src/salis.c (limited to 'src') diff --git a/src/evolver.c b/src/evolver.c new file mode 100644 index 0000000..ba043a3 --- /dev/null +++ b/src/evolver.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include "types.h" +#include "instset.h" +#include "memory.h" +#include "evolver.h" + +sbool g_isInit; +sword g_lastAddress; +sbyte g_lastInst; +sword g_state[4]; + +void +se_init(void) +{ + assert(!g_isInit); + srand((unsigned)time(NULL)); + g_state[0] = rand(); + g_state[1] = rand(); + g_state[2] = rand(); + g_state[3] = rand(); + g_isInit = STRUE; +} + +void +se_quit(void) +{ + assert(g_isInit); + g_isInit = SFALSE; + g_lastAddress = 0; + g_lastInst = 0; + g_state[0] = 0; + g_state[1] = 0; + g_state[2] = 0; + g_state[3] = 0; +} + +void +se_load(FILE *file) +{ + assert(!g_isInit); + assert(file); + fread(&g_isInit, sizeof(sbool), 1, file); + fread(&g_lastAddress, sizeof(sword), 1, file); + fread(&g_lastInst, sizeof(sbyte), 1, file); + fread(g_state, sizeof(sword), 4, file); +} + +void +se_save(FILE *file) +{ + assert(g_isInit); + assert(file); + fwrite(&g_isInit, sizeof(sbool), 1, file); + fwrite(&g_lastAddress, sizeof(sword), 1, file); + fwrite(&g_lastInst, sizeof(sbyte), 1, file); + fwrite(g_state, sizeof(sword), 4, file); +} + +sbool +se_isInit(void) +{ + return g_isInit; +} + +sword +se_getLastAddress(void) +{ + return g_lastAddress; +} + +sbyte +se_getLastInst(void) +{ + assert(si_isInst(g_lastInst)); + return g_lastInst; +} + +sword +se_getState(sword eidx) +{ + assert(eidx < 4); + return g_state[eidx]; +} + +void +se_setState(sword eidx, sword state) +{ + assert(g_isInit); + assert(eidx < 4); + g_state[eidx] = state; +} + +static sword +generateRandomNumber(void) +{ + sword s; + sword t; + assert(g_isInit); + t = g_state[3]; + t ^= t << 11; + t ^= t >> 8; + g_state[3] = g_state[2]; + g_state[2] = g_state[1]; + g_state[1] = g_state[0]; + s = g_state[0]; + t ^= s; + t ^= s >> 19; + g_state[0] = t; + return t; +} + +void +se_cycle(void) +{ + assert(g_isInit); + g_lastAddress = generateRandomNumber(); + g_lastInst = (sbyte)(generateRandomNumber() % SINST_COUNT); + + if (sm_isValidAt(g_lastAddress)) { + sm_setInstAt(g_lastAddress, (sbyte)g_lastInst); + } +} diff --git a/src/instset.c b/src/instset.c new file mode 100644 index 0000000..1333ffb --- /dev/null +++ b/src/instset.c @@ -0,0 +1,56 @@ +#include +#include "types.h" +#include "instset.h" + +sbool +si_isInst(sbyte inst) +{ + return inst < SINST_COUNT; +} + +static sbool +isBetween(sbyte inst, sbyte lo, sbyte hi) +{ + assert(si_isInst(inst)); + assert(lo < SINST_COUNT); + assert(hi < SINST_COUNT); + + if (inst < lo) { + return SFALSE; + } + + if (inst > hi) { + return SFALSE; + } + + return STRUE; +} + +sbool +si_isMod(sbyte inst) +{ + assert(si_isInst(inst)); + return isBetween(inst, SNOP0, SNOP3); +} + +sbool +si_isKey(sbyte inst) +{ + assert(si_isInst(inst)); + return isBetween(inst, SKEYA, SKEYP); +} + +sbool +si_isLock(sbyte inst) +{ + assert(si_isInst(inst)); + return isBetween(inst, SLOKA, SLOKP); +} + +sbool +si_keyLockMatch(sbyte key, sbyte lock) +{ + assert(si_isKey(key)); + assert(si_isInst(lock)); + return (key - SKEYA) == (lock - SLOKA); +} diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 0000000..4befd4f --- /dev/null +++ b/src/memory.c @@ -0,0 +1,227 @@ +#include +#include +#include +#include "types.h" +#include "instset.h" +#include "memory.h" + +#define MEM_BLOCK_START_FLAG (0x80) +#define ALLOCATED_FLAG (0x40) +#define INSTRUCTION_MASK (0x3f) + +static sbool g_isInit; +static sword g_order; +static sword g_size; +static sword g_memBlockCount; +static sword g_allocated; +static sword g_cap; +static sbyte *g_data; + +void +sm_init(sword order) +{ + assert(!g_isInit); + assert(INSTRUCTION_MASK == SINST_COUNT - 1); + g_isInit = STRUE; + g_order = order; + g_size = 1 << g_order; + g_cap = g_size / 2; + g_data = calloc(g_size, sizeof(sbyte)); + assert(g_data); +} + +void +sm_quit(void) +{ + assert(g_isInit); + free(g_data); + g_isInit = SFALSE; + g_order = 0; + g_size = 0; + g_memBlockCount = 0; + g_allocated = 0; + g_cap = 0; + g_data = NULL; +} + +void +sm_load(FILE *file) +{ + assert(!g_isInit); + assert(file); + fread(&g_isInit, sizeof(sbool), 1, file); + fread(&g_order, sizeof(sword), 1, file); + fread(&g_size, sizeof(sword), 1, file); + fread(&g_memBlockCount, sizeof(sword), 1, file); + fread(&g_allocated, sizeof(sword), 1, file); + fread(&g_cap, sizeof(sword), 1, file); + g_data = calloc(g_size, sizeof(sbyte)); + assert(g_data); + fread(g_data, sizeof(sbyte), g_size, file); +} + +void +sm_save(FILE *file) +{ + assert(g_isInit); + assert(file); + fwrite(&g_isInit, sizeof(sbool), 1, file); + fwrite(&g_order, sizeof(sword), 1, file); + fwrite(&g_size, sizeof(sword), 1, file); + fwrite(&g_memBlockCount, sizeof(sword), 1, file); + fwrite(&g_allocated, sizeof(sword), 1, file); + fwrite(&g_cap, sizeof(sword), 1, file); + fwrite(g_data, sizeof(sbyte), g_size, file); +} + +sbool +sm_isInit(void) +{ + return g_isInit; +} + +sword +sm_getOrder(void) +{ + return g_order; +} + +sword +sm_getSize(void) +{ + return g_size; +} + +sword +sm_getMemBlockCount(void) +{ + return g_memBlockCount; +} + +sword +sm_getAllocated(void) +{ + return g_allocated; +} + +sword +sm_getCap(void) +{ + return g_cap; +} + +sbool +sm_isOverCap(void) +{ + assert(g_isInit); + return g_allocated > g_cap; +} + +sbool +sm_isValidAt(sword addr) +{ + assert(g_isInit); + return addr < g_size; +} + +sbool +sm_isMemBlockStartAt(sword addr) +{ + assert(g_isInit); + assert(sm_isValidAt(addr)); + return !!(g_data[addr] & MEM_BLOCK_START_FLAG); +} + +sbool +sm_isAllocatedAt(sword addr) +{ + assert(g_isInit); + assert(sm_isValidAt(addr)); + return !!(g_data[addr] & ALLOCATED_FLAG); +} + +void +sm_setMemBlockStartAt(sword addr) +{ + assert(g_isInit); + assert(sm_isValidAt(addr)); + assert(!sm_isMemBlockStartAt(addr)); + g_data[addr] ^= MEM_BLOCK_START_FLAG; + g_memBlockCount++; + assert(sm_isMemBlockStartAt(addr)); + assert(g_memBlockCount); + assert(g_memBlockCount <= g_size); +} + +void +sm_unsetMemBlockStartAt(sword addr) +{ + assert(g_isInit); + assert(g_memBlockCount); + assert(sm_isValidAt(addr)); + assert(sm_isMemBlockStartAt(addr)); + g_data[addr] ^= MEM_BLOCK_START_FLAG; + g_memBlockCount--; + assert(!sm_isMemBlockStartAt(addr)); + assert(g_memBlockCount <= g_size); +} + +void +sm_allocateAt(sword addr) +{ + assert(g_isInit); + assert(sm_isValidAt(addr)); + assert(!sm_isAllocatedAt(addr)); + g_data[addr] ^= ALLOCATED_FLAG; + g_allocated++; + assert(sm_isAllocatedAt(addr)); + assert(g_allocated); + assert(g_allocated <= g_size); +} + +void +sm_freeAt(sword addr) +{ + assert(g_isInit); + assert(g_allocated); + assert(sm_isValidAt(addr)); + assert(sm_isAllocatedAt(addr)); + g_data[addr] ^= ALLOCATED_FLAG; + g_allocated--; + assert(!sm_isAllocatedAt(addr)); + assert(g_allocated <= g_size); +} + +sbyte +sm_getInstAt(sword addr) +{ + assert(g_isInit); + assert(sm_isValidAt(addr)); + return g_data[addr] & INSTRUCTION_MASK; +} + +void +sm_setInstAt(sword addr, sbyte inst) +{ + assert(g_isInit); + assert(sm_isValidAt(addr)); + assert(si_isInst(inst)); + g_data[addr] &= (MEM_BLOCK_START_FLAG | ALLOCATED_FLAG); + g_data[addr] |= inst; +} + +sbyte +sm_getByteAt(sword addr) +{ + assert(g_isInit); + assert(sm_isValidAt(addr)); + return g_data[addr]; +} + +void +sm_setByteAt(sword addr, sbyte byte) +{ + assert(g_isInit); + assert(sm_isValidAt(addr)); + g_data[addr] = byte; +} diff --git a/src/process.c b/src/process.c new file mode 100644 index 0000000..e3d3c18 --- /dev/null +++ b/src/process.c @@ -0,0 +1,1071 @@ +#include +#include +#include +#include +#include "types.h" +#include "instset.h" +#include "memory.h" +#include "process.h" + +static sbool g_isInit; +static sword g_count; +static sword g_cap; +static sword g_first; +static sword g_last; +static SProc *g_procs; + +void +sp_init(void) +{ + assert(!g_isInit); + g_isInit = STRUE; + g_cap = 1; + g_first = SNULL; + g_last = SNULL; + g_procs = calloc(g_cap, sizeof(SProc)); + assert(g_procs); +} + +void +sp_quit(void) +{ + assert(g_isInit); + free(g_procs); + g_isInit = SFALSE; + g_count = 0; + g_cap = 0; + g_first = 0; + g_last = 0; + g_procs = NULL; +} + +void +sp_load(FILE *file) +{ + assert(!g_isInit); + assert(file); + fread(&g_isInit, sizeof(sbool), 1, file); + fread(&g_count, sizeof(sword), 1, file); + fread(&g_cap, sizeof(sword), 1, file); + fread(&g_first, sizeof(sword), 1, file); + fread(&g_last, sizeof(sword), 1, file); + g_procs = calloc(g_cap, sizeof(SProc)); + assert(g_procs); + fread(g_procs, sizeof(SProc), g_cap, file); +} + +void +sp_save(FILE *file) +{ +assert(g_isInit); +assert(file); +fwrite(&g_isInit, sizeof(sbool), 1, file); +fwrite(&g_count, sizeof(sword), 1, file); +fwrite(&g_cap, sizeof(sword), 1, file); +fwrite(&g_first, sizeof(sword), 1, file); +fwrite(&g_last, sizeof(sword), 1, file); +fwrite(g_procs, sizeof(SProc), g_cap, file); +} + +sbool +sp_isInit(void) +{ + return g_isInit; +} + +sword +sp_getCount(void) +{ + return g_count; +} + +sword +sp_getCap(void) +{ + return g_cap; +} + +sword +sp_getFirst(void) +{ + return g_first; +} + +sword +sp_getLast(void) +{ + return g_last; +} + +sbool +sp_isFree(sword pidx) +{ + sbool isFree; + assert(g_isInit); + assert(pidx < g_cap); + isFree = !(g_procs[pidx].mb1s); +#ifndef NDEBUG + + if (isFree) { + assert(!g_procs[pidx].mb1a); + assert(!g_procs[pidx].mb2a); + assert(!g_procs[pidx].mb2s); + } + +#endif + return isFree; +} + +SProc +sp_getProc(sword pidx) +{ + assert(g_isInit); + assert(pidx < g_cap); + return g_procs[pidx]; +} + +void +sp_setProc(sword pidx, SProc proc) +{ + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + g_procs[pidx] = proc; +} + +static void +reallocQueue(sword queueLock) +{ + sword newCap; + SProc *newQueue; + sword fidx; + sword bidx; + assert(g_isInit); + assert(g_count == g_cap); + assert(queueLock < g_cap); + newCap = g_cap * 2; + newQueue = calloc(newCap, sizeof(SProc)); + assert(newQueue); + fidx = queueLock; + bidx = (queueLock - 1) % newCap; + + /* copy all forward from lock */ + while (STRUE) { + sword oldIdx = fidx % g_cap; + memcpy(&newQueue[fidx], &g_procs[oldIdx], sizeof(SProc)); + + if (oldIdx == g_last) { + g_last = fidx; + break; + } else { + fidx++; + } + } + + if (queueLock != g_first) { + /* copy all backward from lock */ + while (STRUE) { + sword oldIdx = bidx % g_cap; + memcpy(&newQueue[bidx], &g_procs[oldIdx], sizeof(SProc)); + + if (oldIdx == g_first) { + g_first = bidx; + break; + } else { + bidx--; + bidx %= newCap; + } + } + } + + free(g_procs); + g_cap = newCap; + g_procs = newQueue; +} + +static sword +getNewProc(sword queueLock) +{ + assert(g_isInit); + + if (g_count == g_cap) { + reallocQueue(queueLock); + } + + g_count++; + + if (g_count == 1) { + g_first = 0; + g_last = 0; + return 0; + } else { + g_last++; + g_last %= g_cap; + return g_last; + } +} + +static void +create(sword addr, sword size, sword queueLock, sbool allocate) +{ + sword pidx; + assert(g_isInit); + assert(sm_isValidAt(addr)); + assert(sm_isValidAt(addr + size - 1)); + + if (allocate) { + sword offset; + + for (offset = 0; offset < size; offset++) { + sword naddr = addr + offset; + assert(!sm_isAllocatedAt(naddr)); + assert(!sm_isMemBlockStartAt(naddr)); + sm_allocateAt(naddr); + } + + sm_setMemBlockStartAt(addr); + } + + pidx = getNewProc(queueLock); + g_procs[pidx].mb1a = addr; + g_procs[pidx].mb1s = size; + g_procs[pidx].ip = addr; + g_procs[pidx].sp = addr; +} + +void +sp_create(sword addr, sword size) +{ + assert(g_isInit); + assert(sm_isValidAt(addr)); + assert(sm_isValidAt(addr + size - 1)); + create(addr, size, 0, STRUE); +} + +static void +freeMemBlock(sword addr, sword size) +{ + sword offset; + assert(sm_isValidAt(addr)); + assert(sm_isValidAt(addr + size - 1)); + assert(size); + assert(sm_isMemBlockStartAt(addr)); + sm_unsetMemBlockStartAt(addr); + + for (offset = 0; offset < size; offset++) { + sword oaddr = addr + offset; + assert(sm_isValidAt(oaddr)); + assert(sm_isAllocatedAt(oaddr)); + assert(!sm_isMemBlockStartAt(oaddr)); + sm_freeAt(oaddr); + } +} + +static void +freeMemOwnedBy(sword pidx) +{ + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + freeMemBlock(g_procs[pidx].mb1a, g_procs[pidx].mb1s); + + if (g_procs[pidx].mb2s) { + assert(g_procs[pidx].mb1a != g_procs[pidx].mb2a); + freeMemBlock(g_procs[pidx].mb2a, g_procs[pidx].mb2s); + } +} + +void +sp_kill(void) +{ + assert(g_isInit); + assert(g_count); + assert(g_first != SNULL); + assert(g_last != SNULL); + assert(!sp_isFree(g_first)); + freeMemOwnedBy(g_first); + memset(&g_procs[g_first], 0, sizeof(SProc)); + g_count--; + + if (g_first == g_last) { + g_first = SNULL; + g_last = SNULL; + return; + } + + g_first++; + g_first %= g_cap; +} + +static void +incrementIP(sword pidx) +{ + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + g_procs[pidx].ip++; + g_procs[pidx].sp = g_procs[pidx].ip; +} + +static sbool +seek(sword pidx, sbool forward) +{ + sword nextAddr; + sbyte nextInst; + sbyte spInst; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + nextAddr = g_procs[pidx].ip + 1; + + if (!sm_isValidAt(nextAddr)) { + incrementIP(pidx); + return SFALSE; + } + + nextInst = sm_getInstAt(nextAddr); + + if (!si_isKey(nextInst)) { + incrementIP(pidx); + return SFALSE; + } + + spInst = sm_getInstAt(g_procs[pidx].sp); + + if (si_keyLockMatch(nextInst, spInst)) { + return STRUE; + } + + if (forward) { + g_procs[pidx].sp++; + } else { + g_procs[pidx].sp--; + } + + return SFALSE; +} + +static void +jump(sword pidx) +{ +#ifndef NDEBUG + sbyte nextInst; + sbyte spInst; +#endif + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); +#ifndef NDEBUG + nextInst = sm_getInstAt(g_procs[pidx].ip + 1); + spInst = sm_getInstAt(g_procs[pidx].sp); + assert(si_isKey(nextInst)); + assert(si_isLock(spInst)); + assert(si_keyLockMatch(nextInst, spInst)); +#endif + g_procs[pidx].ip = g_procs[pidx].sp; +} + +static sword * +getRegAddr(sword pidx, sword modAddr) +{ + sbyte modInst; + sbyte modOffset; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + assert(sm_isValidAt(modAddr)); + modInst = sm_getInstAt(modAddr); + assert(si_isMod(modInst)); + modOffset = modInst - SNOP0; + assert(modOffset < SPROC_REG_COUNT); + return &(g_procs[pidx].regs[modOffset]); +} + +static void +getRegAddrList(sword pidx, sword **regList, sword regCount, sbool offset) +{ + sword modAddr; + sbyte ridx; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + assert(regList); + assert(regCount); + assert(regCount < 4); + + if (offset) { + modAddr = g_procs[pidx].ip + 2; + } else { + modAddr = g_procs[pidx].ip + 1; + } + + for (ridx = 0; ridx < regCount; ridx++) { + regList[ridx] = &(g_procs[pidx].regs[0]); + } + + for (ridx = 0; ridx < regCount; ridx++) { + sword modNext = modAddr + ridx; + + if (!sm_isValidAt(modNext)) { + break; + } else { + sword modInst = sm_getInstAt(modNext); + + if (!si_isMod(modInst)) { + break; + } else { + regList[ridx] = getRegAddr(pidx, modNext); + } + } + } +} + +static void +addr(sword pidx) +{ +#ifndef NDEBUG + sbyte nextInst; + sbyte spInst; +#endif + sword *reg; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); +#ifndef NDEBUG + nextInst = sm_getInstAt(g_procs[pidx].ip + 1); + spInst = sm_getInstAt(g_procs[pidx].sp); + assert(si_isKey(nextInst)); + assert(si_isLock(spInst)); + assert(si_keyLockMatch(nextInst, spInst)); +#endif + getRegAddrList(pidx, ®, 1, STRUE); + *reg = g_procs[pidx].sp; + incrementIP(pidx); +} + +static void +ifnz(sword pidx) +{ + sword *reg; + sword jumpMod; + sword nextAddr; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + getRegAddrList(pidx, ®, 1, SFALSE); + nextAddr = g_procs[pidx].ip + 1; + + if (sm_isValidAt(nextAddr)) { + sbyte nextInst = sm_getInstAt(nextAddr); + sbool nextInstIsMod = si_isMod(nextInst); + + if (nextInstIsMod) { + jumpMod = 1; + } else { + jumpMod = 0; + } + } else { + jumpMod = 0; + } + + if (*reg) { + /* execute next instruction */ + g_procs[pidx].ip += (jumpMod + 1); + } else { + /* skip next instruction */ + g_procs[pidx].ip += (jumpMod + 2); + } + + g_procs[pidx].sp = g_procs[pidx].ip; +} + +static void +freeMemBlock2Of(sword pidx) +{ + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + assert(g_procs[pidx].mb2s); + freeMemBlock(g_procs[pidx].mb2a, g_procs[pidx].mb2s); + g_procs[pidx].mb2a = 0; + g_procs[pidx].mb2s = 0; +} + +static void +alloc(sword pidx, sbool forward) +{ + sword *regs[2]; + sword blockSize; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + getRegAddrList(pidx, regs, 2, SFALSE); + blockSize = *regs[0]; + + /* check for possible errors */ + /* ignore if requested block size is zero */ + if (!blockSize) { + incrementIP(pidx); + return; + } + + /* ignore if sp is not adjacent to already existing memory block */ + if (g_procs[pidx].mb2s) { + sword correctAddr = g_procs[pidx].mb2a; + + if (forward) { + correctAddr += g_procs[pidx].mb2s; + } else { + correctAddr--; + } + + if (g_procs[pidx].sp != correctAddr) { + incrementIP(pidx); + return; + } + } + + /* on successful allocation */ + /* increment ip and save new block's address on register */ + if (g_procs[pidx].mb2s == blockSize) { + incrementIP(pidx); + *regs[1] = g_procs[pidx].mb2a; + return; + } + + /* handle block enlargement */ + /* handle sp collision with allocated space */ + if (sm_isAllocatedAt(g_procs[pidx].sp)) { + if (g_procs[pidx].mb2s) { + freeMemBlock2Of(pidx); + } + + if (forward) { + g_procs[pidx].sp++; + } else { + g_procs[pidx].sp--; + } + + return; + } + + /* enlarge block when no collision occurs */ + sm_allocateAt(g_procs[pidx].sp); + + /* correct memory block start flag address */ + if (!g_procs[pidx].mb2s) { + g_procs[pidx].mb2a = g_procs[pidx].sp; + sm_setMemBlockStartAt(g_procs[pidx].sp); + } else { + if (!forward) { + sm_unsetMemBlockStartAt(g_procs[pidx].mb2a); + g_procs[pidx].mb2a = g_procs[pidx].sp; + sm_setMemBlockStartAt(g_procs[pidx].mb2a); + } + } + + g_procs[pidx].mb2s++; + + /* move sp to next location */ + if (forward) { + g_procs[pidx].sp++; + } else { + g_procs[pidx].sp--; + } +} + +static void +bswap(sword pidx) +{ + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + + if (g_procs[pidx].mb2s) { + sword addrTmp = g_procs[pidx].mb1a; + sword sizeTmp = g_procs[pidx].mb1s; + g_procs[pidx].mb1a = g_procs[pidx].mb2a; + g_procs[pidx].mb1s = g_procs[pidx].mb2s; + g_procs[pidx].mb2a = addrTmp; + g_procs[pidx].mb2s = sizeTmp; + } + + incrementIP(pidx); +} + +static void +bclear(sword pidx) +{ + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + + if (g_procs[pidx].mb2s) { + freeMemBlock2Of(pidx); + } + + incrementIP(pidx); +} + +static void +split(sword pidx) +{ + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + + if (g_procs[pidx].mb2s) { + create(g_procs[pidx].mb2a, g_procs[pidx].mb2s, pidx, SFALSE); + g_procs[pidx].mb2a = 0; + g_procs[pidx].mb2s = 0; + } + + incrementIP(pidx); +} + +static void +r3op(sword pidx, sbyte inst) +{ + sword *regs[3]; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + getRegAddrList(pidx, regs, 3, SFALSE); + + /* ignore when dividing by zero */ + if ((inst == SDIVN) && (*regs[2] == 0)) { + incrementIP(pidx); + return; + } + + switch (inst) { + case SADDN: + *regs[0] = *regs[1] + *regs[2]; + break; + + case SSUBN: + *regs[0] = *regs[1] - *regs[2]; + break; + + case SMULN: + *regs[0] = *regs[1] * *regs[2]; + break; + + case SDIVN: + assert(*regs[2]); + *regs[0] = *regs[1] / *regs[2]; + break; + + default: + assert(0); + } + + incrementIP(pidx); +} + +static void +r1op(sword pidx, sbyte inst) +{ + sword *reg; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + getRegAddrList(pidx, ®, 1, SFALSE); + + switch (inst) { + case SINCN: + (*reg)++; + break; + + case SDECN: + (*reg)--; + break; + + case SNOTN: + *reg = !(*reg); + break; + + case SSHFL: + *reg <<= 1; + break; + + case SSHFR: + *reg >>= 1; + break; + + case SZERO: + *reg = 0; + break; + + case SUNIT: + *reg = 1; + break; + + default: + assert(0); + } + + incrementIP(pidx); +} + +static void +push(sword pidx) +{ + sword *reg; + sword sidx; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + getRegAddrList(pidx, ®, 1, SFALSE); + + for (sidx = SPROC_STACK_SIZE - 1; sidx; sidx--) { + g_procs[pidx].stack[sidx] = g_procs[pidx].stack[sidx - 1]; + } + + g_procs[pidx].stack[0] = *reg; + incrementIP(pidx); +} + +static void +pop(sword pidx) +{ + sword *reg; + sword sidx; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + getRegAddrList(pidx, ®, 1, SFALSE); + *reg = g_procs[pidx].stack[0]; + + for (sidx = 1; sidx < SPROC_STACK_SIZE; sidx++) { + g_procs[pidx].stack[sidx - 1] = g_procs[pidx].stack[sidx]; + } + + g_procs[pidx].stack[SPROC_STACK_SIZE - 1] = 0; + incrementIP(pidx); +} + +static void +load(sword pidx) +{ + sword *regs[2]; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + getRegAddrList(pidx, regs, 2, SFALSE); + + if (!sm_isValidAt(*regs[0])) { + incrementIP(pidx); + return; + } + + if (g_procs[pidx].sp < *regs[0]) { + g_procs[pidx].sp++; + } else if (g_procs[pidx].sp > *regs[0]) { + g_procs[pidx].sp--; + } else { + *regs[1] = sm_getInstAt(*regs[0]); + incrementIP(pidx); + } +} + +static sbool +isWriteableBy(sword pidx, sword addr) +{ + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + + if (!sm_isValidAt(addr)) { + return SFALSE; + } + + if (!sm_isAllocatedAt(addr)) { + return STRUE; + } else { + sword lo1 = g_procs[pidx].mb1a; + sword lo2 = g_procs[pidx].mb2a; + sword hi1 = lo1 + g_procs[pidx].mb1s; + sword hi2 = lo2 + g_procs[pidx].mb2s; + return (addr >= lo1 && addr < hi1) || (addr >= lo2 && addr < hi2); + } +} + +static void +write(sword pidx) +{ + sword *regs[2]; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + getRegAddrList(pidx, regs, 2, SFALSE); + + if (!sm_isValidAt(*regs[0])) { + incrementIP(pidx); + return; + } + + if (!si_isInst(*regs[1])) { + incrementIP(pidx); + return; + } + + if (g_procs[pidx].sp < *regs[0]) { + g_procs[pidx].sp++; + } else if (g_procs[pidx].sp > *regs[0]) { + g_procs[pidx].sp--; + } else { + if (isWriteableBy(pidx, *regs[0])) { + sm_setInstAt(*regs[0], *regs[1]); + } + + incrementIP(pidx); + } +} + +static void +r2op(sword pidx, sbyte inst) +{ + sword *regs[2]; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + getRegAddrList(pidx, regs, 2, SFALSE); + + switch (inst) { + case SDUPL: + *regs[1] = *regs[0]; + break; + + case SSWAP: { + sword temp = *regs[0]; + *regs[0] = *regs[1]; + *regs[1] = temp; + break; + } + + default: + assert(0); + } + + incrementIP(pidx); +} + +static void +cycle(sword pidx) +{ + sbyte inst; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + + if (!sm_isValidAt(g_procs[pidx].ip) || !sm_isValidAt(g_procs[pidx].sp)) { + incrementIP(pidx); + return; + } + + inst = sm_getInstAt(g_procs[pidx].ip); + + switch (inst) { + case SJMPB: + if (seek(pidx, SFALSE)) { + jump(pidx); + } + + break; + + case SJMPF: + if (seek(pidx, STRUE)) { + jump(pidx); + } + + break; + + case SADRB: + if (seek(pidx, SFALSE)) { + addr(pidx); + } + + break; + + case SADRF: + if (seek(pidx, STRUE)) { + addr(pidx); + } + + break; + + case SIFNZ: + ifnz(pidx); + break; + + case SALLB: + alloc(pidx, SFALSE); + break; + + case SALLF: + alloc(pidx, STRUE); + break; + + case SBSWP: + bswap(pidx); + break; + + case SBCLR: + bclear(pidx); + break; + + case SSPLT: + split(pidx); + break; + + case SADDN: + case SSUBN: + case SMULN: + case SDIVN: + r3op(pidx, inst); + break; + + case SINCN: + case SDECN: + case SNOTN: + case SSHFL: + case SSHFR: + case SZERO: + case SUNIT: + r1op(pidx, inst); + break; + + case SPSHN: + push(pidx); + break; + + case SPOPN: + pop(pidx); + break; + + case SLOAD: + load(pidx); + break; + + case SWRTE: + write(pidx); + break; + + case SDUPL: + case SSWAP: + r2op(pidx, inst); + break; + + default: + incrementIP(pidx); + } +} + +#ifndef NDEBUG + +static void +isFreeValid(sword pidx) +{ + sword *element; + sword eidx; + assert(g_isInit); + assert(pidx < g_cap); + assert(sp_isFree(pidx)); + element = (sword *)&g_procs[pidx]; + + for (eidx = 0; eidx < SPROC_ELEM_COUNT; eidx++) { + assert(!(*element)); + element++; + } +} + +static void +isUsedValid(sword pidx) +{ + sword offset; + assert(g_isInit); + assert(pidx < g_cap); + assert(!sp_isFree(pidx)); + assert(sm_isMemBlockStartAt(g_procs[pidx].mb1a)); + + if (g_procs[pidx].mb2s) { + assert(sm_isMemBlockStartAt(g_procs[pidx].mb2a)); + } + + for (offset = 0; offset < g_procs[pidx].mb1s; offset++) { + sword addr = g_procs[pidx].mb1a + offset; + assert(sm_isValidAt(addr)); + assert(sm_isAllocatedAt(addr)); + } + + for (offset = 0; offset < g_procs[pidx].mb2s; offset++) { + sword addr = g_procs[pidx].mb2a + offset; + assert(sm_isValidAt(addr)); + assert(sm_isAllocatedAt(addr)); + } +} + +static void +isValid(sword pidx) +{ + assert(g_isInit); + assert(pidx < g_cap); + + if (sp_isFree(pidx)) { + isFreeValid(pidx); + } else { + isUsedValid(pidx); + } +} + +#endif + +void +sp_cycle(void) +{ +#ifndef NDEBUG + sword pidx; +#endif + assert(g_isInit); +#ifndef NDEBUG + + /* check for validity before cycle */ + for (pidx = 0; pidx < sp_getCap(); pidx++) { + isValid(pidx); + } + +#endif + + if (sp_getCount()) { + sword qidx = sp_getLast(); + + /* cycle all procs */ + while (STRUE) { + cycle(qidx); + + if (qidx == sp_getFirst()) { + break; + } else { + qidx--; + qidx %= sp_getCap(); + } + } + + /* kill procs if memory is over capacity */ + while (sm_isOverCap()) { + sp_kill(); + } + } else { + sp_create(0, 1); + } + +#ifndef NDEBUG + + /* check for validity after cycle */ + for (pidx = 0; pidx < sp_getCap(); pidx++) { + isValid(pidx); + } + +#endif +} diff --git a/src/salis.c b/src/salis.c new file mode 100644 index 0000000..c57c60e --- /dev/null +++ b/src/salis.c @@ -0,0 +1,98 @@ +#include +#include +#include "salis.h" + +static sbool g_isInit; +static sword g_cycle; +static sword g_epoch; + +void +s_init(sword order) +{ + assert(!g_isInit); + sm_init(order); + se_init(); + sp_init(); + g_isInit = STRUE; +} + +void +s_quit(void) +{ + assert(g_isInit); + sp_quit(); + se_quit(); + sm_quit(); + g_isInit = SFALSE; + g_cycle = 0; + g_epoch = 0; +} + +void +s_load(const char *fileName) +{ + FILE *file; + assert(!g_isInit); + assert(fileName); + file = fopen(fileName, "rb"); + assert(file); + fread(&g_isInit, sizeof(sbool), 1, file); + fread(&g_cycle, sizeof(sword), 1, file); + fread(&g_epoch, sizeof(sword), 1, file); + sm_load(file); + se_load(file); + sp_load(file); + fclose(file); +} + +void +s_save(const char *fileName) +{ + FILE *file; + assert(g_isInit); + assert(fileName); + file = fopen(fileName, "wb"); + assert(file); + fwrite(&g_isInit, sizeof(sbool), 1, file); + fwrite(&g_cycle, sizeof(sword), 1, file); + fwrite(&g_epoch, sizeof(sword), 1, file); + sm_save(file); + se_save(file); + sp_save(file); + fclose(file); +} + +sbool +s_isInit(void) +{ + return g_isInit; +} + +sword +s_getCycle(void) +{ + return g_cycle; +} + +sword +s_getEpoch(void) +{ + return g_epoch; +} + +void +s_cycle(void) +{ + assert(g_isInit); + assert(sm_isInit()); + assert(sp_isInit()); + assert(se_isInit()); + g_cycle++; + + if (!g_cycle) { + g_epoch++; + } + + se_cycle(); + sp_cycle(); +} -- cgit v1.2.1