From 2dc9d118efb64de6ea54a5a9eb4474f8e5ef3145 Mon Sep 17 00:00:00 2001 From: Paul Oliver Date: Thu, 29 Feb 2024 01:50:44 +0100 Subject: Initial commit --- tsalis/Makefile | 30 ++ tsalis/README.md | 76 +++++ tsalis/bin/.keep | 0 tsalis/build/.keep | 0 tsalis/include/handler.h | 6 + tsalis/include/printer.h | 35 +++ tsalis/include/tsalis.h | 11 + tsalis/src/handler.c | 317 ++++++++++++++++++++ tsalis/src/printer.c | 749 +++++++++++++++++++++++++++++++++++++++++++++++ tsalis/src/tsalis.c | 118 ++++++++ 10 files changed, 1342 insertions(+) create mode 100644 tsalis/Makefile create mode 100644 tsalis/README.md create mode 100644 tsalis/bin/.keep create mode 100644 tsalis/build/.keep create mode 100644 tsalis/include/handler.h create mode 100644 tsalis/include/printer.h create mode 100644 tsalis/include/tsalis.h create mode 100644 tsalis/src/handler.c create mode 100644 tsalis/src/printer.c create mode 100644 tsalis/src/tsalis.c (limited to 'tsalis') diff --git a/tsalis/Makefile b/tsalis/Makefile new file mode 100644 index 0000000..c393350 --- /dev/null +++ b/tsalis/Makefile @@ -0,0 +1,30 @@ +CC := gcc +BIN := bin/tsalis + +SOURCES := $(wildcard src/*.c) +OBJECTS := $(patsubst src/%.c,build/%.o,$(SOURCES)) +DEPS := $(patsubst %.o,%.d,$(OBJECTS)) + +LFLAGS := -L ../lib -lsalis -lncurses + +# uncomment for debug +# OFLAGS := -ggdb + +# uncomment for release +OFLAGS := -O3 -DNDEBUG + +CFLAGS := -Iinclude -I../include -c $(OFLAGS) -MMD -Wall -Wextra -std=c89 \ + -pedantic-errors -Wmissing-prototypes -Wstrict-prototypes \ + -Wold-style-definition + +all: $(OBJECTS) + $(CC) $(OBJECTS) $(LFLAGS) -o $(BIN) + +-include $(DEPS) + +$(OBJECTS): $(patsubst build/%.o,src/%.c,$@) + $(CC) $(CFLAGS) $(patsubst build/%.o,src/%.c,$@) -o $@ + +clean: + -rm build/* + -rm $(BIN) diff --git a/tsalis/README.md b/tsalis/README.md new file mode 100644 index 0000000..214e3b9 --- /dev/null +++ b/tsalis/README.md @@ -0,0 +1,76 @@ +# TSALIS +*TSALIS* is a text user interface (TUI) designed to communicate with *SALIS*. +Its only dependencies are ncurses and the *SALIS* library itself. It should be +portable enough and should run easily in any terminal environment. + +## Building instructions +You'll need nothing but a C compiler (C89). You must build the program and link +it with *SALIS* (e.g. *libsalis.a*) and ncurses. A sample makefile +(Makefile) is provided for GNU Make. You can also just run the `make` command +inside the salis directory and it will automate the building and linking of +both the library and this application. Feel free to edit both makefiles as +needed. If you run into any difficulties, please let me know! + +## List of commands +### Command-line arguments +You may run *TSALIS* from the terminal in any of these three ways (arguments +are being represented by *XX*). Note that, upon exit, *SALIS* automatically +generates a save (by default called *defsim*). This save file may be freely +renamed (any name 10 characters or shorter) and reloaded as needed. + +|Arguments |Action | +|:--------------|------------------------------------------------------------------------------:| +|tsalis |If file *defsim* exists in directory, loads simulation from that file. | +|tsalis |If file *defsim* does not exist, creates new simulation (memory size 2^16). | +|tsalis n*XX* |Creates new simulation with memory size 2^*XX*. | +|tsalis l*XX* |Loads simulation from file named *XX*. | + +### Keyboard commands +|Key |Action | +|:--------------|------------------------------------------------------:| +|Left arrow |Previous page | +|Right arrow |Next page | +|wasd |Scroll (PROCESS and WORLD page) | +|W |Scroll to top (PROCESS and WORLD page) | +|A |Scroll to left (PROCESS page) | +|zx |Zoom in/out (WORLD page) | +|op |Select previous/next organism | +|g |Toggle data/gene view (PROCESS page) | +|c |Open console (pauses simulation) | +|Space |Run/pause simulation | +|jl |Select first/last organism | +|k |Go to selected organism (PROCESS and WORLD page) | +|Numbers (1-0) |Cycle simulation (1 = 1, 2 = 2, 3 = 4, 4 = 8, ...) | + +### Console commands +The console opens up when 'c' is pressed. Commands, with their respective +parameters separated by underscores, may be written in order to modify or +control some aspects of the simulation. Parameters here are represented by +*XX*. + +|Command |Param. 1 |Param. 2 |Action | +|:-----------|:-----------|:-----------|---------------------------------------------------------------------:| +|q |--- |--- |Save and quit simulation. | +|i*XX*\_*XX* |address |instructions|Writes given instructions into address. | +|c*XX*\_*XX* |address |file name |Compiles given file into address. | +|n*XX*\_*XX* |address |size |Initializes organism of given size into address. | +|k |--- |--- |Kills organism at bottom of queue (first organism). | +|m*XX* |address |--- |Scroll/move (PROCESS and WORLD page) to given process/address. | +|p*XX* |process id |--- |Select given process. | +|s |--- |--- |Save simulation. | +|r*XX* |name |--- |Rename simulation (will be automatically saved to this name on exit). | +|a*XX* |interval |--- |Set simulation's auto-save interval. | + +### Legend +In WORLD view, as well as in PROCESS view (when gene mode is selected), each +cell is colored according to the following legend: + +|Background color |Meaning | +|:----------------|---------------------------------------:| +|BLUE |Non-allocated cell | +|CYAN |Allocated cell | +|WHITE |Start of memory block | +|YELLOW |Main memory block of selected organism | +|GREEN |Child memory block of selected organism | +|MAGENTA |SP of selected organism | +|RED |IP of selected organism | diff --git a/tsalis/bin/.keep b/tsalis/bin/.keep new file mode 100644 index 0000000..e69de29 diff --git a/tsalis/build/.keep b/tsalis/build/.keep new file mode 100644 index 0000000..e69de29 diff --git a/tsalis/include/handler.h b/tsalis/include/handler.h new file mode 100644 index 0000000..9bb4b0e --- /dev/null +++ b/tsalis/include/handler.h @@ -0,0 +1,6 @@ +#ifndef TSALIS_HANDLER_H +#define TSALIS_HANDLER_H + +void tsh_handleEvent (int event); + +#endif diff --git a/tsalis/include/printer.h b/tsalis/include/printer.h new file mode 100644 index 0000000..5356594 --- /dev/null +++ b/tsalis/include/printer.h @@ -0,0 +1,35 @@ +#ifndef TSALIS_PRINTER_H +#define TSALIS_PRINTER_H + +extern const int PROC_ELEMENT_COUNT; + +extern int g_currentPage; +extern sword g_selectedProcess; +extern sbool g_processShowGenes; +extern sword g_processVertScroll; +extern sword g_processDataScroll; +extern sword g_processGeneScroll; +extern sword g_worldPos; +extern sword g_worldZoom; + +void tsp_init (void); +void tsp_quit (void); +void tsp_onResize (void); +void tsp_prevPage (void); +void tsp_nextPage (void); +void tsp_scrollUp (void); +void tsp_scrollDown (void); +void tsp_scrollLeft (void); +void tsp_scrollRight (void); +void tsp_scrollToTop (void); +void tsp_scrollToLeft (void); +void tsp_zoomIn (void); +void tsp_zoomOut (void); +void tsp_prevOrganism (void); +void tsp_nextOrganism (void); +void tsp_gotoSelectedProc (void); +void tsp_selectProcess (sword proc); +void tsp_moveTo (sword loc); +void tsp_printData (void); + +#endif diff --git a/tsalis/include/tsalis.h b/tsalis/include/tsalis.h new file mode 100644 index 0000000..d60b7c7 --- /dev/null +++ b/tsalis/include/tsalis.h @@ -0,0 +1,11 @@ +#ifndef TSALIS_H +#define TSALIS_H + +#define NAME_MAX_SIZE 10 + +extern sbool g_exit; +extern sbool g_running; +extern sword g_autoSaveInterval; +extern char g_simName[]; + +#endif diff --git a/tsalis/src/handler.c b/tsalis/src/handler.c new file mode 100644 index 0000000..21aa706 --- /dev/null +++ b/tsalis/src/handler.c @@ -0,0 +1,317 @@ +#include +#include +#include +#include +#include "printer.h" +#include "handler.h" +#include "tsalis.h" + +#define CONSOLE_INPUT_LENGTH 64 + +static sbyte +symbolToInst(char charSymbol) +{ +#define SINST(name, symbol) case symbol: return name; +#define SILST(name, symbol) case symbol: return name; + + switch (charSymbol) { + SINST_LIST + } + +#undef SINST +#undef SILST + return (sbyte)(-1); +} + +static void +writeInstructions(const char *command) +{ + sword addr = atoi(command); + char *symbol = strchr(command, '_'); + + if (symbol) { + symbol++; + + while (sm_isValidAt(addr) && *symbol) { + sbyte svalue = symbolToInst(*symbol); + + if (si_isInst(svalue)) { + sm_setInstAt(addr, svalue); + } else { + sm_setInstAt(addr, 0); + } + + addr++; + symbol++; + } + } +} + +static void +compileGenome(const char *command) +{ + sword addr = atoi(command); + char *fileName = strchr(command, '_'); + + if (fileName) { + FILE *file = fopen(fileName + 1, "r"); + + if (file) { + while (addr < sm_getSize()) { + int symbol = fgetc(file); + sbyte svalue = symbolToInst((char)symbol); + + if (symbol == EOF) { + break; + } + + if (si_isInst(svalue)) { + sm_setInstAt(addr, svalue); + } else { + sm_setInstAt(addr, 0); + } + + addr++; + } + } + } +} + +static void +createOrganism(const char *command) +{ + sword addr = atoi(command); + char *sizep = strchr(command, '_'); + + if (sizep) { + sword size = atoi(sizep + 1); + + if (sm_isValidAt(addr) && sm_isValidAt(addr + size - 1)) { + sword offset; + + for (offset = 0; offset < size; offset++) { + if (sm_isAllocatedAt(addr + offset)) { + return; + } + } + + sp_create(addr, size); + } + } +} + +static void +killOrganism(void) +{ + sp_kill(); +} + +static void +moveTo(const char *command) +{ + sword loc = atoi(command); + tsp_moveTo(loc); +} + +static void +selectProc(const char *command) +{ + sword proc = atoi(command); + tsp_selectProcess(proc); +} + +static void +saveSim(void) +{ + s_save(g_simName); +} + +static void +renameSim(const char *name) +{ + if (strlen(name) <= NAME_MAX_SIZE) { + strncpy(g_simName, name, NAME_MAX_SIZE); + } +} + +static void +setAutoSave(const char *command) +{ + g_autoSaveInterval = atoi(command); +} + +static void +clearConsoleLine(void) +{ + move(LINES - 1, 0); + clrtoeol(); +} + +static void +runConsole(void) +{ + char command[CONSOLE_INPUT_LENGTH] = {0}; + clearConsoleLine(); + echo(); + mvprintw(LINES - 1, 1, "$ "); + curs_set(TRUE); + getnstr(command, CONSOLE_INPUT_LENGTH - 1); + curs_set(FALSE); + noecho(); + clearConsoleLine(); + + switch (command[0]) { + case 'q': + g_exit = STRUE; + break; + + case 'i': + writeInstructions(&command[1]); + break; + + case 'c': + compileGenome(&command[1]); + break; + + case 'n': + createOrganism(&command[1]); + break; + + case 'k': + killOrganism(); + break; + + case 'm': + moveTo(&command[1]); + break; + + case 'p': + selectProc(&command[1]); + break; + + case 's': + saveSim(); + break; + + case 'r': + renameSim(&command[1]); + break; + + case 'a': + setAutoSave(&command[1]); + break; + } +} + +void +tsh_handleEvent(int event) +{ + switch (event) { + case KEY_RESIZE: + tsp_onResize(); + break; + + case KEY_LEFT: + tsp_prevPage(); + break; + + case KEY_RIGHT: + tsp_nextPage(); + break; + + case 'w': + tsp_scrollDown(); + break; + + case 'a': + tsp_scrollLeft(); + break; + + case 's': + tsp_scrollUp(); + break; + + case 'd': + tsp_scrollRight(); + break; + + case 'W': + tsp_scrollToTop(); + break; + + case 'A': + tsp_scrollToLeft(); + break; + + case 'z': + tsp_zoomIn(); + break; + + case 'x': + tsp_zoomOut(); + break; + + case 'o': + tsp_prevOrganism(); + break; + + case 'p': + tsp_nextOrganism(); + break; + + case 'g': + g_processShowGenes = !g_processShowGenes; + break; + + case 'c': + g_running = SFALSE; + nodelay(stdscr, SFALSE); + tsp_printData(); + runConsole(); + break; + + case ' ': + g_running = !g_running; + nodelay(stdscr, g_running); + break; + + case 'j': + if (sp_getCount()) { + g_selectedProcess = sp_getFirst(); + } + + break; + + case 'l': + if (sp_getCount()) { + g_selectedProcess = sp_getLast(); + } + + break; + + case 'k': + tsp_gotoSelectedProc(); + break; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '0': + if (!g_running) { + int power = ((event - '0') ? (event - '0') : 10) - 1; + int cycles = 1 << power; + + while (cycles--) { + s_cycle(); + } + } + + break; + } +} diff --git a/tsalis/src/printer.c b/tsalis/src/printer.c new file mode 100644 index 0000000..a3f60b6 --- /dev/null +++ b/tsalis/src/printer.c @@ -0,0 +1,749 @@ +#include +#include +#include +#include "printer.h" +#include "tsalis.h" + +enum { + PAIR_NORMAL = 1, + PAIR_HEADER = 2, + PAIR_SELECTED_PROC = 3, + PAIR_FREE_CELL = 4, + PAIR_ALLOC_CELL = 5, + PAIR_MEM_BLOCK_START = 6, + PAIR_MEM_BLOCK_2 = 7, + PAIR_MEM_BLOCK_1 = 8, + PAIR_SELECTED_SP = 9, + PAIR_SELECTED_IP = 10 +}; + +enum { + PAGE_MEMORY, + PAGE_EVOLVER, + PAGE_PROCESS, + PAGE_WORLD, + PAGE_COUNT +}; + +const char *g_instNames[] = { +#define SINST(name, symbol) #name, +#define SILST(name, symbol) #name + SINST_LIST +#undef SINST +#undef SILST +}; + +const char g_instSymbols[] = { +#define SINST(name, symbol) symbol, +#define SILST(name, symbol) symbol + SINST_LIST +#undef SINST +#undef SILST +}; + +const char *g_procElems[] = { + "mb1a", + "mb1s", + "mb2a", + "mb2s", + "ip", + "sp", + "reg[0]", + "reg[1]", + "reg[2]", + "reg[3]", + "stack[0]", + "stack[1]", + "stack[2]", + "stack[3]", + "stack[4]", + "stack[5]", + "stack[6]", + "stack[7]" +}; + +const int PROC_ELEMENT_COUNT = (sizeof(g_procElems) / sizeof(*g_procElems)); +const int DATA_WIDTH = 25; + +int g_currentPage; +sword g_selectedProcess; +sbool g_processShowGenes; +sword g_processVertScroll; +sword g_processDataScroll; +sword g_processGeneScroll; +sword g_worldPos; +sword g_worldZoom; +sword g_worldLineWidth; +sword g_worldLineCoverage; +sword g_worldArea; + +static void +adjustWorld(void) +{ + g_worldLineWidth = COLS - DATA_WIDTH; + g_worldLineCoverage = g_worldLineWidth * g_worldZoom; + g_worldArea = LINES * g_worldLineCoverage; + + while ((g_worldArea > (sm_getSize() * 2)) && (g_worldZoom > 1)) { + g_worldZoom /= 2; + } +} + +void +tsp_init(void) +{ + initscr(); + cbreak(); + noecho(); + curs_set(0); + keypad(stdscr, TRUE); + start_color(); + init_pair(PAIR_NORMAL, COLOR_WHITE, COLOR_BLACK); + init_pair(PAIR_HEADER, COLOR_CYAN, COLOR_BLACK); + init_pair(PAIR_SELECTED_PROC, COLOR_YELLOW, COLOR_BLACK); + init_pair(PAIR_FREE_CELL, COLOR_CYAN, COLOR_BLUE); + init_pair(PAIR_ALLOC_CELL, COLOR_BLUE, COLOR_CYAN); + init_pair(PAIR_MEM_BLOCK_START, COLOR_BLUE, COLOR_WHITE); + init_pair(PAIR_MEM_BLOCK_1, COLOR_BLACK, COLOR_YELLOW); + init_pair(PAIR_MEM_BLOCK_2, COLOR_BLACK, COLOR_GREEN); + init_pair(PAIR_SELECTED_SP, COLOR_BLACK, COLOR_MAGENTA); + init_pair(PAIR_SELECTED_IP, COLOR_BLACK, COLOR_RED); + g_worldZoom = 1; + adjustWorld(); +} + +void +tsp_quit(void) +{ + endwin(); +} + +void +tsp_onResize(void) +{ + clear(); + adjustWorld(); +} + +void +tsp_prevPage(void) +{ + clear(); + g_currentPage += (PAGE_COUNT - 1); + g_currentPage %= PAGE_COUNT; +} + +void +tsp_nextPage(void) +{ + clear(); + g_currentPage++; + g_currentPage %= PAGE_COUNT; +} + +void +tsp_scrollUp(void) +{ + switch (g_currentPage) { + case PAGE_PROCESS: + if (g_processVertScroll) { + g_processVertScroll--; + } + + break; + + case PAGE_WORLD: + if (g_worldPos >= g_worldLineCoverage) { + g_worldPos -= g_worldLineCoverage; + } + + break; + } + + refresh(); +} + +void +tsp_scrollDown(void) +{ + switch (g_currentPage) { + case PAGE_PROCESS: + if (g_processVertScroll < (sp_getCap() - 1)) { + g_processVertScroll++; + } + + break; + + case PAGE_WORLD: + if ((g_worldPos + g_worldLineCoverage) < sm_getSize()) { + g_worldPos += g_worldLineCoverage; + } + + break; + } + + refresh(); +} + +void +tsp_scrollLeft(void) +{ + switch (g_currentPage) { + case PAGE_PROCESS: + if (g_processShowGenes) { + if (g_processGeneScroll) { + g_processGeneScroll--; + } + } else { + if (g_processDataScroll) { + g_processDataScroll--; + } + } + + break; + + case PAGE_WORLD: + if (g_worldPos >= g_worldZoom) { + g_worldPos -= g_worldZoom; + } else { + g_worldPos = 0; + } + + break; + } + + refresh(); +} + +void +tsp_scrollRight(void) +{ + switch (g_currentPage) { + case PAGE_PROCESS: + if (g_processShowGenes) { + g_processGeneScroll++; + } else { + if (g_processDataScroll < (sword)(PROC_ELEMENT_COUNT - 1)) { + g_processDataScroll++; + } + } + + break; + + case PAGE_WORLD: + if ((g_worldPos + g_worldZoom) < sm_getSize()) { + g_worldPos += g_worldZoom; + } + + break; + } + + refresh(); +} + +void +tsp_scrollToTop(void) +{ + switch (g_currentPage) { + case PAGE_PROCESS: + g_processVertScroll = 0; + break; + + case PAGE_WORLD: + g_worldPos = 0; + break; + } +} + +void +tsp_scrollToLeft(void) +{ + switch (g_currentPage) { + case PAGE_PROCESS: + if (g_processShowGenes) { + g_processGeneScroll = 0; + } else { + g_processDataScroll = 0; + } + + break; + } +} + +void +tsp_zoomIn(void) +{ + if (g_currentPage == PAGE_WORLD) { + if (g_worldZoom > 1) { + g_worldZoom /= 2; + } + + adjustWorld(); + } +} + +void +tsp_zoomOut(void) +{ + if (g_currentPage == PAGE_WORLD) { + if (g_worldArea < sm_getSize()) { + g_worldZoom *= 2; + refresh(); + } + + adjustWorld(); + } +} + +void +tsp_prevOrganism(void) +{ + switch (g_currentPage) { + case PAGE_PROCESS: + case PAGE_WORLD: + if (g_selectedProcess < sp_getCap()) { + g_selectedProcess += (sp_getCap() - 1); + g_selectedProcess %= sp_getCap(); + } + + break; + } + + refresh(); +} + +void +tsp_nextOrganism(void) +{ + switch (g_currentPage) { + case PAGE_PROCESS: + case PAGE_WORLD: + if (g_selectedProcess < sp_getCap()) { + g_selectedProcess++; + g_selectedProcess %= sp_getCap(); + } + + break; + } + + refresh(); +} + +void +tsp_gotoSelectedProc(void) +{ + switch (g_currentPage) { + case PAGE_PROCESS: + g_processVertScroll = g_selectedProcess; + break; + + case PAGE_WORLD: + g_worldPos = sp_getProc(g_selectedProcess).mb1a; + break; + } +} + +void +tsp_selectProcess(sword proc) +{ + if (proc < sp_getCap()) { + g_selectedProcess = proc; + } +} + +void +tsp_moveTo(sword loc) +{ + switch (g_currentPage) { + case PAGE_PROCESS: + if (loc < sp_getCap()) { + g_processVertScroll = loc; + } + + break; + + case PAGE_WORLD: + if (loc < sm_getSize()) { + g_worldPos = loc; + } + + break; + } +} + +static void +printWidget(int line, const char *format, ...) +{ + if (line < LINES) { + va_list args; + char dataLine[24]; + va_start(args, format); + vsprintf(dataLine, format, args); + mvprintw(line, 1, "%.*s", COLS - 1, dataLine); + va_end(args); + } +} + +static void +printHeader(int line, const char *string) +{ + attron(COLOR_PAIR(PAIR_HEADER)); + printWidget(line, string); + standend(); +} + +#define PHEADER(label) printHeader((*line)++, label) +#define PWIDGET(label, data) printWidget((*line)++, "%-10s : %10u", label, data) +#define PSIDGET(label, data) printWidget((*line)++, "%-10s : %10s", label, data) +#define INCREMENT_LINE (*line)++ + +static void +printMemoryPage(int *line) +{ + PHEADER("MEMORY"); + PWIDGET("order", sm_getOrder()); + PWIDGET("size", sm_getSize()); + PWIDGET("blocks", sm_getMemBlockCount()); + PWIDGET("alloc", sm_getAllocated()); + PWIDGET("cap", sm_getCap()); +} + +static void +printEvolverPage(int *line) +{ + PHEADER("EVOLVER"); + PWIDGET("lastAddr", se_getLastAddress()); + PSIDGET("lastInst", g_instNames[se_getLastInst()] + 1); + PWIDGET("state0", se_getState(0)); + PWIDGET("state1", se_getState(1)); + PWIDGET("state2", se_getState(2)); + PWIDGET("state3", se_getState(3)); +} + +static void +printField(int y, int x, const char *field, sbool lalign) +{ + if ((y < LINES) && (x < COLS)) { + if (lalign) { + mvprintw(y, x, "%-.*s", COLS - x, field); + } else { + mvprintw(y, x, "%.*s", COLS - x, field); + } + } +} + +static void +printSingleProcessGenome(int line, sword pidx) +{ + char sidx[11]; + SProc proc = sp_getProc(pidx); + sword gidx = g_processGeneScroll; + int xpos = 14; + + if (pidx == g_selectedProcess) { + attron(COLOR_PAIR(PAIR_SELECTED_PROC)); + } else if (!sp_isFree(pidx)) { + attron(COLOR_PAIR(PAIR_HEADER)); + } + + sprintf(sidx, "%-10u |", pidx); + printField(line, 1, sidx, STRUE); + move(line, xpos); + + while ((gidx < proc.mb1s) && (xpos < COLS)) { + sword gaddr = proc.mb1a + gidx; + + if (gaddr == proc.ip) { + attron(COLOR_PAIR(PAIR_SELECTED_IP)); + } else if (gaddr == proc.sp) { + attron(COLOR_PAIR(PAIR_SELECTED_SP)); + } else { + attron(COLOR_PAIR(PAIR_MEM_BLOCK_1)); + } + + addch(g_instSymbols[sm_getInstAt(gaddr)]); + gidx++; + xpos++; + } + + if (proc.mb1s < g_processGeneScroll) { + gidx = g_processGeneScroll - proc.mb1s; + } else { + gidx = 0; + } + + while ((gidx < proc.mb2s) && (xpos < COLS)) { + sword gaddr = proc.mb2a + gidx; + + if (gaddr == proc.ip) { + attron(COLOR_PAIR(PAIR_SELECTED_IP)); + } else if (gaddr == proc.sp) { + attron(COLOR_PAIR(PAIR_SELECTED_SP)); + } else { + attron(COLOR_PAIR(PAIR_MEM_BLOCK_2)); + } + + addch(g_instSymbols[sm_getInstAt(gaddr)]); + gidx++; + xpos++; + } + + standend(); +} + +static void +printProcessGenes(int *line) +{ + sword pidx = g_processVertScroll; + attron(COLOR_PAIR(PAIR_HEADER)); + printField(*line, 1, "pidx", STRUE); + + standend(); + INCREMENT_LINE; + + while ((*line < LINES) && (pidx < sp_getCap())) { + printSingleProcessGenome(*line, pidx); + INCREMENT_LINE; + pidx++; + } + + standend(); +} + +static void +printSingleProcessData(int line, sword pidx) +{ + char sidx[11]; + int eidx = g_processDataScroll; + int xpos = 12; + SProc proc = sp_getProc(pidx); + sword *data = (sword *)&proc; + + if (pidx == g_selectedProcess) { + attron(COLOR_PAIR(PAIR_SELECTED_PROC)); + } else if (!sp_isFree(pidx)) { + attron(COLOR_PAIR(PAIR_HEADER)); + } + + sprintf(sidx, "%u", pidx); + printField(line, 1, sidx, STRUE); + + while (eidx < PROC_ELEMENT_COUNT) { + char element[13]; + sprintf(element, "| %10u", data[eidx]); + printField(line, xpos, element, SFALSE); + eidx++; + xpos += 13; + } + + standend(); +} + +static void +printProcessData(int *line) +{ + sword pidx = g_processVertScroll; + int eidx = g_processDataScroll; + int xpos = 12; + attron(COLOR_PAIR(PAIR_HEADER)); + printField(*line, 1, "pidx", STRUE); + + while (eidx < PROC_ELEMENT_COUNT) { + char element[13]; + sprintf(element, "| %10s", g_procElems[eidx]); + printField(*line, xpos, element, SFALSE); + eidx++; + xpos += 13; + } + + standend(); + INCREMENT_LINE; + + while ((*line < LINES) && (pidx < sp_getCap())) { + printSingleProcessData(*line, pidx); + INCREMENT_LINE; + pidx++; + } + + standend(); +} + +static void +printProcessPage(int *line) +{ + int cline; + sbool fnull = (sp_getFirst() == (sword) - 1); + sbool lnull = (sp_getLast() == (sword) - 1); + PHEADER("PROCESS"); + PWIDGET("count", sp_getCount()); + PWIDGET("cap", sp_getCap()); + fnull ? PSIDGET("first", "---") : PWIDGET("first", sp_getFirst()); + lnull ? PSIDGET("last", "---") : PWIDGET("last", sp_getLast()); + PWIDGET("selected", g_selectedProcess); + INCREMENT_LINE; + + for (cline = *line; cline < LINES; cline++) { + move(cline, 0); + clrtoeol(); + } + + if (g_processShowGenes) { + printProcessGenes(line); + } else { + printProcessData(line); + } +} + +static int +getColorOf(sword addr) +{ + if (!sp_isFree(g_selectedProcess)) { + SProc proc = sp_getProc(g_selectedProcess); + + if (addr == proc.ip) { + return PAIR_SELECTED_IP; + } else if (addr == proc.sp) { + return PAIR_SELECTED_SP; + } else if ((addr >= proc.mb1a) && (addr < (proc.mb1a + proc.mb1s))) { + return PAIR_MEM_BLOCK_1; + } else if ((addr >= proc.mb2a) && (addr < (proc.mb2a + proc.mb2s))) { + return PAIR_MEM_BLOCK_2; + } + } + + if (sm_isMemBlockStartAt(addr)) { + return PAIR_MEM_BLOCK_START; + } else if (sm_isAllocatedAt(addr)) { + return PAIR_ALLOC_CELL; + } else { + return PAIR_FREE_CELL; + } +} + +static void +printWorld(void) +{ + sword y; + + for (y = 0; y < (sword)LINES; y++) { + sword x; + + for (x = 0; x < g_worldLineWidth; x++) { + sword addr = g_worldPos + (((y * g_worldLineWidth) + x) * g_worldZoom); + sbool atEnd = !sm_isValidAt(addr); + int xpos = DATA_WIDTH + x; + + if (atEnd) { + mvaddch(y, xpos, ' '); + continue; + } + + if (g_worldZoom == 1) { + char symbol = g_instSymbols[sm_getInstAt(addr)]; + attron(COLOR_PAIR(getColorOf(addr))); + mvaddch(y, xpos, symbol); + } else { + sword offset; + char symbol; + sword instSum = 0; + int color = PAIR_FREE_CELL; + + for (offset = 0; offset < g_worldZoom; offset++) { + int testColor; + sword offsetAddr = addr + offset; + + if (!sm_isValidAt(offsetAddr)) { + break; + } + + instSum += sm_getInstAt(offsetAddr); + testColor = getColorOf(offsetAddr); + + if (testColor > color) { + color = testColor; + } + } + + instSum /= g_worldZoom; + + if (!instSum) { + symbol = ' '; + } else if (instSum < 32) { + symbol = '-'; + } else { + symbol = '='; + } + + attron(COLOR_PAIR(color)); + mvaddch(y, xpos, symbol); + } + + standend(); + } + } +} + +static void +printWorldPage(int *line) +{ + int eidx; + SProc proc = sp_getProc(g_selectedProcess); + sword *data = (sword *)&proc; + PHEADER("WORLD"); + PWIDGET("pos", g_worldPos); + PWIDGET("zoom", g_worldZoom); + PWIDGET("selected", g_selectedProcess); + INCREMENT_LINE; + PHEADER("SELECTED"); + + if (!sp_isFree(g_selectedProcess)) { + attron(COLOR_PAIR(PAIR_SELECTED_PROC)); + } + + for (eidx = 0; eidx < PROC_ELEMENT_COUNT; eidx++) { + PWIDGET(g_procElems[eidx], data[eidx]); + } + + standend(); + printWorld(); +} + +void +tsp_printData(void) +{ + int linev = 1; + int *line = &linev; + PHEADER("SALIS"); + PSIDGET("name", g_simName); + PSIDGET("state", g_running ? "running" : "paused"); + + if (g_autoSaveInterval) { + PWIDGET("autosave", g_autoSaveInterval); + } else { + PSIDGET("autosave", "---"); + } + + PWIDGET("cycle", s_getCycle()); + PWIDGET("epoch", s_getEpoch()); + INCREMENT_LINE; + + switch (g_currentPage) { + case PAGE_MEMORY: + printMemoryPage(line); + break; + + case PAGE_EVOLVER: + printEvolverPage(line); + break; + + case PAGE_PROCESS: + printProcessPage(line); + break; + + case PAGE_WORLD: + printWorldPage(line); + break; + } + + refresh(); +} diff --git a/tsalis/src/tsalis.c b/tsalis/src/tsalis.c new file mode 100644 index 0000000..ab24c61 --- /dev/null +++ b/tsalis/src/tsalis.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include +#include "printer.h" +#include "handler.h" +#include "tsalis.h" + +#define DEFAULT_ORDER 16 + +sbool g_exit; +sbool g_running; +sword g_autoSaveInterval; +char g_simName[NAME_MAX_SIZE + 1] = "def.sim"; + +static void +onDefault(void) +{ + FILE *testFile = fopen(g_simName, "r"); + + if (testFile) { + fclose(testFile); + s_load(g_simName); + } else { + s_init(DEFAULT_ORDER); + } +} + +static void +onLoad(const char *fileName) +{ + FILE *testFile; + + if (strlen(fileName) > NAME_MAX_SIZE) { + fputs("ERROR: File name too long", stderr); + exit(1); + } + + strncpy(g_simName, fileName, NAME_MAX_SIZE); + testFile = fopen(g_simName, "r"); + + if (testFile) { + fclose(testFile); + s_load(g_simName); + } else { + fputs("ERROR: File does not exist", stderr); + exit(1); + } +} + +static void +init(int argc, char **argv) +{ + if (argc == 1) { + onDefault(); + } else if (argc == 2) { + char cmd = argv[1][0]; + char *val = &argv[1][1]; + + if (cmd == 'n') { + s_init(atoi(val)); + } else if (cmd == 'l') { + onLoad(val); + } else { + fputs("ERROR: Incorrect arguments", stderr); + exit(1); + } + } else { + fputs("ERROR: Incorrect argument count", stderr); + exit(1); + } + + tsp_init(); +} + +static void +exec(void) +{ + while (!g_exit) { + if (g_running) { + clock_t beg = clock(); + clock_t end; + float delay; + + do { + s_cycle(); + + if (g_autoSaveInterval && !(s_getCycle() % g_autoSaveInterval)) { + s_save(g_simName); + } + + end = clock(); + delay = (float)(end - beg) / CLOCKS_PER_SEC; + } while (delay < (1.0 / 60.0)); + } + + tsp_printData(); + tsh_handleEvent(getch()); + } +} + +static void +quit(void) +{ + tsp_quit(); + s_save(g_simName); + s_quit(); +} + +int +main(int argc, char **argv) +{ + init(argc, argv); + exec(); + quit(); + return 0; +} -- cgit v1.2.1