diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/evolver.c | 125 | ||||
| -rw-r--r-- | src/instset.c | 56 | ||||
| -rw-r--r-- | src/memory.c | 227 | ||||
| -rw-r--r-- | src/process.c | 1071 | ||||
| -rw-r--r-- | src/salis.c | 98 | 
5 files changed, 1577 insertions, 0 deletions
| 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 <assert.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <time.h>
 +#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 <assert.h>
 +#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 <assert.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +#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 <assert.h>
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#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 <assert.h>
 +#include <stdlib.h>
 +#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();
 +}
 | 
