├── tsalis ├── build │ └── .keep ├── include │ ├── handler.h │ ├── tsalis.h │ └── printer.h ├── Makefile ├── src │ ├── tsalis.c │ ├── handler.c │ └── printer.c └── README.md ├── sim.png ├── bin └── genomes │ ├── 55.anc │ └── 64.anc ├── .gitignore ├── include ├── evolver.h ├── salis.h ├── types.h ├── process.h ├── memory.h └── instset.h ├── TODO.md ├── Makefile ├── src ├── instset.c ├── salis.c ├── evolver.c ├── memory.c └── process.c ├── plugins ├── grapher.py └── imager.py └── README.md /tsalis/build/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PaulTOliver/salis-v1/HEAD/sim.png -------------------------------------------------------------------------------- /bin/genomes/55.anc: -------------------------------------------------------------------------------- 1 | A[a]a1^1-11B!3#1#3?3)c{12)dC}12D.03:23^^2v1?1(d$~3~1(bA 2 | -------------------------------------------------------------------------------- /bin/genomes/64.anc: -------------------------------------------------------------------------------- 1 | A[a1u<<<<< 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | void s_init (sword order); 16 | void s_quit (void); 17 | void s_load (const char *fileName); 18 | void s_save (const char *fileName); 19 | 20 | sbool s_isInit (void); 21 | sword s_getCycle (void); 22 | sword s_getEpoch (void); 23 | 24 | void s_cycle (void); 25 | 26 | #ifdef __cplusplus 27 | } 28 | #endif 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | ## SALIS UPDATES 2 | - Add eat-string (EATF/EATB) instruction 3 | - Reward organisms for "eating" information 4 | 5 | ## TSALIS UPDATES 6 | - Create process cursor selector (on WORLD and PROCESS view) 7 | - Better console: 8 | - Allow longer input 9 | - Allow hex input 10 | - Line editing 11 | - Command history 12 | - Console responses 13 | - Make save files portable 14 | 15 | ## PYTHON PLUGINS/APPS 16 | - PySalis simulation runner script 17 | - Create REPORT app that reads many savefiles and generates data files from: 18 | - Organism sizes 19 | - Instruction count 20 | - Species dictionary 21 | - Dictionary graph 22 | - 2D evolution grapher 23 | -------------------------------------------------------------------------------- /include/types.h: -------------------------------------------------------------------------------- 1 | #ifndef SALIS_TYPES_H 2 | #define SALIS_TYPES_H 3 | 4 | #include 5 | 6 | #define SWORD_MAX (0xffffffff) 7 | #define SBYTE_MAX (0xff) 8 | 9 | #if USHRT_MAX == SWORD_MAX 10 | typedef unsigned short sword; 11 | #elif UINT_MAX == SWORD_MAX 12 | typedef unsigned int sword; 13 | #elif ULONG_MAX == SWORD_MAX 14 | typedef unsigned long sword; 15 | #elif 16 | #error "Cannot define 32 bit unsigned int (sword)" 17 | #endif 18 | 19 | #if UCHAR_MAX == SBYTE_MAX 20 | typedef unsigned char sbyte; 21 | #elif 22 | #error "Cannot define 8 bit unsigned int (sbyte)" 23 | #endif 24 | 25 | typedef int sbool; 26 | 27 | #define SFALSE (0) 28 | #define STRUE (1) 29 | #define SNULL ((sword)-1) 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /tsalis/Makefile: -------------------------------------------------------------------------------- 1 | CC := gcc 2 | BIN := ../bin/tsalis 3 | 4 | SOURCES := $(wildcard src/*.c) 5 | OBJECTS := $(patsubst src/%.c,build/%.o,$(SOURCES)) 6 | DEPS := $(patsubst %.o,%.d,$(OBJECTS)) 7 | 8 | LFLAGS := -L ../bin -l:libsalis.so -lncurses 9 | 10 | # uncomment for debug 11 | # OFLAGS := -ggdb 12 | 13 | # uncomment for release 14 | OFLAGS := -O3 -DNDEBUG 15 | 16 | CFLAGS := -Iinclude -I../include -c $(OFLAGS) -MMD -Wall -Wextra -std=c89 \ 17 | -pedantic-errors -Wmissing-prototypes -Wstrict-prototypes \ 18 | -Wold-style-definition 19 | 20 | all: $(OBJECTS) 21 | $(CC) $(OBJECTS) $(LFLAGS) -o $(BIN) 22 | 23 | -include $(DEPS) 24 | 25 | $(OBJECTS): $(patsubst build/%.o,src/%.c,$@) 26 | $(CC) $(CFLAGS) $(patsubst build/%.o,src/%.c,$@) -o $@ 27 | 28 | clean: 29 | -rm build/* 30 | -rm $(BIN) 31 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC := gcc 2 | LIB := bin/libsalis.so 3 | ULIB := /usr/lib/libsalis.so 4 | 5 | SOURCES := $(wildcard src/*.c) 6 | OBJECTS := $(patsubst src/%.c,build/%.o,$(SOURCES)) 7 | DEPS := $(patsubst %.o,%.d,$(OBJECTS)) 8 | 9 | LFLAGS := -shared 10 | 11 | # uncomment for debug 12 | # OFLAGS := -ggdb 13 | 14 | # uncomment for release 15 | OFLAGS := -O3 -DNDEBUG 16 | 17 | CFLAGS := -Iinclude -c $(OFLAGS) -MMD -Wall -Wextra -std=c89 -fPIC \ 18 | -pedantic-errors -Wmissing-prototypes -Wstrict-prototypes \ 19 | -Wold-style-definition 20 | 21 | all: $(OBJECTS) 22 | $(CC) $(LFLAGS) -o $(LIB) $(OBJECTS) 23 | $(MAKE) -C tsalis 24 | 25 | -include $(DEPS) 26 | 27 | $(OBJECTS): $(patsubst build/%.o,src/%.c,$@) 28 | $(CC) $(CFLAGS) $(patsubst build/%.o,src/%.c,$@) -o $@ 29 | 30 | clean: 31 | -rm build/* 32 | -rm $(LIB) 33 | $(MAKE) clean -C tsalis 34 | 35 | install: 36 | cp $(LIB) $(ULIB) 37 | -------------------------------------------------------------------------------- /include/process.h: -------------------------------------------------------------------------------- 1 | #ifndef SALIS_PROCESS_H 2 | #define SALIS_PROCESS_H 3 | 4 | #define SPROC_REG_COUNT 4 5 | #define SPROC_STACK_SIZE 8 6 | #define SPROC_ELEM_COUNT (6 + SPROC_REG_COUNT + SPROC_STACK_SIZE) 7 | 8 | typedef struct { 9 | sword mb1a; 10 | sword mb1s; 11 | sword mb2a; 12 | sword mb2s; 13 | 14 | sword ip; 15 | sword sp; 16 | 17 | sword regs [SPROC_REG_COUNT]; 18 | sword stack [SPROC_STACK_SIZE]; 19 | } SProc; 20 | 21 | void sp_init (void); 22 | void sp_quit (void); 23 | void sp_load (FILE *file); 24 | void sp_save (FILE *file); 25 | 26 | sbool sp_isInit (void); 27 | sword sp_getCount (void); 28 | sword sp_getCap (void); 29 | sword sp_getFirst (void); 30 | sword sp_getLast (void); 31 | 32 | sbool sp_isFree (sword pidx); 33 | SProc sp_getProc (sword pidx); 34 | void sp_setProc (sword pidx, SProc proc); 35 | 36 | void sp_create (sword addr, sword size); 37 | void sp_kill (void); 38 | void sp_cycle (void); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /src/instset.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "types.h" 3 | #include "instset.h" 4 | 5 | sbool 6 | si_isInst(sword inst) 7 | { 8 | return inst < SINST_COUNT; 9 | } 10 | 11 | static sbool 12 | isBetween(sword inst, sword lo, sword hi) 13 | { 14 | assert(si_isInst(inst)); 15 | assert(lo < SINST_COUNT); 16 | assert(hi < SINST_COUNT); 17 | 18 | if (inst < lo) { 19 | return SFALSE; 20 | } 21 | 22 | if (inst > hi) { 23 | return SFALSE; 24 | } 25 | 26 | return STRUE; 27 | } 28 | 29 | sbool 30 | si_isMod(sword inst) 31 | { 32 | assert(si_isInst(inst)); 33 | return isBetween(inst, SNOP0, SNOP3); 34 | } 35 | 36 | sbool 37 | si_isKey(sword inst) 38 | { 39 | assert(si_isInst(inst)); 40 | return isBetween(inst, SKEYA, SKEYP); 41 | } 42 | 43 | sbool 44 | si_isLock(sword inst) 45 | { 46 | assert(si_isInst(inst)); 47 | return isBetween(inst, SLOKA, SLOKP); 48 | } 49 | 50 | sbool 51 | si_keyLockMatch(sword key, sword lock) 52 | { 53 | assert(si_isKey(key)); 54 | assert(si_isInst(lock)); 55 | return (key - SKEYA) == (lock - SLOKA); 56 | } 57 | -------------------------------------------------------------------------------- /include/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef SALIS_MEMORY_H 2 | #define SALIS_MEMORY_H 3 | 4 | void sm_init (sword order); 5 | void sm_quit (void); 6 | void sm_load (FILE *file); 7 | void sm_save (FILE *file); 8 | 9 | sbool sm_isInit (void); 10 | sword sm_getOrder (void); 11 | sword sm_getSize (void); 12 | sword sm_getMemBlockCount (void); 13 | sword sm_getAllocated (void); 14 | sword sm_getCap (void); 15 | 16 | sbool sm_isOverCap (void); 17 | sbool sm_isValidAt (sword addr); 18 | sbool sm_isMemBlockStartAt (sword addr); 19 | sbool sm_isAllocatedAt (sword addr); 20 | 21 | void sm_setMemBlockStartAt (sword addr); 22 | void sm_unsetMemBlockStartAt (sword addr); 23 | void sm_allocateAt (sword addr); 24 | void sm_freeAt (sword addr); 25 | sbyte sm_getInstAt (sword addr); 26 | void sm_setInstAt (sword addr, sbyte inst); 27 | sbyte sm_getByteAt (sword addr); 28 | void sm_setByteAt (sword addr, sbyte byte); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /tsalis/include/printer.h: -------------------------------------------------------------------------------- 1 | #ifndef TSALIS_PRINTER_H 2 | #define TSALIS_PRINTER_H 3 | 4 | extern const int PROC_ELEMENT_COUNT; 5 | 6 | extern int g_currentPage; 7 | extern sword g_selectedProcess; 8 | extern sbool g_processShowGenes; 9 | extern sword g_processVertScroll; 10 | extern sword g_processDataScroll; 11 | extern sword g_processGeneScroll; 12 | extern sword g_worldPos; 13 | extern sword g_worldZoom; 14 | 15 | sbool tsp_check (void); 16 | void tsp_init (void); 17 | void tsp_quit (void); 18 | void tsp_onResize (void); 19 | void tsp_prevPage (void); 20 | void tsp_nextPage (void); 21 | void tsp_scrollUp (void); 22 | void tsp_scrollDown (void); 23 | void tsp_fastScrollUp (void); 24 | void tsp_fastScrollDown (void); 25 | void tsp_scrollLeft (void); 26 | void tsp_scrollRight (void); 27 | void tsp_scrollToTop (void); 28 | void tsp_scrollToLeft (void); 29 | void tsp_zoomIn (void); 30 | void tsp_zoomOut (void); 31 | void tsp_prevOrganism (void); 32 | void tsp_nextOrganism (void); 33 | void tsp_gotoSelectedProc (void); 34 | void tsp_selectProcess (sword proc); 35 | void tsp_moveTo (sword loc); 36 | void tsp_printData (void); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /plugins/grapher.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ''' 3 | This script generates a data file that can be read by gnuplot or similar 4 | software. The first column represent the date (cycle * epoch) of the Salis 5 | save file. The second column represents the number of organisms at that given 6 | dat. 7 | 8 | To run it, you may call it from within the ./bin/ directory (or wherever you 9 | keep your auto-saved files) inside the SALIS main directory, such as: 10 | 11 | ../plugins/grapher.py def.sim.*.auto 12 | 13 | Calling this will create a single DATA file (output.data) including data from 14 | all files matching the given pattern. This file may, in turn, be passed into 15 | gnuplot for generating graphs. 16 | ''' 17 | import os 18 | import sys 19 | from ctypes import * 20 | 21 | oname = 'output.data' 22 | salis = CDLL('libsalis.so') 23 | salis.s_getCycle.restype = c_uint 24 | salis.s_getEpoch.restype = c_uint 25 | salis.sp_getCount.restype = c_uint 26 | 27 | with open(oname, 'w') as output: 28 | for fileName in sys.argv[1:]: 29 | salis.s_load(bytes(fileName, 'utf-8')) 30 | cycle = salis.s_getCycle() 31 | epoch = salis.s_getEpoch() 32 | date = cycle + (epoch * (2 ** 32)) 33 | output.write('{} {}\n'.format(date, salis.sp_getCount())) 34 | print('data of date {} added to \'output.data\''.format(date)) 35 | salis.s_quit() 36 | -------------------------------------------------------------------------------- /plugins/imager.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | ''' 3 | This script generates a PNG image from a SALIS save file (or a list of saved 4 | files), on which each pixel corresponds to a single byte on the simulation. 5 | It's useful for identifying large scale structures and appreciating the 6 | macro-evolution of the world. 7 | 8 | Tu run it, simply call it from within the ./bin/ directory inside the SALIS 9 | main directory, such as: 10 | 11 | ../plugins/imager.py def.sim.*.auto 12 | 13 | Calling this will create a PNG image for each file matching the given pattern. 14 | 15 | By default, this script ignores any existing simulation files whose name 16 | matches an existing image on the same directory. You may force it to overwrite 17 | existing images by passing the '-o' or '--overwrite' flag. All other parameters 18 | are considered part of the file list. 19 | ''' 20 | import os 21 | import sys 22 | from ctypes import * 23 | from PIL import Image 24 | 25 | if '-o' in sys.argv or '--overwrite' in sys.argv: 26 | overwrite = True 27 | sys.argv.remove('-o') 28 | sys.argv.remove('--overwrite') 29 | else: 30 | overwrite = False 31 | 32 | salis = CDLL('libsalis.so') 33 | salis.sm_getSize.restype = c_uint 34 | 35 | def makeImage(iname): 36 | oname = iname + '.png' 37 | 38 | if not overwrite: 39 | if os.path.isfile('./' + oname): 40 | print(oname + ' skipped') 41 | else: 42 | salis.s_load(bytes(iname, 'utf-8')) 43 | lsize = int(salis.sm_getSize() ** 0.5) 44 | image = Image.new('L', (lsize, lsize), 'black') 45 | pixels = image.load() 46 | 47 | for y in range(lsize): 48 | for x in range(lsize): 49 | addr = (y * lsize) + x 50 | byte = salis.sm_getByteAt(addr) 51 | pixels[x, y] = byte 52 | 53 | salis.s_quit() 54 | image.save(oname) 55 | print(oname + ' generated') 56 | 57 | for fileName in sys.argv[1:]: 58 | makeImage(fileName) 59 | -------------------------------------------------------------------------------- /src/salis.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "salis.h" 4 | 5 | static sbool g_isInit; 6 | static sword g_cycle; 7 | static sword g_epoch; 8 | 9 | void 10 | s_init(sword order) 11 | { 12 | assert(!g_isInit); 13 | sm_init(order); 14 | se_init(); 15 | sp_init(); 16 | g_isInit = STRUE; 17 | } 18 | 19 | void 20 | s_quit(void) 21 | { 22 | assert(g_isInit); 23 | sp_quit(); 24 | se_quit(); 25 | sm_quit(); 26 | g_isInit = SFALSE; 27 | g_cycle = 0; 28 | g_epoch = 0; 29 | } 30 | 31 | void 32 | s_load(const char *fileName) 33 | { 34 | FILE *file; 35 | assert(!g_isInit); 36 | assert(fileName); 37 | file = fopen(fileName, "rb"); 38 | assert(file); 39 | fread(&g_isInit, sizeof(sbool), 1, file); 40 | fread(&g_cycle, sizeof(sword), 1, file); 41 | fread(&g_epoch, sizeof(sword), 1, file); 42 | sm_load(file); 43 | se_load(file); 44 | sp_load(file); 45 | fclose(file); 46 | } 47 | 48 | void 49 | s_save(const char *fileName) 50 | { 51 | FILE *file; 52 | assert(g_isInit); 53 | assert(fileName); 54 | file = fopen(fileName, "wb"); 55 | assert(file); 56 | fwrite(&g_isInit, sizeof(sbool), 1, file); 57 | fwrite(&g_cycle, sizeof(sword), 1, file); 58 | fwrite(&g_epoch, sizeof(sword), 1, file); 59 | sm_save(file); 60 | se_save(file); 61 | sp_save(file); 62 | fclose(file); 63 | } 64 | 65 | sbool 66 | s_isInit(void) 67 | { 68 | return g_isInit; 69 | } 70 | 71 | sword 72 | s_getCycle(void) 73 | { 74 | return g_cycle; 75 | } 76 | 77 | sword 78 | s_getEpoch(void) 79 | { 80 | return g_epoch; 81 | } 82 | 83 | void 84 | s_cycle(void) 85 | { 86 | assert(g_isInit); 87 | assert(sm_isInit()); 88 | assert(sp_isInit()); 89 | assert(se_isInit()); 90 | g_cycle++; 91 | 92 | if (!g_cycle) { 93 | g_epoch++; 94 | } 95 | 96 | se_cycle(); 97 | sp_cycle(); 98 | } 99 | -------------------------------------------------------------------------------- /include/instset.h: -------------------------------------------------------------------------------- 1 | #ifndef SALIS_INSTSET_H 2 | #define SALIS_INSTSET_H 3 | 4 | #define SINST_COUNT 64 5 | 6 | #define SINST_LIST \ 7 | SINST(SNOOP, ' ') \ 8 | SINST(SNOP0, '0') \ 9 | SINST(SNOP1, '1') \ 10 | SINST(SNOP2, '2') \ 11 | SINST(SNOP3, '3') \ 12 | \ 13 | SINST(SJMPB, '(') \ 14 | SINST(SJMPF, ')') \ 15 | SINST(SADRB, '[') \ 16 | SINST(SADRF, ']') \ 17 | SINST(SIFNZ, '?') \ 18 | \ 19 | SINST(SALLB, '{') \ 20 | SINST(SALLF, '}') \ 21 | SINST(SBSWP, '%') \ 22 | SINST(SBCLR, '|') \ 23 | SINST(SSPLT, '$') \ 24 | \ 25 | SINST(SADDN, '+') \ 26 | SINST(SSUBN, '-') \ 27 | SINST(SMULN, '*') \ 28 | SINST(SDIVN, '/') \ 29 | SINST(SINCN, '^') \ 30 | SINST(SDECN, 'v') \ 31 | SINST(SNOTN, '!') \ 32 | SINST(SSHFL, '<') \ 33 | SINST(SSHFR, '>') \ 34 | SINST(SZERO, 'z') \ 35 | SINST(SUNIT, 'u') \ 36 | \ 37 | SINST(SPSHN, '#') \ 38 | SINST(SPOPN, '~') \ 39 | \ 40 | SINST(SLOAD, '.') \ 41 | SINST(SWRTE, ':') \ 42 | SINST(SDUPL, '"') \ 43 | SINST(SSWAP, 'x') \ 44 | \ 45 | SINST(SKEYA, 'a') \ 46 | SINST(SKEYB, 'b') \ 47 | SINST(SKEYC, 'c') \ 48 | SINST(SKEYD, 'd') \ 49 | SINST(SKEYE, 'e') \ 50 | SINST(SKEYF, 'f') \ 51 | SINST(SKEYG, 'g') \ 52 | SINST(SKEYH, 'h') \ 53 | SINST(SKEYI, 'i') \ 54 | SINST(SKEYJ, 'j') \ 55 | SINST(SKEYK, 'k') \ 56 | SINST(SKEYL, 'l') \ 57 | SINST(SKEYM, 'm') \ 58 | SINST(SKEYN, 'n') \ 59 | SINST(SKEYO, 'o') \ 60 | SINST(SKEYP, 'p') \ 61 | \ 62 | SINST(SLOKA, 'A') \ 63 | SINST(SLOKB, 'B') \ 64 | SINST(SLOKC, 'C') \ 65 | SINST(SLOKD, 'D') \ 66 | SINST(SLOKE, 'E') \ 67 | SINST(SLOKF, 'F') \ 68 | SINST(SLOKG, 'G') \ 69 | SINST(SLOKH, 'H') \ 70 | SINST(SLOKI, 'I') \ 71 | SINST(SLOKJ, 'J') \ 72 | SINST(SLOKK, 'K') \ 73 | SINST(SLOKL, 'L') \ 74 | SINST(SLOKM, 'M') \ 75 | SINST(SLOKN, 'N') \ 76 | SINST(SLOKO, 'O') \ 77 | SILST(SLOKP, 'P') 78 | 79 | enum sinst { 80 | #define SINST(name, symb) name, 81 | #define SILST(name, symb) name 82 | SINST_LIST 83 | #undef SINST 84 | #undef SILST 85 | }; 86 | 87 | sbool si_isInst (sword inst); 88 | sbool si_isMod (sword inst); 89 | sbool si_isKey (sword inst); 90 | sbool si_isLock (sword inst); 91 | sbool si_keyLockMatch (sword key, sword lock); 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /tsalis/src/tsalis.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "printer.h" 7 | #include "handler.h" 8 | #include "tsalis.h" 9 | 10 | #define DEFAULT_ORDER 16 11 | 12 | sbool g_exit; 13 | sbool g_running; 14 | sword g_autoSaveInterval; 15 | char g_simName[NAME_MAX_SIZE + 1] = "def.sim"; 16 | 17 | static void 18 | onDefault(void) 19 | { 20 | FILE *testFile = fopen(g_simName, "r"); 21 | 22 | if (testFile) { 23 | fclose(testFile); 24 | s_load(g_simName); 25 | } else { 26 | s_init(DEFAULT_ORDER); 27 | } 28 | } 29 | 30 | static void 31 | onLoad(const char *fileName) 32 | { 33 | FILE *testFile; 34 | 35 | if (strlen(fileName) > NAME_MAX_SIZE) { 36 | fputs("ERROR: File name too long\n", stderr); 37 | exit(1); 38 | } 39 | 40 | strncpy(g_simName, fileName, NAME_MAX_SIZE); 41 | testFile = fopen(g_simName, "r"); 42 | 43 | if (testFile) { 44 | fclose(testFile); 45 | s_load(g_simName); 46 | } else { 47 | fputs("ERROR: File does not exist\n", stderr); 48 | exit(1); 49 | } 50 | } 51 | 52 | static void 53 | init(int argc, char **argv) 54 | { 55 | if (!tsp_check()) { 56 | fputs("ERROR: Terminal not supported\n", stderr); 57 | exit(1); 58 | } 59 | 60 | if (argc == 1) { 61 | onDefault(); 62 | } else if (argc == 3) { 63 | if (!strcmp(argv[1], "-n") || !strcmp(argv[1], "--new")) { 64 | s_init(atoi(argv[2])); 65 | } else if (!strcmp(argv[1], "-l") || !strcmp(argv[1], "--load")) { 66 | onLoad(argv[2]); 67 | } else { 68 | fputs("ERROR: Incorrect arguments\n", stderr); 69 | exit(1); 70 | } 71 | } else { 72 | fputs("ERROR: Incorrect argument count\n", stderr); 73 | exit(1); 74 | } 75 | 76 | tsp_init(); 77 | } 78 | 79 | static void 80 | exec(void) 81 | { 82 | while (!g_exit) { 83 | if (g_running) { 84 | clock_t beg = clock(); 85 | clock_t end; 86 | float delay; 87 | 88 | do { 89 | s_cycle(); 90 | 91 | if (g_autoSaveInterval && !(s_getCycle() % g_autoSaveInterval)) { 92 | char extendedName[NAME_MAX_SIZE + 28]; 93 | sprintf(extendedName, "%s.%010u.%010u.auto", g_simName, s_getEpoch(), s_getCycle()); 94 | s_save(extendedName); 95 | } 96 | 97 | end = clock(); 98 | delay = (float)(end - beg) / CLOCKS_PER_SEC; 99 | } while (delay < (1.0 / 60.0)); 100 | } 101 | 102 | tsp_printData(); 103 | tsh_handleEvent(getch()); 104 | } 105 | } 106 | 107 | static void 108 | quit(void) 109 | { 110 | tsp_quit(); 111 | s_quit(); 112 | } 113 | 114 | int 115 | main(int argc, char **argv) 116 | { 117 | init(argc, argv); 118 | exec(); 119 | quit(); 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /src/evolver.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "types.h" 6 | #include "instset.h" 7 | #include "memory.h" 8 | #include "evolver.h" 9 | 10 | sbool g_isInit; 11 | sword g_lastAddress; 12 | sbyte g_lastInst; 13 | sword g_state[4]; 14 | 15 | void 16 | se_init(void) 17 | { 18 | assert(!g_isInit); 19 | srand((unsigned)time(NULL)); 20 | g_state[0] = rand(); 21 | g_state[1] = rand(); 22 | g_state[2] = rand(); 23 | g_state[3] = rand(); 24 | g_isInit = STRUE; 25 | } 26 | 27 | void 28 | se_quit(void) 29 | { 30 | assert(g_isInit); 31 | g_isInit = SFALSE; 32 | g_lastAddress = 0; 33 | g_lastInst = 0; 34 | g_state[0] = 0; 35 | g_state[1] = 0; 36 | g_state[2] = 0; 37 | g_state[3] = 0; 38 | } 39 | 40 | void 41 | se_load(FILE *file) 42 | { 43 | assert(!g_isInit); 44 | assert(file); 45 | fread(&g_isInit, sizeof(sbool), 1, file); 46 | fread(&g_lastAddress, sizeof(sword), 1, file); 47 | fread(&g_lastInst, sizeof(sbyte), 1, file); 48 | fread(g_state, sizeof(sword), 4, file); 49 | } 50 | 51 | void 52 | se_save(FILE *file) 53 | { 54 | assert(g_isInit); 55 | assert(file); 56 | fwrite(&g_isInit, sizeof(sbool), 1, file); 57 | fwrite(&g_lastAddress, sizeof(sword), 1, file); 58 | fwrite(&g_lastInst, sizeof(sbyte), 1, file); 59 | fwrite(g_state, sizeof(sword), 4, file); 60 | } 61 | 62 | sbool 63 | se_isInit(void) 64 | { 65 | return g_isInit; 66 | } 67 | 68 | sword 69 | se_getLastAddress(void) 70 | { 71 | return g_lastAddress; 72 | } 73 | 74 | sbyte 75 | se_getLastInst(void) 76 | { 77 | assert(si_isInst(g_lastInst)); 78 | return g_lastInst; 79 | } 80 | 81 | sword 82 | se_getState(sword eidx) 83 | { 84 | assert(eidx < 4); 85 | return g_state[eidx]; 86 | } 87 | 88 | void 89 | se_setState(sword eidx, sword state) 90 | { 91 | assert(g_isInit); 92 | assert(eidx < 4); 93 | g_state[eidx] = state; 94 | } 95 | 96 | static sword 97 | generateRandomNumber(void) 98 | { 99 | sword s; 100 | sword t; 101 | assert(g_isInit); 102 | t = g_state[3]; 103 | t ^= t << 11; 104 | t ^= t >> 8; 105 | g_state[3] = g_state[2]; 106 | g_state[2] = g_state[1]; 107 | g_state[1] = g_state[0]; 108 | s = g_state[0]; 109 | t ^= s; 110 | t ^= s >> 19; 111 | g_state[0] = t; 112 | return t; 113 | } 114 | 115 | void 116 | se_randomizeAt(sword addr) 117 | { 118 | assert(g_isInit); 119 | assert(sm_isValidAt(addr)); 120 | sm_setInstAt(addr, (sbyte)(generateRandomNumber() % SINST_COUNT)); 121 | } 122 | 123 | void 124 | se_cycle(void) 125 | { 126 | assert(g_isInit); 127 | g_lastAddress = generateRandomNumber(); 128 | g_lastInst = (sbyte)(generateRandomNumber() % SINST_COUNT); 129 | 130 | if (sm_isValidAt(g_lastAddress)) { 131 | sm_setInstAt(g_lastAddress, (sbyte)g_lastInst); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/memory.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "types.h" 5 | #include "instset.h" 6 | #include "memory.h" 7 | 8 | #define MEM_BLOCK_START_FLAG (0x80) 9 | #define ALLOCATED_FLAG (0x40) 10 | #define INSTRUCTION_MASK (0x3f) 11 | 12 | static sbool g_isInit; 13 | static sword g_order; 14 | static sword g_size; 15 | static sword g_memBlockCount; 16 | static sword g_allocated; 17 | static sword g_cap; 18 | static sbyte *g_data; 19 | 20 | void 21 | sm_init(sword order) 22 | { 23 | assert(!g_isInit); 24 | assert(INSTRUCTION_MASK == SINST_COUNT - 1); 25 | g_isInit = STRUE; 26 | g_order = order; 27 | g_size = 1 << g_order; 28 | g_cap = g_size / 2; 29 | g_data = calloc(g_size, sizeof(sbyte)); 30 | assert(g_data); 31 | } 32 | 33 | void 34 | sm_quit(void) 35 | { 36 | assert(g_isInit); 37 | free(g_data); 38 | g_isInit = SFALSE; 39 | g_order = 0; 40 | g_size = 0; 41 | g_memBlockCount = 0; 42 | g_allocated = 0; 43 | g_cap = 0; 44 | g_data = NULL; 45 | } 46 | 47 | void 48 | sm_load(FILE *file) 49 | { 50 | assert(!g_isInit); 51 | assert(file); 52 | fread(&g_isInit, sizeof(sbool), 1, file); 53 | fread(&g_order, sizeof(sword), 1, file); 54 | fread(&g_size, sizeof(sword), 1, file); 55 | fread(&g_memBlockCount, sizeof(sword), 1, file); 56 | fread(&g_allocated, sizeof(sword), 1, file); 57 | fread(&g_cap, sizeof(sword), 1, file); 58 | g_data = calloc(g_size, sizeof(sbyte)); 59 | assert(g_data); 60 | fread(g_data, sizeof(sbyte), g_size, file); 61 | } 62 | 63 | void 64 | sm_save(FILE *file) 65 | { 66 | assert(g_isInit); 67 | assert(file); 68 | fwrite(&g_isInit, sizeof(sbool), 1, file); 69 | fwrite(&g_order, sizeof(sword), 1, file); 70 | fwrite(&g_size, sizeof(sword), 1, file); 71 | fwrite(&g_memBlockCount, sizeof(sword), 1, file); 72 | fwrite(&g_allocated, sizeof(sword), 1, file); 73 | fwrite(&g_cap, sizeof(sword), 1, file); 74 | fwrite(g_data, sizeof(sbyte), g_size, file); 75 | } 76 | 77 | sbool 78 | sm_isInit(void) 79 | { 80 | return g_isInit; 81 | } 82 | 83 | sword 84 | sm_getOrder(void) 85 | { 86 | return g_order; 87 | } 88 | 89 | sword 90 | sm_getSize(void) 91 | { 92 | return g_size; 93 | } 94 | 95 | sword 96 | sm_getMemBlockCount(void) 97 | { 98 | return g_memBlockCount; 99 | } 100 | 101 | sword 102 | sm_getAllocated(void) 103 | { 104 | return g_allocated; 105 | } 106 | 107 | sword 108 | sm_getCap(void) 109 | { 110 | return g_cap; 111 | } 112 | 113 | sbool 114 | sm_isOverCap(void) 115 | { 116 | assert(g_isInit); 117 | return g_allocated > g_cap; 118 | } 119 | 120 | sbool 121 | sm_isValidAt(sword addr) 122 | { 123 | assert(g_isInit); 124 | return addr < g_size; 125 | } 126 | 127 | sbool 128 | sm_isMemBlockStartAt(sword addr) 129 | { 130 | assert(g_isInit); 131 | assert(sm_isValidAt(addr)); 132 | return !!(g_data[addr] & MEM_BLOCK_START_FLAG); 133 | } 134 | 135 | sbool 136 | sm_isAllocatedAt(sword addr) 137 | { 138 | assert(g_isInit); 139 | assert(sm_isValidAt(addr)); 140 | return !!(g_data[addr] & ALLOCATED_FLAG); 141 | } 142 | 143 | void 144 | sm_setMemBlockStartAt(sword addr) 145 | { 146 | assert(g_isInit); 147 | assert(sm_isValidAt(addr)); 148 | assert(!sm_isMemBlockStartAt(addr)); 149 | g_data[addr] ^= MEM_BLOCK_START_FLAG; 150 | g_memBlockCount++; 151 | assert(sm_isMemBlockStartAt(addr)); 152 | assert(g_memBlockCount); 153 | assert(g_memBlockCount <= g_size); 154 | } 155 | 156 | void 157 | sm_unsetMemBlockStartAt(sword addr) 158 | { 159 | assert(g_isInit); 160 | assert(g_memBlockCount); 161 | assert(sm_isValidAt(addr)); 162 | assert(sm_isMemBlockStartAt(addr)); 163 | g_data[addr] ^= MEM_BLOCK_START_FLAG; 164 | g_memBlockCount--; 165 | assert(!sm_isMemBlockStartAt(addr)); 166 | assert(g_memBlockCount <= g_size); 167 | } 168 | 169 | void 170 | sm_allocateAt(sword addr) 171 | { 172 | assert(g_isInit); 173 | assert(sm_isValidAt(addr)); 174 | assert(!sm_isAllocatedAt(addr)); 175 | g_data[addr] ^= ALLOCATED_FLAG; 176 | g_allocated++; 177 | assert(sm_isAllocatedAt(addr)); 178 | assert(g_allocated); 179 | assert(g_allocated <= g_size); 180 | } 181 | 182 | void 183 | sm_freeAt(sword addr) 184 | { 185 | assert(g_isInit); 186 | assert(g_allocated); 187 | assert(sm_isValidAt(addr)); 188 | assert(sm_isAllocatedAt(addr)); 189 | g_data[addr] ^= ALLOCATED_FLAG; 190 | g_allocated--; 191 | assert(!sm_isAllocatedAt(addr)); 192 | assert(g_allocated <= g_size); 193 | } 194 | 195 | sbyte 196 | sm_getInstAt(sword addr) 197 | { 198 | assert(g_isInit); 199 | assert(sm_isValidAt(addr)); 200 | return g_data[addr] & INSTRUCTION_MASK; 201 | } 202 | 203 | void 204 | sm_setInstAt(sword addr, sbyte inst) 205 | { 206 | assert(g_isInit); 207 | assert(sm_isValidAt(addr)); 208 | assert(si_isInst(inst)); 209 | g_data[addr] &= (MEM_BLOCK_START_FLAG | ALLOCATED_FLAG); 210 | g_data[addr] |= inst; 211 | } 212 | 213 | sbyte 214 | sm_getByteAt(sword addr) 215 | { 216 | assert(g_isInit); 217 | assert(sm_isValidAt(addr)); 218 | return g_data[addr]; 219 | } 220 | 221 | void 222 | sm_setByteAt(sword addr, sbyte byte) 223 | { 224 | assert(g_isInit); 225 | assert(sm_isValidAt(addr)); 226 | g_data[addr] = byte; 227 | } 228 | -------------------------------------------------------------------------------- /tsalis/README.md: -------------------------------------------------------------------------------- 1 | # TSALIS 2 | *TSALIS* is a text user interface (TUI) designed to communicate with *SALIS*. 3 | Its only dependencies are ncurses and the *SALIS* library itself. It should be 4 | portable enough and should run easily in any terminal environment. 5 | 6 | ## Building instructions 7 | You'll need nothing but a C compiler (C89). You must build the program and link 8 | it with *SALIS* (e.g. *libsalis.so*) and ncurses. A sample makefile 9 | (Makefile) is provided for GNU Make. You can also just run the `make` command 10 | inside the salis directory and it will automate the building and linking of 11 | both the library and this application. By default, both *SALIS* and *TSALIS* 12 | will be built on the `bin` directory, on the *SALIS* main repository. Feel 13 | free to edit both makefiles as needed. If you run into any difficulties, please 14 | let me know! 15 | 16 | ## List of commands 17 | ### Command-line arguments 18 | You may run *TSALIS* from the terminal in any of the following ways (arguments 19 | are being represented by *XX*). Note that, upon exit, *SALIS* automatically 20 | generates a save (by default called *def.sim*). This save file may be freely 21 | renamed and reloaded as needed. 22 | 23 | |Arguments |Action | 24 | |:------------------|-------------------------------------------------------------------------------:| 25 | |tsalis |If file *def.sim* exists in directory, loads simulation from that file. | 26 | |tsalis |If file *def.sim* does not exist, creates new simulation (memory size 2^16). | 27 | |tsalis -n *XX* |Creates new simulation with memory size 2^*XX*. | 28 | |tsalis --new *XX* |Creates new simulation with memory size 2^*XX*. | 29 | |tsalis -l *XX* |Loads simulation from file named *XX*. | 30 | |tsalis --load *XX* |Loads simulation from file named *XX*. | 31 | 32 | ### Keyboard commands 33 | |Key |Action | 34 | |:--------------|--------------------------------------------------------------------------------------------:| 35 | |Left arrow |Previous page | 36 | |Right arrow |Next page | 37 | |wasd |Scroll (PROCESS and WORLD page) | 38 | |WA |Fast vertical scroll (PROCESS and WORLD page) | 39 | |Q |Scroll to top (PROCESS and WORLD page) | 40 | |A |Scroll to left (PROCESS page) | 41 | |zx |Zoom in/out (WORLD page) | 42 | |op |Select previous/next organism | 43 | |g |Toggle data/gene view (PROCESS page) | 44 | |c |Open console (pauses simulation) | 45 | |Space |Run/pause simulation | 46 | |jl |Select first/last organism | 47 | |k |Go to selected organism (PROCESS and WORLD page) | 48 | |Numbers (1-0) |Cycle simulation 2^(n-1) steps (i.e. 1 = 1 step, 2 = 2 steps, 3 = 4 steps, 4 = 8 steps, ...) | 49 | 50 | ### Console commands 51 | The console opens up when 'c' is pressed. Commands, with their respective 52 | parameters separated by underscores, may be written in order to modify or 53 | control some aspects of the simulation. Parameters here are represented by 54 | *XX*. 55 | 56 | |Command |Param. 1 |Param. 2 |Action | 57 | |:-----------|:-----------|:-----------|---------------------------------------------------------------------:| 58 | |q |--- |--- |Save and quit simulation. | 59 | |q! |--- |--- |Quit simulation without saving. | 60 | |i*XX*\_*XX* |address |instructions|Writes given instructions into address. | 61 | |c*XX*\_*XX* |address |file name |Compiles given file into address. | 62 | |n*XX*\_*XX* |address |size |Initializes organism of given size into address. | 63 | |k |--- |--- |Kills organism at bottom of queue (first organism). | 64 | |m*XX* |address |--- |Scroll/move (PROCESS and WORLD page) to given process/address. | 65 | |p*XX* |process id |--- |Select given process. | 66 | |s |--- |--- |Save simulation. | 67 | |r*XX* |name |--- |Rename simulation (will be automatically saved to this name on exit). | 68 | |a*XX* |interval |--- |Set simulation's auto-save interval. | 69 | 70 | ### Legend 71 | In WORLD view, as well as in PROCESS view (when gene mode is selected), each 72 | cell is colored according to the following legend: 73 | 74 | |Background color |Meaning | 75 | |:----------------|---------------------------------------:| 76 | |BLUE |Non-allocated cell | 77 | |CYAN |Allocated cell | 78 | |WHITE |Start of memory block | 79 | |YELLOW |Main memory block of selected organism | 80 | |GREEN |Child memory block of selected organism | 81 | |MAGENTA |SP of selected organism | 82 | |RED |IP of selected organism | 83 | -------------------------------------------------------------------------------- /tsalis/src/handler.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "printer.h" 6 | #include "handler.h" 7 | #include "tsalis.h" 8 | 9 | #define CONSOLE_INPUT_LENGTH 64 10 | 11 | static sbyte 12 | symbolToInst(char charSymbol) 13 | { 14 | #define SINST(name, symbol) case symbol: return name; 15 | #define SILST(name, symbol) case symbol: return name; 16 | 17 | switch (charSymbol) { 18 | SINST_LIST 19 | } 20 | 21 | #undef SINST 22 | #undef SILST 23 | return (sbyte)(-1); 24 | } 25 | 26 | static void 27 | writeInstructions(const char *command) 28 | { 29 | sword addr = atoi(command); 30 | char *symbol = strchr(command, '_'); 31 | 32 | if (symbol) { 33 | symbol++; 34 | 35 | while (sm_isValidAt(addr) && *symbol) { 36 | sbyte svalue = symbolToInst(*symbol); 37 | 38 | if (si_isInst(svalue)) { 39 | sm_setInstAt(addr, svalue); 40 | } else { 41 | sm_setInstAt(addr, 0); 42 | } 43 | 44 | addr++; 45 | symbol++; 46 | } 47 | } 48 | } 49 | 50 | static void 51 | compileGenome(const char *command) 52 | { 53 | sword addr = atoi(command); 54 | char *fileName = strchr(command, '_'); 55 | 56 | if (fileName) { 57 | FILE *file = fopen(fileName + 1, "r"); 58 | 59 | if (file) { 60 | while (addr < sm_getSize()) { 61 | int symbol = fgetc(file); 62 | sbyte svalue = symbolToInst((char)symbol); 63 | 64 | if (symbol == EOF) { 65 | break; 66 | } 67 | 68 | if (si_isInst(svalue)) { 69 | sm_setInstAt(addr, svalue); 70 | } else { 71 | sm_setInstAt(addr, 0); 72 | } 73 | 74 | addr++; 75 | } 76 | } 77 | } 78 | } 79 | 80 | static void 81 | createOrganism(const char *command) 82 | { 83 | sword addr = atoi(command); 84 | char *sizep = strchr(command, '_'); 85 | 86 | if (sizep) { 87 | sword size = atoi(sizep + 1); 88 | 89 | if (sm_isValidAt(addr) && sm_isValidAt(addr + size - 1)) { 90 | sword offset; 91 | 92 | for (offset = 0; offset < size; offset++) { 93 | if (sm_isAllocatedAt(addr + offset)) { 94 | return; 95 | } 96 | } 97 | 98 | sp_create(addr, size); 99 | } 100 | } 101 | } 102 | 103 | static void 104 | killOrganism(void) 105 | { 106 | sp_kill(); 107 | } 108 | 109 | static void 110 | moveTo(const char *command) 111 | { 112 | sword loc = atoi(command); 113 | tsp_moveTo(loc); 114 | } 115 | 116 | static void 117 | selectProc(const char *command) 118 | { 119 | sword proc = atoi(command); 120 | tsp_selectProcess(proc); 121 | } 122 | 123 | static void 124 | saveSim(void) 125 | { 126 | s_save(g_simName); 127 | } 128 | 129 | static void 130 | renameSim(const char *name) 131 | { 132 | if (strlen(name) <= NAME_MAX_SIZE) { 133 | clear(); 134 | strncpy(g_simName, name, NAME_MAX_SIZE); 135 | } 136 | } 137 | 138 | static void 139 | setAutoSave(const char *command) 140 | { 141 | g_autoSaveInterval = atoi(command); 142 | } 143 | 144 | static void 145 | clearConsoleLine(void) 146 | { 147 | move(LINES - 1, 0); 148 | clrtoeol(); 149 | } 150 | 151 | static void 152 | runConsole(void) 153 | { 154 | char command[CONSOLE_INPUT_LENGTH] = {0}; 155 | clearConsoleLine(); 156 | echo(); 157 | mvprintw(LINES - 1, 1, "$ "); 158 | curs_set(TRUE); 159 | getnstr(command, CONSOLE_INPUT_LENGTH - 1); 160 | curs_set(FALSE); 161 | noecho(); 162 | clearConsoleLine(); 163 | 164 | switch (command[0]) { 165 | case 'q': 166 | if (command[1] != '!') { 167 | s_save(g_simName); 168 | } 169 | 170 | g_exit = STRUE; 171 | break; 172 | 173 | case 'i': 174 | writeInstructions(&command[1]); 175 | break; 176 | 177 | case 'c': 178 | compileGenome(&command[1]); 179 | break; 180 | 181 | case 'n': 182 | createOrganism(&command[1]); 183 | break; 184 | 185 | case 'k': 186 | killOrganism(); 187 | break; 188 | 189 | case 'm': 190 | moveTo(&command[1]); 191 | break; 192 | 193 | case 'p': 194 | selectProc(&command[1]); 195 | break; 196 | 197 | case 's': 198 | saveSim(); 199 | break; 200 | 201 | case 'r': 202 | renameSim(&command[1]); 203 | break; 204 | 205 | case 'a': 206 | setAutoSave(&command[1]); 207 | break; 208 | } 209 | } 210 | 211 | void 212 | tsh_handleEvent(int event) 213 | { 214 | switch (event) { 215 | case KEY_RESIZE: 216 | tsp_onResize(); 217 | break; 218 | 219 | case KEY_LEFT: 220 | tsp_prevPage(); 221 | break; 222 | 223 | case KEY_RIGHT: 224 | tsp_nextPage(); 225 | break; 226 | 227 | case 'w': 228 | tsp_scrollDown(); 229 | break; 230 | 231 | case 'a': 232 | tsp_scrollLeft(); 233 | break; 234 | 235 | case 's': 236 | tsp_scrollUp(); 237 | break; 238 | 239 | case 'd': 240 | tsp_scrollRight(); 241 | break; 242 | 243 | case 'W': 244 | tsp_fastScrollDown(); 245 | break; 246 | 247 | case 'S': 248 | tsp_fastScrollUp(); 249 | break; 250 | 251 | case 'Q': 252 | tsp_scrollToTop(); 253 | break; 254 | 255 | case 'A': 256 | tsp_scrollToLeft(); 257 | break; 258 | 259 | case 'z': 260 | tsp_zoomIn(); 261 | break; 262 | 263 | case 'x': 264 | tsp_zoomOut(); 265 | break; 266 | 267 | case 'o': 268 | tsp_prevOrganism(); 269 | break; 270 | 271 | case 'p': 272 | tsp_nextOrganism(); 273 | break; 274 | 275 | case 'g': 276 | g_processShowGenes = !g_processShowGenes; 277 | break; 278 | 279 | case 'c': 280 | if (g_running) { 281 | nodelay(stdscr, SFALSE); 282 | } 283 | 284 | tsp_printData(); 285 | runConsole(); 286 | 287 | if (g_running) { 288 | nodelay(stdscr, STRUE); 289 | } 290 | 291 | break; 292 | 293 | case ' ': 294 | g_running = !g_running; 295 | nodelay(stdscr, g_running); 296 | break; 297 | 298 | case 'j': 299 | if (sp_getCount()) { 300 | g_selectedProcess = sp_getFirst(); 301 | } 302 | 303 | break; 304 | 305 | case 'l': 306 | if (sp_getCount()) { 307 | g_selectedProcess = sp_getLast(); 308 | } 309 | 310 | break; 311 | 312 | case 'k': 313 | tsp_gotoSelectedProc(); 314 | break; 315 | 316 | case '1': 317 | case '2': 318 | case '3': 319 | case '4': 320 | case '5': 321 | case '6': 322 | case '7': 323 | case '8': 324 | case '9': 325 | case '0': 326 | if (!g_running) { 327 | int power = ((event - '0') ? (event - '0') : 10) - 1; 328 | int cycles = 1 << power; 329 | 330 | while (cycles--) { 331 | s_cycle(); 332 | } 333 | } 334 | 335 | break; 336 | } 337 | } 338 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SALIS: A-Life Simulator 2 | 3 | ![SALIS running simulation](sim.png) 4 | 5 | ## Overview 6 | *SALIS* is my newest artificial life project. Mainly a re-take on Tom Ray's 7 | TIERRA simulation, but with my very own set of tweaks. Having a grasp on TIERRA 8 | will make understanding this simulation a lot easier. 9 | 10 | - [video about TIERRA](https://www.youtube.com/watch?v=Wl5rRGVD0QI) 11 | - [read about TIERRA](http://life.ou.edu/pubs/doc/index.html#What) 12 | 13 | For those that already know TIERRA, the main differences between it and SALIS 14 | are: 15 | - the replacement of templates with key-lock instruction pairs 16 | - the addition of a SEEKER POINTER to all organisms 17 | 18 | The seeker pointer is an attempt to bring extra spatial and temporal coherence 19 | to the simulation. Allocation, reads and writes will take more time when done 20 | between addresses that are far away, as a consequence of the SP having to 21 | travel those distances at a speed of 1 byte per update. In other words, in 22 | SALIS information can't travel faster than 1 byte per update (SALIS' speed of 23 | light, if you will). 24 | 25 | To watch an introductory video about *SALIS* 26 | [go here.](https://www.youtube.com/watch?v=jCFmOCvy6po) 27 | 28 | Follow *SALIS* on 29 | [Reddit.](https://www.reddit.com/r/salis/) 30 | 31 | ### Details 32 | - *SALIS* is an API, so an UI must be written to communicate with it 33 | - *SALIS* is written in C 34 | - *SALIS* must be compiled as a library (e.g. *libsalis.so*) 35 | 36 | ### Organisms consist of 37 | - One or two associated memory blocks 38 | - One instruction pointer 39 | - One seeker pointer 40 | - Four registers 41 | - A stack of configurable size (default is 8) 42 | 43 | ### Queue 44 | - Newborn organisms are placed on top of the queue 45 | - Organisms are killed at the bottom of the queue 46 | - Organisms are killed whenever memory fills above 50% 47 | 48 | ### Evolution 49 | In *SALIS* mutation occurs via *cosmic rays*: at every cycle a random 32 bit 50 | address is selected and a random instruction is written into it. 51 | 52 | ### Instruction set 53 | *SALIS*' organisms read a simple language similar to ASM. This language 54 | consists of 64 instructions, each with an associated name and symbol. 55 | Whenever an organism performs an invalid instruction it's considered a *fault*. 56 | When a *fault* is commited by any organism, the faulty instruction gets 57 | randomly replaced at that address and the organism's IP gets incremented. 58 | 59 | #### Faults 60 | - Perform a search or attempt a jump without a following key 61 | - Writing to an allocated (but not owned) or invalid address 62 | - Reading (loading) from an invalid address 63 | - SP on address non-adjacent to child memory block while allocating 64 | - Swapping, freeing or splitting when not owning 2 memory blocks 65 | - Dividing by zero 66 | 67 | #### Instruction set table 68 | |Name |Sym. |Val. |Description | 69 | |:--------|:-----|:-----|---------------------------------------------------------------------:| 70 | |NOOP | |00 |No operation. Does nothing. | 71 | |NOP0-3 |0-3 |01-04 |No operation. Modifies registers to be used (r0x to r3x). | 72 | |JMPB-F\* |() |05-06 |Jump to lock matching following key. | 73 | |ADRB-F\* |[] |07-08 |Search for lock matching following key and store on r[0]. | 74 | |IFNZ |? |09 |If r[0] is not zero, execute following instruction. Skip otherwise. | 75 | |ALLB-F\* |{} |10-11 |Allocate block of size stored on r[0]. Store its address on r[0]. | 76 | |BSWP\* |% |12 |Swap parent and child memory blocks. | 77 | |BCLR\* |\| |13 |Free child memory block. | 78 | |SPLT\* |$ |14 |Split. Child memory block becomes new organism. | 79 | |ADDN |+ |15 |Add (r[0] = r[1] + r[2]). | 80 | |SUBN |- |16 |Subtract (r[0] = r[1] - r[2]). | 81 | |MULN |\* |17 |Multiply (r[0] = r[1] \* r[2]). | 82 | |DIVN\* |/ |18 |Divide (r[0] = r[1] / r[2]). Faults if divisor is zero. | 83 | |INCN |^ |19 |Increment (r[0]++). | 84 | |DECN |v |20 |Decrement (r[0]--). | 85 | |NOTN |! |21 |Not (r[0] = !r[0]). | 86 | |SHFL |< |22 |Shift left by 1 (r[0] << 1). | 87 | |SHFR |> |23 |Shift right by 1 (r[0] >> 1). | 88 | |ZERO |z |24 |Put zero (r[0] = 0). | 89 | |UNIT |u |25 |Put one (r[0] = 1). | 90 | |PSHN |# |26 |Push r[0] to stack. | 91 | |POPN |~ |27 |Pop from stack into r[0]. | 92 | |LOAD\* |. |28 |Load instruction at address pointed by r[0] into r[1]. | 93 | |WRTE\* |: |29 |Write instruction on r[1] to address pointed by r[0]. | 94 | |DUPL |" |30 |Duplicate value on r[0] into r[1]. | 95 | |SWAP |x |31 |Swap values on r[0] and r[1]. | 96 | |KEYA-P |a-p |32-47 |Keys. | 97 | |LOKA-P |A-P |48-63 |Locks. | 98 | 99 | Instructions that may fault are marked with an asterisk (\*) on the table above. 100 | 101 | Instructions that modify values on registers may be followed by 102 | up to 3 register modifiers (r[0], r[1] and r[2]). By default, all registers 103 | are set to r0x. 104 | 105 | |Sample |r[0] |r[1] |r[2] |Meaning | 106 | |:-------|:----|:----|:----|-----------------------------------------:| 107 | |+123 |r1x |r2x |r3x |r1x = r2x + r3x | 108 | |-11 |r1x |r1x |r0x |r1x = r1x - r0x | 109 | |\* |r0x |r0x |r0x |r0x = r0x \* r0x | 110 | |!2 |r2x |--- |--- |r2x = !r2x | 111 | |x01 |r0x |r1x |--- |swap r0x and r1x | 112 | |]a1 |r1x |--- |--- |r1x = address of closest following LOKA | 113 | |[b |r0x |--- |--- |r0x = address of closest previous LOKB | 114 | 115 | ## Building instructions 116 | You'll need nothing but a C compiler (C89). If you want to build TSalis, 117 | you'll also need the NCurses development libraries. A sample makefile is 118 | provided for GNU Make. Just run `make` inside this directory and the salis 119 | library should compile as well as the tsalis executable. You may want to run 120 | `sudo make install` as well, in order to install the salis library as such: 121 | 122 | ``` 123 | $ git clone https://github.com/paultoliver/salis 124 | $ cd salis/ 125 | $ make 126 | $ sudo make install 127 | ``` 128 | 129 | To run, simply: 130 | 131 | ``` 132 | $ cd bin/ 133 | $ ./tsalis 134 | ``` 135 | 136 | Feel free to edit the makefile as needed. Code should compile easily on all 137 | platforms and on all C89 compliant compilers. If you run into any difficulties, 138 | please let me know! 139 | -------------------------------------------------------------------------------- /tsalis/src/printer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "printer.h" 6 | #include "tsalis.h" 7 | 8 | #define PROC_PAGE_LINES_BEFORE_LIST 16 9 | 10 | enum { 11 | PAIR_NORMAL = 1, 12 | PAIR_HEADER = 2, 13 | PAIR_SELECTED_PROC = 3, 14 | PAIR_FREE_CELL = 4, 15 | PAIR_ALLOC_CELL = 5, 16 | PAIR_MEM_BLOCK_START = 6, 17 | PAIR_MEM_BLOCK_2 = 7, 18 | PAIR_MEM_BLOCK_1 = 8, 19 | PAIR_SELECTED_SP = 9, 20 | PAIR_SELECTED_IP = 10 21 | }; 22 | 23 | enum { 24 | PAGE_MEMORY, 25 | PAGE_EVOLVER, 26 | PAGE_PROCESS, 27 | PAGE_WORLD, 28 | PAGE_COUNT 29 | }; 30 | 31 | const char *g_instNames[] = { 32 | #define SINST(name, symbol) #name, 33 | #define SILST(name, symbol) #name 34 | SINST_LIST 35 | #undef SINST 36 | #undef SILST 37 | }; 38 | 39 | const char g_instSymbols[] = { 40 | #define SINST(name, symbol) symbol, 41 | #define SILST(name, symbol) symbol 42 | SINST_LIST 43 | #undef SINST 44 | #undef SILST 45 | }; 46 | 47 | const char *g_procElems[] = { 48 | "mb1a", 49 | "mb1s", 50 | "mb2a", 51 | "mb2s", 52 | "ip", 53 | "sp", 54 | "reg[0]", 55 | "reg[1]", 56 | "reg[2]", 57 | "reg[3]", 58 | "stack[0]", 59 | "stack[1]", 60 | "stack[2]", 61 | "stack[3]", 62 | "stack[4]", 63 | "stack[5]", 64 | "stack[6]", 65 | "stack[7]" 66 | }; 67 | 68 | const int PROC_ELEMENT_COUNT = (sizeof(g_procElems) / sizeof(*g_procElems)); 69 | const int DATA_WIDTH = 25; 70 | 71 | int g_currentPage; 72 | sword g_selectedProcess; 73 | sbool g_processShowGenes; 74 | sword g_processVertScroll; 75 | sword g_processDataScroll; 76 | sword g_processGeneScroll; 77 | sword g_worldPos; 78 | sword g_worldZoom; 79 | sword g_worldLineWidth; 80 | sword g_worldLineCoverage; 81 | sword g_worldArea; 82 | 83 | static void 84 | adjustWorld(void) 85 | { 86 | g_worldLineWidth = COLS - DATA_WIDTH; 87 | g_worldLineCoverage = g_worldLineWidth * g_worldZoom; 88 | g_worldArea = LINES * g_worldLineCoverage; 89 | 90 | while ((g_worldArea > (sm_getSize() * 2)) && (g_worldZoom > 1)) { 91 | g_worldZoom /= 2; 92 | } 93 | } 94 | 95 | sbool 96 | tsp_check(void) 97 | { 98 | initscr(); 99 | 100 | if (!has_colors()) { 101 | endwin(); 102 | return SFALSE; 103 | } 104 | 105 | endwin(); 106 | return STRUE; 107 | } 108 | 109 | void 110 | tsp_init(void) 111 | { 112 | initscr(); 113 | cbreak(); 114 | noecho(); 115 | curs_set(0); 116 | keypad(stdscr, TRUE); 117 | start_color(); 118 | init_pair(PAIR_NORMAL, COLOR_WHITE, COLOR_BLACK); 119 | init_pair(PAIR_HEADER, COLOR_CYAN, COLOR_BLACK); 120 | init_pair(PAIR_SELECTED_PROC, COLOR_YELLOW, COLOR_BLACK); 121 | init_pair(PAIR_FREE_CELL, COLOR_CYAN, COLOR_BLUE); 122 | init_pair(PAIR_ALLOC_CELL, COLOR_BLUE, COLOR_CYAN); 123 | init_pair(PAIR_MEM_BLOCK_START, COLOR_BLUE, COLOR_WHITE); 124 | init_pair(PAIR_MEM_BLOCK_1, COLOR_BLACK, COLOR_YELLOW); 125 | init_pair(PAIR_MEM_BLOCK_2, COLOR_BLACK, COLOR_GREEN); 126 | init_pair(PAIR_SELECTED_SP, COLOR_BLACK, COLOR_MAGENTA); 127 | init_pair(PAIR_SELECTED_IP, COLOR_BLACK, COLOR_RED); 128 | g_worldZoom = 1; 129 | adjustWorld(); 130 | } 131 | 132 | void 133 | tsp_quit(void) 134 | { 135 | endwin(); 136 | } 137 | 138 | void 139 | tsp_onResize(void) 140 | { 141 | clear(); 142 | adjustWorld(); 143 | } 144 | 145 | void 146 | tsp_prevPage(void) 147 | { 148 | clear(); 149 | g_currentPage += (PAGE_COUNT - 1); 150 | g_currentPage %= PAGE_COUNT; 151 | } 152 | 153 | void 154 | tsp_nextPage(void) 155 | { 156 | clear(); 157 | g_currentPage++; 158 | g_currentPage %= PAGE_COUNT; 159 | } 160 | 161 | void 162 | tsp_scrollUp(void) 163 | { 164 | switch (g_currentPage) { 165 | case PAGE_PROCESS: 166 | if (g_processVertScroll) { 167 | g_processVertScroll--; 168 | } 169 | 170 | break; 171 | 172 | case PAGE_WORLD: 173 | if (g_worldPos >= g_worldLineCoverage) { 174 | g_worldPos -= g_worldLineCoverage; 175 | } else { 176 | g_worldPos = 0; 177 | } 178 | 179 | break; 180 | } 181 | 182 | refresh(); 183 | } 184 | 185 | void 186 | tsp_scrollDown(void) 187 | { 188 | switch (g_currentPage) { 189 | case PAGE_PROCESS: 190 | if (g_processVertScroll < (sp_getCap() - 1)) { 191 | g_processVertScroll++; 192 | } 193 | 194 | break; 195 | 196 | case PAGE_WORLD: 197 | if ((g_worldPos + g_worldLineCoverage) < sm_getSize()) { 198 | g_worldPos += g_worldLineCoverage; 199 | } 200 | 201 | break; 202 | } 203 | 204 | refresh(); 205 | } 206 | 207 | void 208 | tsp_fastScrollUp(void) 209 | { 210 | switch (g_currentPage) { 211 | case PAGE_PROCESS: { 212 | sword toScroll = LINES - PROC_PAGE_LINES_BEFORE_LIST; 213 | 214 | if (g_processVertScroll >= toScroll) { 215 | g_processVertScroll -= toScroll; 216 | } else { 217 | g_processVertScroll = 0; 218 | } 219 | } 220 | 221 | break; 222 | 223 | case PAGE_WORLD: 224 | if (g_worldPos >= g_worldArea) { 225 | g_worldPos -= g_worldArea; 226 | } else { 227 | g_worldPos = 0; 228 | } 229 | 230 | break; 231 | } 232 | 233 | refresh(); 234 | } 235 | 236 | void 237 | tsp_fastScrollDown(void) 238 | { 239 | switch (g_currentPage) { 240 | case PAGE_PROCESS: { 241 | sword toScroll = LINES - PROC_PAGE_LINES_BEFORE_LIST; 242 | 243 | if (g_processVertScroll < (sp_getCap() - toScroll)) { 244 | g_processVertScroll += toScroll; 245 | } 246 | } 247 | 248 | break; 249 | 250 | case PAGE_WORLD: 251 | if ((g_worldPos + g_worldArea) < sm_getSize()) { 252 | g_worldPos += g_worldArea; 253 | } 254 | 255 | break; 256 | } 257 | 258 | } 259 | 260 | void 261 | tsp_scrollLeft(void) 262 | { 263 | switch (g_currentPage) { 264 | case PAGE_PROCESS: 265 | if (g_processShowGenes) { 266 | if (g_processGeneScroll) { 267 | g_processGeneScroll--; 268 | } 269 | } else { 270 | if (g_processDataScroll) { 271 | g_processDataScroll--; 272 | } 273 | } 274 | 275 | break; 276 | 277 | case PAGE_WORLD: 278 | if (g_worldPos >= g_worldZoom) { 279 | g_worldPos -= g_worldZoom; 280 | } else { 281 | g_worldPos = 0; 282 | } 283 | 284 | break; 285 | } 286 | 287 | refresh(); 288 | } 289 | 290 | void 291 | tsp_scrollRight(void) 292 | { 293 | switch (g_currentPage) { 294 | case PAGE_PROCESS: 295 | if (g_processShowGenes) { 296 | g_processGeneScroll++; 297 | } else { 298 | if (g_processDataScroll < (sword)(PROC_ELEMENT_COUNT - 1)) { 299 | g_processDataScroll++; 300 | } 301 | } 302 | 303 | break; 304 | 305 | case PAGE_WORLD: 306 | if ((g_worldPos + g_worldZoom) < sm_getSize()) { 307 | g_worldPos += g_worldZoom; 308 | } 309 | 310 | break; 311 | } 312 | 313 | refresh(); 314 | } 315 | 316 | void 317 | tsp_scrollToTop(void) 318 | { 319 | switch (g_currentPage) { 320 | case PAGE_PROCESS: 321 | g_processVertScroll = 0; 322 | break; 323 | 324 | case PAGE_WORLD: 325 | g_worldPos = 0; 326 | break; 327 | } 328 | } 329 | 330 | void 331 | tsp_scrollToLeft(void) 332 | { 333 | switch (g_currentPage) { 334 | case PAGE_PROCESS: 335 | if (g_processShowGenes) { 336 | g_processGeneScroll = 0; 337 | } else { 338 | g_processDataScroll = 0; 339 | } 340 | 341 | break; 342 | } 343 | } 344 | 345 | void 346 | tsp_zoomIn(void) 347 | { 348 | if (g_currentPage == PAGE_WORLD) { 349 | if (g_worldZoom > 1) { 350 | g_worldZoom /= 2; 351 | } 352 | 353 | adjustWorld(); 354 | } 355 | } 356 | 357 | void 358 | tsp_zoomOut(void) 359 | { 360 | if (g_currentPage == PAGE_WORLD) { 361 | if (g_worldArea < sm_getSize()) { 362 | g_worldZoom *= 2; 363 | refresh(); 364 | } 365 | 366 | adjustWorld(); 367 | } 368 | } 369 | 370 | void 371 | tsp_prevOrganism(void) 372 | { 373 | switch (g_currentPage) { 374 | case PAGE_PROCESS: 375 | case PAGE_WORLD: 376 | if (g_selectedProcess < sp_getCap()) { 377 | g_selectedProcess += (sp_getCap() - 1); 378 | g_selectedProcess %= sp_getCap(); 379 | } 380 | 381 | break; 382 | } 383 | 384 | refresh(); 385 | } 386 | 387 | void 388 | tsp_nextOrganism(void) 389 | { 390 | switch (g_currentPage) { 391 | case PAGE_PROCESS: 392 | case PAGE_WORLD: 393 | if (g_selectedProcess < sp_getCap()) { 394 | g_selectedProcess++; 395 | g_selectedProcess %= sp_getCap(); 396 | } 397 | 398 | break; 399 | } 400 | 401 | refresh(); 402 | } 403 | 404 | void 405 | tsp_gotoSelectedProc(void) 406 | { 407 | switch (g_currentPage) { 408 | case PAGE_PROCESS: 409 | g_processVertScroll = g_selectedProcess; 410 | break; 411 | 412 | case PAGE_WORLD: 413 | g_worldPos = sp_getProc(g_selectedProcess).mb1a; 414 | break; 415 | } 416 | } 417 | 418 | void 419 | tsp_selectProcess(sword proc) 420 | { 421 | if (proc < sp_getCap()) { 422 | g_selectedProcess = proc; 423 | } 424 | } 425 | 426 | void 427 | tsp_moveTo(sword loc) 428 | { 429 | switch (g_currentPage) { 430 | case PAGE_PROCESS: 431 | if (loc < sp_getCap()) { 432 | g_processVertScroll = loc; 433 | } 434 | 435 | break; 436 | 437 | case PAGE_WORLD: 438 | if (loc < sm_getSize()) { 439 | g_worldPos = loc; 440 | } 441 | 442 | break; 443 | } 444 | } 445 | 446 | static void 447 | printWidget(int line, const char *format, ...) 448 | { 449 | if (line < LINES) { 450 | va_list args; 451 | char dataLine[24]; 452 | va_start(args, format); 453 | vsprintf(dataLine, format, args); 454 | mvprintw(line, 1, "%.*s", COLS - 1, dataLine); 455 | va_end(args); 456 | } 457 | } 458 | 459 | static void 460 | printHeader(int line, const char *string) 461 | { 462 | attron(COLOR_PAIR(PAIR_HEADER)); 463 | printWidget(line, string); 464 | attron(COLOR_PAIR(PAIR_NORMAL)); 465 | } 466 | 467 | #define PHEADER(label) printHeader((*line)++, label) 468 | #define PWIDGET(label, data) printWidget((*line)++, "%-10s : %10u", label, data) 469 | #define PSIDGET(label, data) printWidget((*line)++, "%-10s : %10s", label, data) 470 | #define INCREMENT_LINE (*line)++ 471 | 472 | static void 473 | printMemoryPage(int *line) 474 | { 475 | PHEADER("MEMORY"); 476 | PWIDGET("order", sm_getOrder()); 477 | PWIDGET("size", sm_getSize()); 478 | PWIDGET("blocks", sm_getMemBlockCount()); 479 | PWIDGET("alloc", sm_getAllocated()); 480 | PWIDGET("cap", sm_getCap()); 481 | } 482 | 483 | static void 484 | printEvolverPage(int *line) 485 | { 486 | PHEADER("EVOLVER"); 487 | PWIDGET("lastAddr", se_getLastAddress()); 488 | PSIDGET("lastInst", g_instNames[se_getLastInst()] + 1); 489 | PWIDGET("state0", se_getState(0)); 490 | PWIDGET("state1", se_getState(1)); 491 | PWIDGET("state2", se_getState(2)); 492 | PWIDGET("state3", se_getState(3)); 493 | } 494 | 495 | static void 496 | printField(int y, int x, const char *field, sbool lalign) 497 | { 498 | if ((y < LINES) && (x < COLS)) { 499 | if (lalign) { 500 | mvprintw(y, x, "%-.*s", COLS - x, field); 501 | } else { 502 | mvprintw(y, x, "%.*s", COLS - x, field); 503 | } 504 | } 505 | } 506 | 507 | static void 508 | printSingleProcessGenome(int line, sword pidx) 509 | { 510 | char sidx[13]; 511 | SProc proc = sp_getProc(pidx); 512 | sword gidx = g_processGeneScroll; 513 | int xpos = 14; 514 | 515 | if (pidx == g_selectedProcess) { 516 | attron(COLOR_PAIR(PAIR_SELECTED_PROC)); 517 | } else if (!sp_isFree(pidx)) { 518 | attron(COLOR_PAIR(PAIR_HEADER)); 519 | } 520 | 521 | sprintf(sidx, "%-10u |", pidx); 522 | printField(line, 1, sidx, STRUE); 523 | move(line, xpos); 524 | 525 | while ((gidx < proc.mb1s) && (xpos < COLS)) { 526 | sword gaddr = proc.mb1a + gidx; 527 | 528 | if (gaddr == proc.ip) { 529 | attron(COLOR_PAIR(PAIR_SELECTED_IP)); 530 | } else if (gaddr == proc.sp) { 531 | attron(COLOR_PAIR(PAIR_SELECTED_SP)); 532 | } else { 533 | attron(COLOR_PAIR(PAIR_MEM_BLOCK_1)); 534 | } 535 | 536 | addch(g_instSymbols[sm_getInstAt(gaddr)]); 537 | gidx++; 538 | xpos++; 539 | } 540 | 541 | if (proc.mb1s < g_processGeneScroll) { 542 | gidx = g_processGeneScroll - proc.mb1s; 543 | } else { 544 | gidx = 0; 545 | } 546 | 547 | while ((gidx < proc.mb2s) && (xpos < COLS)) { 548 | sword gaddr = proc.mb2a + gidx; 549 | 550 | if (gaddr == proc.ip) { 551 | attron(COLOR_PAIR(PAIR_SELECTED_IP)); 552 | } else if (gaddr == proc.sp) { 553 | attron(COLOR_PAIR(PAIR_SELECTED_SP)); 554 | } else { 555 | attron(COLOR_PAIR(PAIR_MEM_BLOCK_2)); 556 | } 557 | 558 | addch(g_instSymbols[sm_getInstAt(gaddr)]); 559 | gidx++; 560 | xpos++; 561 | } 562 | 563 | attron(COLOR_PAIR(PAIR_NORMAL)); 564 | } 565 | 566 | static void 567 | printProcessGenes(int *line) 568 | { 569 | sword pidx = g_processVertScroll; 570 | attron(COLOR_PAIR(PAIR_HEADER)); 571 | printField(*line, 1, "pidx", STRUE); 572 | 573 | attron(COLOR_PAIR(PAIR_NORMAL)); 574 | INCREMENT_LINE; 575 | 576 | while ((*line < LINES) && (pidx < sp_getCap())) { 577 | printSingleProcessGenome(*line, pidx); 578 | INCREMENT_LINE; 579 | pidx++; 580 | } 581 | 582 | attron(COLOR_PAIR(PAIR_NORMAL)); 583 | } 584 | 585 | static void 586 | printSingleProcessData(int line, sword pidx) 587 | { 588 | char sidx[11]; 589 | int eidx = g_processDataScroll; 590 | int xpos = 12; 591 | SProc proc = sp_getProc(pidx); 592 | sword *data = (sword *)&proc; 593 | 594 | if (pidx == g_selectedProcess) { 595 | attron(COLOR_PAIR(PAIR_SELECTED_PROC)); 596 | } else if (!sp_isFree(pidx)) { 597 | attron(COLOR_PAIR(PAIR_HEADER)); 598 | } 599 | 600 | sprintf(sidx, "%u", pidx); 601 | printField(line, 1, sidx, STRUE); 602 | 603 | while (eidx < PROC_ELEMENT_COUNT) { 604 | char element[13]; 605 | sprintf(element, "| %10u", data[eidx]); 606 | printField(line, xpos, element, SFALSE); 607 | eidx++; 608 | xpos += 13; 609 | } 610 | 611 | attron(COLOR_PAIR(PAIR_NORMAL)); 612 | } 613 | 614 | static void 615 | printProcessData(int *line) 616 | { 617 | sword pidx = g_processVertScroll; 618 | int eidx = g_processDataScroll; 619 | int xpos = 12; 620 | attron(COLOR_PAIR(PAIR_HEADER)); 621 | printField(*line, 1, "pidx", STRUE); 622 | 623 | while (eidx < PROC_ELEMENT_COUNT) { 624 | char element[13]; 625 | sprintf(element, "| %10s", g_procElems[eidx]); 626 | printField(*line, xpos, element, SFALSE); 627 | eidx++; 628 | xpos += 13; 629 | } 630 | 631 | attron(COLOR_PAIR(PAIR_NORMAL)); 632 | INCREMENT_LINE; 633 | 634 | while ((*line < LINES) && (pidx < sp_getCap())) { 635 | printSingleProcessData(*line, pidx); 636 | INCREMENT_LINE; 637 | pidx++; 638 | } 639 | 640 | attron(COLOR_PAIR(PAIR_NORMAL)); 641 | } 642 | 643 | static void 644 | printProcessPage(int *line) 645 | { 646 | int cline; 647 | sbool fnull = (sp_getFirst() == (sword) - 1); 648 | sbool lnull = (sp_getLast() == (sword) - 1); 649 | PHEADER("PROCESS"); 650 | PWIDGET("count", sp_getCount()); 651 | PWIDGET("cap", sp_getCap()); 652 | fnull ? PSIDGET("first", "---") : PWIDGET("first", sp_getFirst()); 653 | lnull ? PSIDGET("last", "---") : PWIDGET("last", sp_getLast()); 654 | PWIDGET("selected", g_selectedProcess); 655 | INCREMENT_LINE; 656 | 657 | for (cline = *line; cline < LINES; cline++) { 658 | move(cline, 0); 659 | clrtoeol(); 660 | } 661 | 662 | if (g_processShowGenes) { 663 | printProcessGenes(line); 664 | } else { 665 | printProcessData(line); 666 | } 667 | } 668 | 669 | static int 670 | getColorOf(sword addr) 671 | { 672 | if (!sp_isFree(g_selectedProcess)) { 673 | SProc proc = sp_getProc(g_selectedProcess); 674 | 675 | if (addr == proc.ip) { 676 | return PAIR_SELECTED_IP; 677 | } else if (addr == proc.sp) { 678 | return PAIR_SELECTED_SP; 679 | } else if ((addr >= proc.mb1a) && (addr < (proc.mb1a + proc.mb1s))) { 680 | return PAIR_MEM_BLOCK_1; 681 | } else if ((addr >= proc.mb2a) && (addr < (proc.mb2a + proc.mb2s))) { 682 | return PAIR_MEM_BLOCK_2; 683 | } 684 | } 685 | 686 | if (sm_isMemBlockStartAt(addr)) { 687 | return PAIR_MEM_BLOCK_START; 688 | } else if (sm_isAllocatedAt(addr)) { 689 | return PAIR_ALLOC_CELL; 690 | } else { 691 | return PAIR_FREE_CELL; 692 | } 693 | } 694 | 695 | static void 696 | printWorld(void) 697 | { 698 | sword y; 699 | 700 | for (y = 0; y < (sword)LINES; y++) { 701 | sword x; 702 | 703 | for (x = 0; x < g_worldLineWidth; x++) { 704 | sword addr = g_worldPos + (((y * g_worldLineWidth) + x) * g_worldZoom); 705 | sbool atEnd = !sm_isValidAt(addr); 706 | int xpos = DATA_WIDTH + x; 707 | 708 | if (atEnd) { 709 | mvaddch(y, xpos, ' '); 710 | continue; 711 | } 712 | 713 | if (g_worldZoom == 1) { 714 | char symbol = g_instSymbols[sm_getInstAt(addr)]; 715 | attron(COLOR_PAIR(getColorOf(addr))); 716 | mvaddch(y, xpos, symbol); 717 | } else { 718 | sword offset; 719 | char symbol; 720 | sword instSum = 0; 721 | int color = PAIR_FREE_CELL; 722 | 723 | for (offset = 0; offset < g_worldZoom; offset++) { 724 | int testColor; 725 | sword offsetAddr = addr + offset; 726 | 727 | if (!sm_isValidAt(offsetAddr)) { 728 | break; 729 | } 730 | 731 | instSum += sm_getInstAt(offsetAddr); 732 | testColor = getColorOf(offsetAddr); 733 | 734 | if (testColor > color) { 735 | color = testColor; 736 | } 737 | } 738 | 739 | instSum /= g_worldZoom; 740 | 741 | if (!instSum) { 742 | symbol = ' '; 743 | } else if (instSum < 32) { 744 | symbol = '-'; 745 | } else { 746 | symbol = '='; 747 | } 748 | 749 | attron(COLOR_PAIR(color)); 750 | mvaddch(y, xpos, symbol); 751 | } 752 | 753 | attron(COLOR_PAIR(PAIR_NORMAL)); 754 | } 755 | } 756 | } 757 | 758 | static void 759 | printWorldPage(int *line) 760 | { 761 | int eidx; 762 | SProc proc = sp_getProc(g_selectedProcess); 763 | sword *data = (sword *)&proc; 764 | PHEADER("WORLD"); 765 | PWIDGET("pos", g_worldPos); 766 | PWIDGET("zoom", g_worldZoom); 767 | PWIDGET("selected", g_selectedProcess); 768 | INCREMENT_LINE; 769 | PHEADER("SELECTED"); 770 | 771 | if (!sp_isFree(g_selectedProcess)) { 772 | attron(COLOR_PAIR(PAIR_SELECTED_PROC)); 773 | } 774 | 775 | for (eidx = 0; eidx < PROC_ELEMENT_COUNT; eidx++) { 776 | PWIDGET(g_procElems[eidx], data[eidx]); 777 | } 778 | 779 | attron(COLOR_PAIR(PAIR_NORMAL)); 780 | printWorld(); 781 | } 782 | 783 | void 784 | tsp_printData(void) 785 | { 786 | int linev = 1; 787 | int *line = &linev; 788 | PHEADER("SALIS"); 789 | 790 | if (strlen(g_simName) < 24) { 791 | PHEADER(g_simName); 792 | } else { 793 | attron(COLOR_PAIR(PAIR_HEADER)); 794 | printWidget((*line)++, "%.20s...", g_simName); 795 | attron(COLOR_PAIR(PAIR_NORMAL)); 796 | } 797 | 798 | PSIDGET("state", g_running ? "running" : "paused"); 799 | 800 | if (g_autoSaveInterval) { 801 | PWIDGET("autosave", g_autoSaveInterval); 802 | } else { 803 | PSIDGET("autosave", "---"); 804 | } 805 | 806 | PWIDGET("cycle", s_getCycle()); 807 | PWIDGET("epoch", s_getEpoch()); 808 | INCREMENT_LINE; 809 | 810 | switch (g_currentPage) { 811 | case PAGE_MEMORY: 812 | printMemoryPage(line); 813 | break; 814 | 815 | case PAGE_EVOLVER: 816 | printEvolverPage(line); 817 | break; 818 | 819 | case PAGE_PROCESS: 820 | printProcessPage(line); 821 | break; 822 | 823 | case PAGE_WORLD: 824 | printWorldPage(line); 825 | break; 826 | } 827 | 828 | refresh(); 829 | } 830 | -------------------------------------------------------------------------------- /src/process.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "types.h" 6 | #include "instset.h" 7 | #include "memory.h" 8 | #include "process.h" 9 | #include "evolver.h" 10 | 11 | static sbool g_isInit; 12 | static sword g_count; 13 | static sword g_cap; 14 | static sword g_first; 15 | static sword g_last; 16 | static SProc *g_procs; 17 | 18 | void 19 | sp_init(void) 20 | { 21 | assert(!g_isInit); 22 | g_isInit = STRUE; 23 | g_cap = 1; 24 | g_first = SNULL; 25 | g_last = SNULL; 26 | g_procs = calloc(g_cap, sizeof(SProc)); 27 | assert(g_procs); 28 | } 29 | 30 | void 31 | sp_quit(void) 32 | { 33 | assert(g_isInit); 34 | free(g_procs); 35 | g_isInit = SFALSE; 36 | g_count = 0; 37 | g_cap = 0; 38 | g_first = 0; 39 | g_last = 0; 40 | g_procs = NULL; 41 | } 42 | 43 | void 44 | sp_load(FILE *file) 45 | { 46 | assert(!g_isInit); 47 | assert(file); 48 | fread(&g_isInit, sizeof(sbool), 1, file); 49 | fread(&g_count, sizeof(sword), 1, file); 50 | fread(&g_cap, sizeof(sword), 1, file); 51 | fread(&g_first, sizeof(sword), 1, file); 52 | fread(&g_last, sizeof(sword), 1, file); 53 | g_procs = calloc(g_cap, sizeof(SProc)); 54 | assert(g_procs); 55 | fread(g_procs, sizeof(SProc), g_cap, file); 56 | } 57 | 58 | void 59 | sp_save(FILE *file) 60 | { 61 | assert(g_isInit); 62 | assert(file); 63 | fwrite(&g_isInit, sizeof(sbool), 1, file); 64 | fwrite(&g_count, sizeof(sword), 1, file); 65 | fwrite(&g_cap, sizeof(sword), 1, file); 66 | fwrite(&g_first, sizeof(sword), 1, file); 67 | fwrite(&g_last, sizeof(sword), 1, file); 68 | fwrite(g_procs, sizeof(SProc), g_cap, file); 69 | } 70 | 71 | sbool 72 | sp_isInit(void) 73 | { 74 | return g_isInit; 75 | } 76 | 77 | sword 78 | sp_getCount(void) 79 | { 80 | return g_count; 81 | } 82 | 83 | sword 84 | sp_getCap(void) 85 | { 86 | return g_cap; 87 | } 88 | 89 | sword 90 | sp_getFirst(void) 91 | { 92 | return g_first; 93 | } 94 | 95 | sword 96 | sp_getLast(void) 97 | { 98 | return g_last; 99 | } 100 | 101 | sbool 102 | sp_isFree(sword pidx) 103 | { 104 | sbool isFree; 105 | assert(g_isInit); 106 | assert(pidx < g_cap); 107 | isFree = !(g_procs[pidx].mb1s); 108 | #ifndef NDEBUG 109 | 110 | if (isFree) { 111 | assert(!g_procs[pidx].mb1a); 112 | assert(!g_procs[pidx].mb2a); 113 | assert(!g_procs[pidx].mb2s); 114 | } 115 | 116 | #endif 117 | return isFree; 118 | } 119 | 120 | SProc 121 | sp_getProc(sword pidx) 122 | { 123 | assert(g_isInit); 124 | assert(pidx < g_cap); 125 | return g_procs[pidx]; 126 | } 127 | 128 | void 129 | sp_setProc(sword pidx, SProc proc) 130 | { 131 | assert(g_isInit); 132 | assert(pidx < g_cap); 133 | assert(!sp_isFree(pidx)); 134 | g_procs[pidx] = proc; 135 | } 136 | 137 | static void 138 | reallocQueue(sword queueLock) 139 | { 140 | sword newCap; 141 | SProc *newQueue; 142 | sword fidx; 143 | sword bidx; 144 | assert(g_isInit); 145 | assert(g_count == g_cap); 146 | assert(queueLock < g_cap); 147 | newCap = g_cap * 2; 148 | newQueue = calloc(newCap, sizeof(SProc)); 149 | assert(newQueue); 150 | fidx = queueLock; 151 | bidx = (queueLock - 1) % newCap; 152 | 153 | /* copy all forward from lock */ 154 | while (STRUE) { 155 | sword oldIdx = fidx % g_cap; 156 | memcpy(&newQueue[fidx], &g_procs[oldIdx], sizeof(SProc)); 157 | 158 | if (oldIdx == g_last) { 159 | g_last = fidx; 160 | break; 161 | } else { 162 | fidx++; 163 | } 164 | } 165 | 166 | if (queueLock != g_first) { 167 | /* copy all backward from lock */ 168 | while (STRUE) { 169 | sword oldIdx = bidx % g_cap; 170 | memcpy(&newQueue[bidx], &g_procs[oldIdx], sizeof(SProc)); 171 | 172 | if (oldIdx == g_first) { 173 | g_first = bidx; 174 | break; 175 | } else { 176 | bidx--; 177 | bidx %= newCap; 178 | } 179 | } 180 | } 181 | 182 | free(g_procs); 183 | g_cap = newCap; 184 | g_procs = newQueue; 185 | } 186 | 187 | static sword 188 | getNewProc(sword queueLock) 189 | { 190 | assert(g_isInit); 191 | 192 | if (g_count == g_cap) { 193 | reallocQueue(queueLock); 194 | } 195 | 196 | g_count++; 197 | 198 | if (g_count == 1) { 199 | g_first = 0; 200 | g_last = 0; 201 | return 0; 202 | } else { 203 | g_last++; 204 | g_last %= g_cap; 205 | return g_last; 206 | } 207 | } 208 | 209 | static void 210 | create(sword addr, sword size, sword queueLock, sbool allocate) 211 | { 212 | sword pidx; 213 | assert(g_isInit); 214 | assert(sm_isValidAt(addr)); 215 | assert(sm_isValidAt(addr + size - 1)); 216 | 217 | if (allocate) { 218 | sword offset; 219 | 220 | for (offset = 0; offset < size; offset++) { 221 | sword naddr = addr + offset; 222 | assert(!sm_isAllocatedAt(naddr)); 223 | assert(!sm_isMemBlockStartAt(naddr)); 224 | sm_allocateAt(naddr); 225 | } 226 | 227 | sm_setMemBlockStartAt(addr); 228 | } 229 | 230 | pidx = getNewProc(queueLock); 231 | g_procs[pidx].mb1a = addr; 232 | g_procs[pidx].mb1s = size; 233 | g_procs[pidx].ip = addr; 234 | g_procs[pidx].sp = addr; 235 | } 236 | 237 | void 238 | sp_create(sword addr, sword size) 239 | { 240 | assert(g_isInit); 241 | assert(sm_isValidAt(addr)); 242 | assert(sm_isValidAt(addr + size - 1)); 243 | create(addr, size, 0, STRUE); 244 | } 245 | 246 | static void 247 | freeMemBlock(sword addr, sword size) 248 | { 249 | sword offset; 250 | assert(sm_isValidAt(addr)); 251 | assert(sm_isValidAt(addr + size - 1)); 252 | assert(size); 253 | assert(sm_isMemBlockStartAt(addr)); 254 | sm_unsetMemBlockStartAt(addr); 255 | 256 | for (offset = 0; offset < size; offset++) { 257 | sword oaddr = addr + offset; 258 | assert(sm_isValidAt(oaddr)); 259 | assert(sm_isAllocatedAt(oaddr)); 260 | assert(!sm_isMemBlockStartAt(oaddr)); 261 | sm_freeAt(oaddr); 262 | } 263 | } 264 | 265 | static void 266 | freeMemOwnedBy(sword pidx) 267 | { 268 | assert(g_isInit); 269 | assert(pidx < g_cap); 270 | assert(!sp_isFree(pidx)); 271 | freeMemBlock(g_procs[pidx].mb1a, g_procs[pidx].mb1s); 272 | 273 | if (g_procs[pidx].mb2s) { 274 | assert(g_procs[pidx].mb1a != g_procs[pidx].mb2a); 275 | freeMemBlock(g_procs[pidx].mb2a, g_procs[pidx].mb2s); 276 | } 277 | } 278 | 279 | void 280 | sp_kill(void) 281 | { 282 | assert(g_isInit); 283 | assert(g_count); 284 | assert(g_first != SNULL); 285 | assert(g_last != SNULL); 286 | assert(!sp_isFree(g_first)); 287 | freeMemOwnedBy(g_first); 288 | memset(&g_procs[g_first], 0, sizeof(SProc)); 289 | g_count--; 290 | 291 | if (g_first == g_last) { 292 | g_first = SNULL; 293 | g_last = SNULL; 294 | return; 295 | } 296 | 297 | g_first++; 298 | g_first %= g_cap; 299 | } 300 | 301 | static void 302 | incrementIP(sword pidx) 303 | { 304 | assert(g_isInit); 305 | assert(pidx < g_cap); 306 | assert(!sp_isFree(pidx)); 307 | g_procs[pidx].ip++; 308 | g_procs[pidx].sp = g_procs[pidx].ip; 309 | } 310 | 311 | static void 312 | onFault(sword pidx) 313 | { 314 | sword ip; 315 | assert(g_isInit); 316 | assert(pidx < g_cap); 317 | assert(!sp_isFree(pidx)); 318 | ip = sp_getProc(pidx).ip; 319 | assert(sm_isValidAt(ip)); 320 | se_randomizeAt(ip); 321 | } 322 | 323 | static sbool 324 | seek(sword pidx, sbool forward) 325 | { 326 | sword nextAddr; 327 | sbyte nextInst; 328 | sbyte spInst; 329 | assert(g_isInit); 330 | assert(pidx < g_cap); 331 | assert(!sp_isFree(pidx)); 332 | nextAddr = g_procs[pidx].ip + 1; 333 | 334 | if (!sm_isValidAt(nextAddr)) { 335 | onFault(pidx); 336 | incrementIP(pidx); 337 | return SFALSE; 338 | } 339 | 340 | nextInst = sm_getInstAt(nextAddr); 341 | 342 | if (!si_isKey(nextInst)) { 343 | onFault(pidx); 344 | incrementIP(pidx); 345 | return SFALSE; 346 | } 347 | 348 | spInst = sm_getInstAt(g_procs[pidx].sp); 349 | 350 | if (si_keyLockMatch(nextInst, spInst)) { 351 | return STRUE; 352 | } 353 | 354 | if (forward) { 355 | g_procs[pidx].sp++; 356 | } else { 357 | g_procs[pidx].sp--; 358 | } 359 | 360 | return SFALSE; 361 | } 362 | 363 | static void 364 | jump(sword pidx) 365 | { 366 | #ifndef NDEBUG 367 | sbyte nextInst; 368 | sbyte spInst; 369 | #endif 370 | assert(g_isInit); 371 | assert(pidx < g_cap); 372 | assert(!sp_isFree(pidx)); 373 | #ifndef NDEBUG 374 | nextInst = sm_getInstAt(g_procs[pidx].ip + 1); 375 | spInst = sm_getInstAt(g_procs[pidx].sp); 376 | assert(si_isKey(nextInst)); 377 | assert(si_isLock(spInst)); 378 | assert(si_keyLockMatch(nextInst, spInst)); 379 | #endif 380 | g_procs[pidx].ip = g_procs[pidx].sp; 381 | } 382 | 383 | static sword * 384 | getRegAddr(sword pidx, sword modAddr) 385 | { 386 | sbyte modInst; 387 | sbyte modOffset; 388 | assert(g_isInit); 389 | assert(pidx < g_cap); 390 | assert(!sp_isFree(pidx)); 391 | assert(sm_isValidAt(modAddr)); 392 | modInst = sm_getInstAt(modAddr); 393 | assert(si_isMod(modInst)); 394 | modOffset = modInst - SNOP0; 395 | assert(modOffset < SPROC_REG_COUNT); 396 | return &(g_procs[pidx].regs[modOffset]); 397 | } 398 | 399 | static void 400 | getRegAddrList(sword pidx, sword **regList, sword regCount, sbool offset) 401 | { 402 | sword modAddr; 403 | sbyte ridx; 404 | assert(g_isInit); 405 | assert(pidx < g_cap); 406 | assert(!sp_isFree(pidx)); 407 | assert(regList); 408 | assert(regCount); 409 | assert(regCount < 4); 410 | 411 | if (offset) { 412 | modAddr = g_procs[pidx].ip + 2; 413 | } else { 414 | modAddr = g_procs[pidx].ip + 1; 415 | } 416 | 417 | for (ridx = 0; ridx < regCount; ridx++) { 418 | regList[ridx] = &(g_procs[pidx].regs[0]); 419 | } 420 | 421 | for (ridx = 0; ridx < regCount; ridx++) { 422 | sword modNext = modAddr + ridx; 423 | 424 | if (!sm_isValidAt(modNext)) { 425 | break; 426 | } else { 427 | sword modInst = sm_getInstAt(modNext); 428 | 429 | if (!si_isMod(modInst)) { 430 | break; 431 | } else { 432 | regList[ridx] = getRegAddr(pidx, modNext); 433 | } 434 | } 435 | } 436 | } 437 | 438 | static void 439 | addr(sword pidx) 440 | { 441 | #ifndef NDEBUG 442 | sbyte nextInst; 443 | sbyte spInst; 444 | #endif 445 | sword *reg; 446 | assert(g_isInit); 447 | assert(pidx < g_cap); 448 | assert(!sp_isFree(pidx)); 449 | #ifndef NDEBUG 450 | nextInst = sm_getInstAt(g_procs[pidx].ip + 1); 451 | spInst = sm_getInstAt(g_procs[pidx].sp); 452 | assert(si_isKey(nextInst)); 453 | assert(si_isLock(spInst)); 454 | assert(si_keyLockMatch(nextInst, spInst)); 455 | #endif 456 | getRegAddrList(pidx, ®, 1, STRUE); 457 | *reg = g_procs[pidx].sp; 458 | incrementIP(pidx); 459 | } 460 | 461 | static void 462 | ifnz(sword pidx) 463 | { 464 | sword *reg; 465 | sword jumpMod; 466 | sword nextAddr; 467 | assert(g_isInit); 468 | assert(pidx < g_cap); 469 | assert(!sp_isFree(pidx)); 470 | getRegAddrList(pidx, ®, 1, SFALSE); 471 | nextAddr = g_procs[pidx].ip + 1; 472 | 473 | if (sm_isValidAt(nextAddr)) { 474 | sbyte nextInst = sm_getInstAt(nextAddr); 475 | sbool nextInstIsMod = si_isMod(nextInst); 476 | 477 | if (nextInstIsMod) { 478 | jumpMod = 1; 479 | } else { 480 | jumpMod = 0; 481 | } 482 | } else { 483 | jumpMod = 0; 484 | } 485 | 486 | if (*reg) { 487 | /* execute next instruction */ 488 | g_procs[pidx].ip += (jumpMod + 1); 489 | } else { 490 | /* skip next instruction */ 491 | g_procs[pidx].ip += (jumpMod + 2); 492 | } 493 | 494 | g_procs[pidx].sp = g_procs[pidx].ip; 495 | } 496 | 497 | static void 498 | freeMemBlock2Of(sword pidx) 499 | { 500 | assert(g_isInit); 501 | assert(pidx < g_cap); 502 | assert(!sp_isFree(pidx)); 503 | assert(g_procs[pidx].mb2s); 504 | freeMemBlock(g_procs[pidx].mb2a, g_procs[pidx].mb2s); 505 | g_procs[pidx].mb2a = 0; 506 | g_procs[pidx].mb2s = 0; 507 | } 508 | 509 | static void 510 | alloc(sword pidx, sbool forward) 511 | { 512 | sword *regs[2]; 513 | sword blockSize; 514 | assert(g_isInit); 515 | assert(pidx < g_cap); 516 | assert(!sp_isFree(pidx)); 517 | getRegAddrList(pidx, regs, 2, SFALSE); 518 | blockSize = *regs[0]; 519 | 520 | /* check for possible errors */ 521 | /* ignore if requested block size is zero */ 522 | if (!blockSize) { 523 | incrementIP(pidx); 524 | return; 525 | } 526 | 527 | /* ignore if sp is not adjacent to already existing memory block */ 528 | if (g_procs[pidx].mb2s) { 529 | sword correctAddr = g_procs[pidx].mb2a; 530 | 531 | if (forward) { 532 | correctAddr += g_procs[pidx].mb2s; 533 | } else { 534 | correctAddr--; 535 | } 536 | 537 | if (g_procs[pidx].sp != correctAddr) { 538 | onFault(pidx); 539 | incrementIP(pidx); 540 | return; 541 | } 542 | } 543 | 544 | /* on successful allocation */ 545 | /* increment ip and save new block's address on register */ 546 | if (g_procs[pidx].mb2s == blockSize) { 547 | incrementIP(pidx); 548 | *regs[1] = g_procs[pidx].mb2a; 549 | return; 550 | } 551 | 552 | /* handle block enlargement */ 553 | /* handle sp collision with allocated space */ 554 | if (sm_isAllocatedAt(g_procs[pidx].sp)) { 555 | if (g_procs[pidx].mb2s) { 556 | freeMemBlock2Of(pidx); 557 | } 558 | 559 | if (forward) { 560 | g_procs[pidx].sp++; 561 | } else { 562 | g_procs[pidx].sp--; 563 | } 564 | 565 | return; 566 | } 567 | 568 | /* enlarge block when no collision occurs */ 569 | sm_allocateAt(g_procs[pidx].sp); 570 | 571 | /* correct memory block start flag address */ 572 | if (!g_procs[pidx].mb2s) { 573 | g_procs[pidx].mb2a = g_procs[pidx].sp; 574 | sm_setMemBlockStartAt(g_procs[pidx].sp); 575 | } else { 576 | if (!forward) { 577 | sm_unsetMemBlockStartAt(g_procs[pidx].mb2a); 578 | g_procs[pidx].mb2a = g_procs[pidx].sp; 579 | sm_setMemBlockStartAt(g_procs[pidx].mb2a); 580 | } 581 | } 582 | 583 | g_procs[pidx].mb2s++; 584 | 585 | /* move sp to next location */ 586 | if (forward) { 587 | g_procs[pidx].sp++; 588 | } else { 589 | g_procs[pidx].sp--; 590 | } 591 | } 592 | 593 | static void 594 | bswap(sword pidx) 595 | { 596 | assert(g_isInit); 597 | assert(pidx < g_cap); 598 | assert(!sp_isFree(pidx)); 599 | 600 | if (g_procs[pidx].mb2s) { 601 | sword addrTmp = g_procs[pidx].mb1a; 602 | sword sizeTmp = g_procs[pidx].mb1s; 603 | g_procs[pidx].mb1a = g_procs[pidx].mb2a; 604 | g_procs[pidx].mb1s = g_procs[pidx].mb2s; 605 | g_procs[pidx].mb2a = addrTmp; 606 | g_procs[pidx].mb2s = sizeTmp; 607 | } else { 608 | onFault(pidx); 609 | } 610 | 611 | incrementIP(pidx); 612 | } 613 | 614 | static void 615 | bclear(sword pidx) 616 | { 617 | assert(g_isInit); 618 | assert(pidx < g_cap); 619 | assert(!sp_isFree(pidx)); 620 | 621 | if (g_procs[pidx].mb2s) { 622 | freeMemBlock2Of(pidx); 623 | } else { 624 | onFault(pidx); 625 | } 626 | 627 | incrementIP(pidx); 628 | } 629 | 630 | static void 631 | split(sword pidx) 632 | { 633 | assert(g_isInit); 634 | assert(pidx < g_cap); 635 | assert(!sp_isFree(pidx)); 636 | 637 | if (g_procs[pidx].mb2s) { 638 | create(g_procs[pidx].mb2a, g_procs[pidx].mb2s, pidx, SFALSE); 639 | g_procs[pidx].mb2a = 0; 640 | g_procs[pidx].mb2s = 0; 641 | } else { 642 | onFault(pidx); 643 | } 644 | 645 | incrementIP(pidx); 646 | } 647 | 648 | static void 649 | r3op(sword pidx, sbyte inst) 650 | { 651 | sword *regs[3]; 652 | assert(g_isInit); 653 | assert(pidx < g_cap); 654 | assert(!sp_isFree(pidx)); 655 | getRegAddrList(pidx, regs, 3, SFALSE); 656 | 657 | /* fault when dividing by zero */ 658 | if ((inst == SDIVN) && (*regs[2] == 0)) { 659 | onFault(pidx); 660 | incrementIP(pidx); 661 | return; 662 | } 663 | 664 | switch (inst) { 665 | case SADDN: 666 | *regs[0] = *regs[1] + *regs[2]; 667 | break; 668 | 669 | case SSUBN: 670 | *regs[0] = *regs[1] - *regs[2]; 671 | break; 672 | 673 | case SMULN: 674 | *regs[0] = *regs[1] * *regs[2]; 675 | break; 676 | 677 | case SDIVN: 678 | assert(*regs[2]); 679 | *regs[0] = *regs[1] / *regs[2]; 680 | break; 681 | 682 | default: 683 | assert(0); 684 | } 685 | 686 | incrementIP(pidx); 687 | } 688 | 689 | static void 690 | r1op(sword pidx, sbyte inst) 691 | { 692 | sword *reg; 693 | assert(g_isInit); 694 | assert(pidx < g_cap); 695 | assert(!sp_isFree(pidx)); 696 | getRegAddrList(pidx, ®, 1, SFALSE); 697 | 698 | switch (inst) { 699 | case SINCN: 700 | (*reg)++; 701 | break; 702 | 703 | case SDECN: 704 | (*reg)--; 705 | break; 706 | 707 | case SNOTN: 708 | *reg = !(*reg); 709 | break; 710 | 711 | case SSHFL: 712 | *reg <<= 1; 713 | break; 714 | 715 | case SSHFR: 716 | *reg >>= 1; 717 | break; 718 | 719 | case SZERO: 720 | *reg = 0; 721 | break; 722 | 723 | case SUNIT: 724 | *reg = 1; 725 | break; 726 | 727 | default: 728 | assert(0); 729 | } 730 | 731 | incrementIP(pidx); 732 | } 733 | 734 | static void 735 | push(sword pidx) 736 | { 737 | sword *reg; 738 | sword sidx; 739 | assert(g_isInit); 740 | assert(pidx < g_cap); 741 | assert(!sp_isFree(pidx)); 742 | getRegAddrList(pidx, ®, 1, SFALSE); 743 | 744 | for (sidx = SPROC_STACK_SIZE - 1; sidx; sidx--) { 745 | g_procs[pidx].stack[sidx] = g_procs[pidx].stack[sidx - 1]; 746 | } 747 | 748 | g_procs[pidx].stack[0] = *reg; 749 | incrementIP(pidx); 750 | } 751 | 752 | static void 753 | pop(sword pidx) 754 | { 755 | sword *reg; 756 | sword sidx; 757 | assert(g_isInit); 758 | assert(pidx < g_cap); 759 | assert(!sp_isFree(pidx)); 760 | getRegAddrList(pidx, ®, 1, SFALSE); 761 | *reg = g_procs[pidx].stack[0]; 762 | 763 | for (sidx = 1; sidx < SPROC_STACK_SIZE; sidx++) { 764 | g_procs[pidx].stack[sidx - 1] = g_procs[pidx].stack[sidx]; 765 | } 766 | 767 | g_procs[pidx].stack[SPROC_STACK_SIZE - 1] = 0; 768 | incrementIP(pidx); 769 | } 770 | 771 | static void 772 | load(sword pidx) 773 | { 774 | sword *regs[2]; 775 | assert(g_isInit); 776 | assert(pidx < g_cap); 777 | assert(!sp_isFree(pidx)); 778 | getRegAddrList(pidx, regs, 2, SFALSE); 779 | 780 | if (!sm_isValidAt(*regs[0])) { 781 | onFault(pidx); 782 | incrementIP(pidx); 783 | return; 784 | } 785 | 786 | if (g_procs[pidx].sp < *regs[0]) { 787 | g_procs[pidx].sp++; 788 | } else if (g_procs[pidx].sp > *regs[0]) { 789 | g_procs[pidx].sp--; 790 | } else { 791 | *regs[1] = sm_getInstAt(*regs[0]); 792 | incrementIP(pidx); 793 | } 794 | } 795 | 796 | static sbool 797 | isWriteableBy(sword pidx, sword addr) 798 | { 799 | assert(g_isInit); 800 | assert(pidx < g_cap); 801 | assert(!sp_isFree(pidx)); 802 | 803 | if (!sm_isValidAt(addr)) { 804 | return SFALSE; 805 | } 806 | 807 | if (!sm_isAllocatedAt(addr)) { 808 | return STRUE; 809 | } else { 810 | sword lo1 = g_procs[pidx].mb1a; 811 | sword lo2 = g_procs[pidx].mb2a; 812 | sword hi1 = lo1 + g_procs[pidx].mb1s; 813 | sword hi2 = lo2 + g_procs[pidx].mb2s; 814 | return (addr >= lo1 && addr < hi1) || (addr >= lo2 && addr < hi2); 815 | } 816 | } 817 | 818 | static void 819 | write(sword pidx) 820 | { 821 | sword *regs[2]; 822 | assert(g_isInit); 823 | assert(pidx < g_cap); 824 | assert(!sp_isFree(pidx)); 825 | getRegAddrList(pidx, regs, 2, SFALSE); 826 | 827 | if (!sm_isValidAt(*regs[0])) { 828 | onFault(pidx); 829 | incrementIP(pidx); 830 | return; 831 | } 832 | 833 | if (!si_isInst(*regs[1])) { 834 | onFault(pidx); 835 | incrementIP(pidx); 836 | return; 837 | } 838 | 839 | if (g_procs[pidx].sp < *regs[0]) { 840 | g_procs[pidx].sp++; 841 | } else if (g_procs[pidx].sp > *regs[0]) { 842 | g_procs[pidx].sp--; 843 | } else { 844 | if (isWriteableBy(pidx, *regs[0])) { 845 | sm_setInstAt(*regs[0], *regs[1]); 846 | } else { 847 | onFault(pidx); 848 | } 849 | 850 | incrementIP(pidx); 851 | } 852 | } 853 | 854 | static void 855 | r2op(sword pidx, sbyte inst) 856 | { 857 | sword *regs[2]; 858 | assert(g_isInit); 859 | assert(pidx < g_cap); 860 | assert(!sp_isFree(pidx)); 861 | getRegAddrList(pidx, regs, 2, SFALSE); 862 | 863 | switch (inst) { 864 | case SDUPL: 865 | *regs[1] = *regs[0]; 866 | break; 867 | 868 | case SSWAP: { 869 | sword temp = *regs[0]; 870 | *regs[0] = *regs[1]; 871 | *regs[1] = temp; 872 | break; 873 | } 874 | 875 | default: 876 | assert(0); 877 | } 878 | 879 | incrementIP(pidx); 880 | } 881 | 882 | static void 883 | cycle(sword pidx) 884 | { 885 | sbyte inst; 886 | assert(g_isInit); 887 | assert(pidx < g_cap); 888 | assert(!sp_isFree(pidx)); 889 | 890 | if (!sm_isValidAt(g_procs[pidx].ip) || !sm_isValidAt(g_procs[pidx].sp)) { 891 | incrementIP(pidx); 892 | return; 893 | } 894 | 895 | inst = sm_getInstAt(g_procs[pidx].ip); 896 | 897 | switch (inst) { 898 | case SJMPB: 899 | if (seek(pidx, SFALSE)) { 900 | jump(pidx); 901 | } 902 | 903 | break; 904 | 905 | case SJMPF: 906 | if (seek(pidx, STRUE)) { 907 | jump(pidx); 908 | } 909 | 910 | break; 911 | 912 | case SADRB: 913 | if (seek(pidx, SFALSE)) { 914 | addr(pidx); 915 | } 916 | 917 | break; 918 | 919 | case SADRF: 920 | if (seek(pidx, STRUE)) { 921 | addr(pidx); 922 | } 923 | 924 | break; 925 | 926 | case SIFNZ: 927 | ifnz(pidx); 928 | break; 929 | 930 | case SALLB: 931 | alloc(pidx, SFALSE); 932 | break; 933 | 934 | case SALLF: 935 | alloc(pidx, STRUE); 936 | break; 937 | 938 | case SBSWP: 939 | bswap(pidx); 940 | break; 941 | 942 | case SBCLR: 943 | bclear(pidx); 944 | break; 945 | 946 | case SSPLT: 947 | split(pidx); 948 | break; 949 | 950 | case SADDN: 951 | case SSUBN: 952 | case SMULN: 953 | case SDIVN: 954 | r3op(pidx, inst); 955 | break; 956 | 957 | case SINCN: 958 | case SDECN: 959 | case SNOTN: 960 | case SSHFL: 961 | case SSHFR: 962 | case SZERO: 963 | case SUNIT: 964 | r1op(pidx, inst); 965 | break; 966 | 967 | case SPSHN: 968 | push(pidx); 969 | break; 970 | 971 | case SPOPN: 972 | pop(pidx); 973 | break; 974 | 975 | case SLOAD: 976 | load(pidx); 977 | break; 978 | 979 | case SWRTE: 980 | write(pidx); 981 | break; 982 | 983 | case SDUPL: 984 | case SSWAP: 985 | r2op(pidx, inst); 986 | break; 987 | 988 | default: 989 | incrementIP(pidx); 990 | } 991 | } 992 | 993 | #ifndef NDEBUG 994 | 995 | static void 996 | isFreeValid(sword pidx) 997 | { 998 | sword *element; 999 | sword eidx; 1000 | assert(g_isInit); 1001 | assert(pidx < g_cap); 1002 | assert(sp_isFree(pidx)); 1003 | element = (sword *)&g_procs[pidx]; 1004 | 1005 | for (eidx = 0; eidx < SPROC_ELEM_COUNT; eidx++) { 1006 | assert(!(*element)); 1007 | element++; 1008 | } 1009 | } 1010 | 1011 | static void 1012 | isUsedValid(sword pidx) 1013 | { 1014 | sword offset; 1015 | assert(g_isInit); 1016 | assert(pidx < g_cap); 1017 | assert(!sp_isFree(pidx)); 1018 | assert(sm_isMemBlockStartAt(g_procs[pidx].mb1a)); 1019 | 1020 | if (g_procs[pidx].mb2s) { 1021 | assert(sm_isMemBlockStartAt(g_procs[pidx].mb2a)); 1022 | } 1023 | 1024 | for (offset = 0; offset < g_procs[pidx].mb1s; offset++) { 1025 | sword addr = g_procs[pidx].mb1a + offset; 1026 | assert(sm_isValidAt(addr)); 1027 | assert(sm_isAllocatedAt(addr)); 1028 | } 1029 | 1030 | for (offset = 0; offset < g_procs[pidx].mb2s; offset++) { 1031 | sword addr = g_procs[pidx].mb2a + offset; 1032 | assert(sm_isValidAt(addr)); 1033 | assert(sm_isAllocatedAt(addr)); 1034 | } 1035 | } 1036 | 1037 | static void 1038 | isValid(sword pidx) 1039 | { 1040 | assert(g_isInit); 1041 | assert(pidx < g_cap); 1042 | 1043 | if (sp_isFree(pidx)) { 1044 | isFreeValid(pidx); 1045 | } else { 1046 | isUsedValid(pidx); 1047 | } 1048 | } 1049 | 1050 | #endif 1051 | 1052 | void 1053 | sp_cycle(void) 1054 | { 1055 | #ifndef NDEBUG 1056 | sword pidx; 1057 | #endif 1058 | assert(g_isInit); 1059 | #ifndef NDEBUG 1060 | 1061 | /* check for validity before cycle */ 1062 | for (pidx = 0; pidx < sp_getCap(); pidx++) { 1063 | isValid(pidx); 1064 | } 1065 | 1066 | #endif 1067 | 1068 | if (sp_getCount()) { 1069 | sword qidx = sp_getLast(); 1070 | 1071 | /* cycle all procs */ 1072 | while (STRUE) { 1073 | cycle(qidx); 1074 | 1075 | if (qidx == sp_getFirst()) { 1076 | break; 1077 | } else { 1078 | qidx--; 1079 | qidx %= sp_getCap(); 1080 | } 1081 | } 1082 | 1083 | /* kill procs if memory is over capacity */ 1084 | while (sm_isOverCap()) { 1085 | sp_kill(); 1086 | } 1087 | } 1088 | 1089 | #ifndef NDEBUG 1090 | 1091 | /* check for validity after cycle */ 1092 | for (pidx = 0; pidx < sp_getCap(); pidx++) { 1093 | isValid(pidx); 1094 | } 1095 | 1096 | #endif 1097 | } 1098 | --------------------------------------------------------------------------------