commit d7865d956f9fe3a08ebe4429dce4428a9f74bc6c
Author: Louis Burda <quent.burda@gmail.com>
Date: Mon, 24 Jul 2023 00:43:33 +0200
Add initial rough outline
Diffstat:
A | .gitignore | | | 4 | ++++ |
A | Makefile | | | 23 | +++++++++++++++++++++++ |
A | test/test.asm | | | 17 | +++++++++++++++++ |
A | tis-as.c | | | 362 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | tis-curses.c | | | 306 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | tpu.c | | | 27 | +++++++++++++++++++++++++++ |
A | tpu.h | | | 82 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
7 files changed, 821 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,4 @@
+tis-as
+tis-curses
+compile_commands.json
+.cache
diff --git a/Makefile b/Makefile
@@ -0,0 +1,23 @@
+PREFIX ?= /usr/local
+BINDIR ?= /bin
+
+CFLAGS = -Wunused-function -Wunused-variable -Wconversion -Wswitch
+
+all: tis-as tis-curses
+
+clean:
+ rm -f tis-as tis-curses
+
+tis-as: tis-as.c tpu.c
+ $(CC) -o $@ $^ $(CFLAGS)
+
+tis-curses: tis-curses.c tpu.c
+ $(CC) -o $@ $^ $(CFLAGS) -lncursesw
+
+install:
+ install -m755 tis-as tis-curses -t "$(DESTDIR)$(PREFIX)$(BINDIR)"
+
+uninstall:
+ rm -f "$(DESTDIR)$(PREFIX)$(BINDIR)"/{tis-as,tis-curses}
+
+.PHONY: all clean install uninstall
diff --git a/test/test.asm b/test/test.asm
@@ -0,0 +1,17 @@
+in X1 Y1
+out X3 Y1
+
+tpu X1 Y1
+ mov acc, bak
+label:
+ goto label
+end
+
+tpu X2 Y1
+ mov UP, RIGHT
+ mov RIGHT
+end
+
+tpu X3 Y1
+
+edn
diff --git a/tis-as.c b/tis-as.c
@@ -0,0 +1,362 @@
+#include "tpu.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#define WHITESPACE " \t\v\r\n"
+
+enum tok {
+ /* Global */
+ TOK_STDIN, TOK_STDOUT, TOK_TPU, TOK_END,
+
+ /* Operands (order like OP_*) */
+ TOK_ACC, TOK_BAK, TOK_NIL, TOK_LEFT, TOK_RIGHT,
+ TOK_UP, TOK_DOWN, TOK_ANY, TOK_LAST, TOK_LIT,
+
+ /* Instructions (order like INST_*) */
+ TOK_NOP, TOK_MOV, TOK_SWP, TOK_SAV, TOK_ADD, TOK_SUB,
+ TOK_NEG, TOK_JMP, TOK_JEZ, TOK_JNZ, TOK_JLZ, TOK_JRO,
+
+ /* Misc */
+ TOK_COMMENT, TOK_LABEL, TOK_XPOS, TOK_YPOS, TOK_NL, TOK_EOF
+};
+
+struct tokenizer {
+ FILE *file;
+ enum tok tok;
+ char *tokstr;
+ size_t lineno, off;
+ char linebuf[256];
+};
+
+static int stdin_x = 0, stdin_y = 0;
+static int stdout_x = 0, stdout_y = 0;
+
+struct tpu_map map;
+
+static const char *tok_reprs[] = {
+ /* Global */
+ "STDIN", "STDOUT", "BLOCK", "END",
+
+ /* Operands */
+ "ACC", "BAK", "NIL", "LEFT", "RIGHT", "UP",
+ "DOWN", "ANY", "LAST", "<LIT>",
+
+ /* Instructions */
+ "NOP", "MOV", "SWP", "SAV", "ADD", "SUB",
+ "NEG", "JMP", "JEZ", "JNZ", "JLZ", "JRO",
+
+ /* Misc */
+ "#<COMMENT>", "<LABEL>", "X<INT>", "Y<INT>", "<NL>", "<EOF>"
+};
+
+static void
+__attribute__((format(printf, 1, 2)))
+__attribute__((noreturn))
+die(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fprintf(stderr, "tis: ");
+ vfprintf(stderr, fmt, ap);
+ if (*fmt && fmt[strlen(fmt)-1] == ':') {
+ fputc(' ', stderr);
+ perror(NULL);
+ } else {
+ fputc('\n', stderr);
+ }
+ va_end(ap);
+
+ exit(1);
+}
+
+bool
+is_lit(const char *str)
+{
+ unsigned long v;
+ char *end;
+
+ v = strtoul(str, &end, 10);
+ if (!end || *end) return false;
+
+ return v < 256;
+}
+
+uint8_t
+str2lit(const char *str)
+{
+ return (uint8_t) atoi(str);
+}
+
+enum tpu_inst_type
+tok_to_inst(enum tok tok)
+{
+ if (tok < TOK_NOP || tok >= TOK_JRO) abort();
+ return tok - TOK_NOP + INST_NOP;
+}
+
+enum tpu_inst_op_type
+tok_to_optype(enum tok tok)
+{
+ if (tok < TOK_ACC || tok >= TOK_LIT) abort();
+ return tok - TOK_ACC + OP_ACC;
+}
+
+enum tok
+tok_next(struct tokenizer *tok)
+{
+ size_t len;
+ char *s;
+
+ if (!tok->linebuf[tok->off]) {
+ if (feof(tok->file)) return TOK_EOF;
+ s = fgets(tok->linebuf, sizeof(tok->linebuf), tok->file);
+ if (!s && !feof(tok->file)) die("fgets:");
+ if (!s) return TOK_EOF;
+ if (*s && s[strlen(s)-1] != '\n')
+ die("tokenizer: line %lu too long", tok->lineno);
+ tok->off = 0;
+ }
+
+ s = tok->linebuf + tok->off;
+ len = strspn(s, WHITESPACE);
+ tok->off += len;
+ s += len;
+
+ len = strcspn(s, WHITESPACE);
+ s[len] = '\0';
+ tok->off += len;
+ if (!len) return TOK_NL;
+
+ if (!strcasecmp(s, "stdin")) {
+ return TOK_STDIN;
+ } else if (!strcasecmp(s, "stdout")) {
+ return TOK_STDIN;
+ } else if (!strcasecmp(s, "block")) {
+ return TOK_TPU;
+ } else if (!strcasecmp(s, "end")) {
+ return TOK_END;
+ } else if (!strcasecmp(s, "acc")) {
+ return TOK_ACC;
+ } else if (!strcasecmp(s, "bak")) {
+ return TOK_BAK;
+ } else if (!strcasecmp(s, "nil")) {
+ return TOK_NIL;
+ } else if (!strcasecmp(s, "left")) {
+ return TOK_LEFT;
+ } else if (!strcasecmp(s, "right")) {
+ return TOK_RIGHT;
+ } else if (!strcasecmp(s, "up")) {
+ return TOK_UP;
+ } else if (!strcasecmp(s, "down")) {
+ return TOK_DOWN;
+ } else if (!strcasecmp(s, "any")) {
+ return TOK_ANY;
+ } else if (!strcasecmp(s, "last")) {
+ return TOK_LAST;
+ } else if (is_lit(s)) {
+ return TOK_LIT;
+ } else if (!strcasecmp(s, "nop")) {
+ return TOK_NOP;
+ } else if (!strcasecmp(s, "mov")) {
+ return TOK_MOV;
+ } else if (!strcasecmp(s, "swp")) {
+ return TOK_SWP;
+ } else if (!strcasecmp(s, "sav")) {
+ return TOK_SAV;
+ } else if (!strcasecmp(s, "add")) {
+ return TOK_ADD;
+ } else if (!strcasecmp(s, "sub")) {
+ return TOK_SUB;
+ } else if (!strcasecmp(s, "neg")) {
+ return TOK_NEG;
+ } else if (!strcasecmp(s, "jmp")) {
+ return TOK_JMP;
+ } else if (!strcasecmp(s, "jez")) {
+ return TOK_JEZ;
+ } else if (!strcasecmp(s, "jnz")) {
+ return TOK_JNZ;
+ } else if (!strcasecmp(s, "jlz")) {
+ return TOK_JLZ;
+ } else if (!strcasecmp(s, "jro")) {
+ return TOK_JRO;
+ } else if (*s == '#') {
+ tok->off = strlen(s);
+ return TOK_COMMENT;
+ } else if (len && s[len-1] == ':') {
+ return TOK_LABEL;
+ } else if (*s == 'X' && atoi(s+1) > 0) {
+ return TOK_XPOS;
+ } else if (*s == 'Y' && atoi(s+1) > 0) {
+ return TOK_YPOS;
+ } else {
+ die("tokenizer: line %lu, invalid token '%s'", tok->lineno, s);
+ }
+}
+
+enum tok
+tok_next_in(struct tokenizer *tokenizer, ...)
+{
+ va_list ap, cpy;
+ enum tok tok;
+ bool first;
+ int arg;
+
+ tok = tok_next(tokenizer);
+
+ va_copy(cpy, ap);
+
+ va_start(cpy, tokenizer);
+ while ((arg = va_arg(cpy, int)) > 0) {
+ if (tok == arg) return tok;
+ }
+ va_end(cpy);
+
+ fprintf(stderr, "tis-as: tokenizer: ");
+ fprintf(stderr, "line %lu, got tok '%s', expected one of ",
+ tokenizer->lineno, tok_reprs[tok]);
+
+ first = true;
+ va_start(ap, tokenizer);
+ while ((arg = va_arg(ap, int)) > 0) {
+ if (!first) fputc(',', stderr);
+ fputs(tok_reprs[arg], stderr);
+ first = false;
+ }
+ va_end(ap);
+
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+static void
+load(const char *fname)
+{
+ struct tokenizer tokenizer;
+ enum tpu_inst_op_type op1, op2;
+ enum tok op1_tok, op2_tok;
+ uint8_t op1_lit, op2_lit;
+ enum tpu_inst_type inst;
+ struct tpu *tpu = NULL;
+ enum tok tok;
+ FILE *file;
+
+ file = fopen(fname, "r");
+ if (!file) die("fopen:");
+
+ tokenizer.lineno = 1;
+ tokenizer.file = file;
+ tokenizer.off = 0;
+ tokenizer.tokstr = NULL;
+ tokenizer.linebuf[tokenizer.off] = '\0';
+ while ((tok = tok_next(&tokenizer)) != TOK_EOF) {
+ switch (tok) {
+ case TOK_STDIN:
+ if (tpu) goto disallowed;
+ tok_next_in(&tokenizer, TOK_XPOS, -1);
+ stdin_x = atoi(tokenizer.tokstr + 1);
+ tok_next_in(&tokenizer, TOK_YPOS, -1);
+ stdin_y = atoi(tokenizer.tokstr + 1);
+ tok_next_in(&tokenizer, TOK_NL, -1);
+ break;
+ case TOK_STDOUT:
+ if (tpu) goto disallowed;
+ tok_next_in(&tokenizer, TOK_XPOS, -1);
+ stdout_x = atoi(tokenizer.tokstr + 1);
+ tok_next_in(&tokenizer, TOK_YPOS, -1);
+ stdout_y = atoi(tokenizer.tokstr + 1);
+ tok_next_in(&tokenizer, TOK_NL, -1);
+ break;
+ case TOK_TPU:
+ if (tpu) goto disallowed;
+ tpu = malloc(sizeof(struct tpu));
+ if (!tpu) die("malloc:");
+ tpu_init(tpu);
+ tok_next_in(&tokenizer, TOK_XPOS, -1);
+ tpu->x = atoi(tokenizer.tokstr + 1);
+ tok_next_in(&tokenizer, TOK_YPOS, -1);
+ tpu->y = atoi(tokenizer.tokstr + 1);
+ tok_next_in(&tokenizer, TOK_NL, -1);
+ /* TODO insert tpu */
+ break;
+ case TOK_END:
+ if (!tpu) goto disallowed;
+ tpu = NULL;
+ break;
+ case TOK_NOP: case TOK_MOV: case TOK_SWP: case TOK_SAV:
+ case TOK_ADD: case TOK_SUB: case TOK_NEG: case TOK_JMP:
+ case TOK_JEZ: case TOK_JNZ: case TOK_JLZ: case TOK_JRO:
+ if (!tpu) goto disallowed;
+ inst = tok_to_inst(tok);
+
+ op1_tok = tok_next_in(&tokenizer, TOK_ACC,
+ TOK_BAK, TOK_UP, TOK_DOWN,
+ TOK_LEFT, TOK_RIGHT, TOK_NL, -1);
+ if (op1_tok == TOK_NL) {
+ tok_next_in(&tokenizer, TOK_NL, -1);
+ tpu_add_inst(tpu, inst, -1, 0, -1, 0);
+ break;
+ }
+
+ op1 = tok_to_optype(op1_tok);
+ if (op1 == OP_LIT)
+ op1_lit = str2lit(tokenizer.tokstr);
+
+ op2_tok = tok_next_in(&tokenizer, TOK_ACC,
+ TOK_BAK, TOK_UP, TOK_DOWN,
+ TOK_LEFT, TOK_RIGHT, TOK_NL, -1);
+ if (op2_tok == TOK_NL) {
+ tok_next_in(&tokenizer, TOK_NL, -1);
+ tpu_add_inst(tpu, inst,
+ (int) op1, op1_lit, -1, 0);
+ break;
+ }
+
+ op2 = tok_to_optype(op2_tok);
+ if (op2 == OP_LIT)
+ op2_lit = str2lit(tokenizer.tokstr);
+ tok_next_in(&tokenizer, TOK_NL, -1);
+ tpu_add_inst(tpu, inst, (int) op1, op1_lit,
+ (int) op2, op2_lit);
+ break;
+ case TOK_COMMENT:
+ tok_next_in(&tokenizer, TOK_NL, -1);
+ break;
+ case TOK_LABEL:
+ /* TODO */
+ break;
+ default:
+ goto disallowed;
+ }
+ }
+
+ fclose(file);
+
+disallowed:
+ die("tokenizer: line %lu, token %s not allowed here",
+ tokenizer.lineno, tok_reprs[tok]);
+}
+
+void
+run(void)
+{
+
+}
+
+int
+main(int argc, const char **argv)
+{
+ if (argc != 2) {
+ fprintf(stderr, "Usage: tis-as FILE\n");
+ exit(1);
+ }
+
+ load(argv[1]);
+
+ run();
+}
diff --git a/tis-curses.c b/tis-curses.c
@@ -0,0 +1,306 @@
+#define NCURSES_WIDECHAR 1
+
+#include "tpu.h"
+
+#include <curses.h>
+
+#include <locale.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#define KEY_ESC 0x1b
+#define KEY_CTRL(c) ((c) & ~0x60)
+
+#define TCELL_INPUT_ROWS 14
+#define TCELL_INPUT_COLS 20
+#define TCELL_INFO_W 6
+#define TCELL_INFO_H 4
+#define TCELL_CNT 6
+#define TCELL_W (TCELL_INPUT_COLS + 2 + 6)
+#define TCELL_H (TCELL_INPUT_ROWS + 2)
+
+enum {
+ COLOR_HEADING,
+ COLOR_VAL
+};
+
+struct tpu_cell {
+ struct tpu tpu;
+ enum tpu_mode mode;
+ size_t x, y;
+ const char source[TCELL_INPUT_ROWS][TCELL_INPUT_COLS + 1];
+ bool enabled;
+ char *warn;
+ float idle;
+};
+
+static size_t tpu_cell_rows = 2;
+static size_t tpu_cell_cols = 3;
+
+static size_t screenw = 80;
+static size_t screenh = 40;
+
+static struct tpu_cell *tpu_cells = NULL;
+
+static void
+__attribute__((format(printf, 1, 2)))
+__attribute__((noreturn))
+die(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fprintf(stderr, "tis: ");
+ vfprintf(stderr, fmt, ap);
+ if (*fmt && fmt[strlen(fmt)-1] == ':') {
+ fputc(' ', stderr);
+ perror(NULL);
+ } else {
+ fputc('\n', stderr);
+ }
+ va_end(ap);
+
+ exit(1);
+}
+
+static const char *
+cell_mode_str(struct tpu_cell *cell)
+{
+ switch (cell->mode) {
+ case MODE_READ:
+ return "=R=";
+ case MODE_WRITE:
+ return "=W=";
+ case MODE_IDLE:
+ return "=I=";
+ case MODE_RUN:
+ return "=X=";
+ }
+}
+
+static const char *
+cell_last_str(struct tpu_cell *cell)
+{
+ return "N/A";
+}
+
+static void
+tui_draw_box(int sx, int sy, int w, int h, const cchar_t *ul, const cchar_t *ur,
+ const cchar_t *ll, const cchar_t *lr)
+{
+ int x, y;
+
+ mvadd_wch(sy, sx, ul);
+ mvadd_wch(sy, sx + w - 1, ur);
+ mvadd_wch(sy + h - 1, sx, ll);
+ mvadd_wch(sy + h - 1, sx + w - 1, lr);
+ for (x = sx + 1; x < sx + w - 1; x++)
+ mvadd_wch(sy, x, WACS_D_HLINE);
+ for (x = sx + 1; x < sx + w - 1; x++)
+ mvadd_wch(sy + h - 1, x, WACS_D_HLINE);
+ for (y = sy + 1; y < sy + h - 1; y++)
+ mvadd_wch(y, sx, WACS_D_VLINE);
+ for (y = sy + 1; y < sy + h - 1; y++)
+ mvadd_wch(y, sx + w - 1, WACS_D_VLINE);
+}
+
+static void
+__attribute__((format(printf, 4, 5)))
+tui_draw_text(int x, int y, int attr, const char *fmt, ...)
+{
+ char buf[256];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, 256, fmt, ap);
+ va_end(ap);
+
+ attron(attr);
+ mvprintw(y, x, "%s", buf);
+ attroff(attr);
+}
+
+static void
+tui_draw_wch(int x, int y, int attr, const cchar_t *c)
+{
+ attron(attr);
+ mvadd_wch(y, x, c);
+ attroff(attr);
+}
+
+static void
+tui_draw_tpu_cell(struct tpu_cell *cell)
+{
+ struct tpu_port *port;
+ int x, y, w, h;
+
+ tui_draw_box((int) cell->x, (int) cell->y, TCELL_W, TCELL_H,
+ WACS_D_ULCORNER, WACS_D_URCORNER, WACS_D_LLCORNER, WACS_D_LRCORNER);
+
+ x = (int) cell->x + TCELL_W - TCELL_INFO_W;
+ w = TCELL_INFO_W;
+ h = TCELL_INFO_H;
+
+ tui_draw_box(x, (y = (int) cell->y), w, h,
+ WACS_D_TTEE, WACS_D_URCORNER, WACS_D_LTEE, WACS_D_RTEE);
+ tui_draw_text(x + 2, y + 1, A_BOLD, "ACC");
+ tui_draw_text(x + 2, y + 2, 0, "%03i", cell->tpu.acc);
+
+ tui_draw_box(x, (y += TCELL_INFO_H - 1), w, h,
+ WACS_D_LTEE, WACS_D_RTEE, WACS_D_LTEE, WACS_D_RTEE);
+ tui_draw_text(x + 2, y + 1, A_BOLD, "BAK");
+ tui_draw_text(x + 2, y + 2, 0, "%03i", cell->tpu.bak);
+
+ tui_draw_box(x, (y += TCELL_INFO_H - 1), w, h,
+ WACS_D_LTEE, WACS_D_RTEE, WACS_D_LTEE, WACS_D_RTEE);
+ tui_draw_text(x + 2, y + 1, A_BOLD, "LST");
+ tui_draw_text(x + 2, y + 2, 0, "%s", cell_last_str(cell));
+
+ tui_draw_box(x, (y += TCELL_INFO_H - 1), w, h,
+ WACS_D_LTEE, WACS_D_RTEE, WACS_D_LTEE, WACS_D_RTEE);
+ tui_draw_text(x + 2, y + 1, A_BOLD, "MOD");
+ tui_draw_text(x + 2, y + 2, 0, "%s", cell_mode_str(cell));
+
+ tui_draw_box(x, (y += TCELL_INFO_H - 1), w, h,
+ WACS_D_LTEE, WACS_D_RTEE, WACS_D_BTEE, WACS_D_LRCORNER);
+ tui_draw_text(x + 2, y + 1, A_BOLD, "IDL");
+ tui_draw_text(x + 2, y + 2, 0, "%03i", (int) (cell->idle * 100));
+
+ if (cell->tpu.ports[DIR_LEFT].dst_tpu) {
+ port = &cell->tpu.ports[DIR_LEFT];
+ if (port->type & PORT_IN)
+ tui_draw_wch((int) cell->x - 1, (int) cell->y + 8,
+ port->read ? A_BOLD : 0, WACS_RARROW);
+ if (port->type & PORT_OUT)
+ tui_draw_wch((int) cell->x - 1, (int) cell->y + 7,
+ port->write ? A_BOLD : 0, WACS_LARROW);
+ if (port->write)
+ tui_draw_text((int) cell->x - 3, (int) cell->y + 6,
+ A_BOLD, "%03i", port->val);
+ }
+
+ if (cell->tpu.ports[DIR_RIGHT].dst_tpu) {
+ port = &cell->tpu.ports[DIR_RIGHT];
+ if (port->type & PORT_IN)
+ tui_draw_wch((int) cell->x + TCELL_W + 1, (int) cell->y + 7,
+ port->read ? A_BOLD : 0, WACS_LARROW);
+ if (port->type & PORT_OUT)
+ tui_draw_wch((int) cell->x + TCELL_W + 1, (int) cell->y + 8,
+ port->write ? A_BOLD : 0, WACS_RARROW);
+ if (port->write)
+ tui_draw_text((int) cell->x + TCELL_W + 1, (int) cell->y + 9,
+ A_BOLD, "%03i", port->val);
+ }
+
+ if (cell->tpu.ports[DIR_UP].dst_tpu) {
+ port = &cell->tpu.ports[DIR_UP];
+ if (port->type & PORT_IN)
+ tui_draw_wch((int) cell->x + 13, (int) cell->y - 1,
+ port->read ? A_BOLD : 0, WACS_DARROW);
+ if (port->type & PORT_OUT)
+ tui_draw_wch((int) cell->x + 15, (int) cell->y - 1,
+ port->write ? A_BOLD : 0, WACS_UARROW);
+ if (port->write)
+ tui_draw_text((int) cell->x + 16, (int) cell->y - 1,
+ A_BOLD, "%03i", port->val);
+ }
+
+ if (cell->tpu.ports[DIR_DOWN].dst_tpu) {
+ port = &cell->tpu.ports[DIR_DOWN];
+ if (port->type & PORT_IN)
+ tui_draw_wch((int) cell->x + 13, (int) cell->y + TCELL_H,
+ port->write ? A_BOLD : 0, WACS_DARROW);
+ if (port->type & PORT_OUT)
+ tui_draw_wch((int) cell->x + 15, (int) cell->y + TCELL_H,
+ port->read ? A_BOLD : 0, WACS_UARROW);
+ if (port->write)
+ tui_draw_text((int) cell->x + 10, (int) cell->y + TCELL_H,
+ A_BOLD, "%03i", port->val);
+ }
+}
+
+static void
+tui_draw(void)
+{
+ int i;
+
+ for (i = 0; i < TCELL_CNT; i++)
+ tui_draw_tpu_cell(&tpu_cells[i]);
+
+ refresh();
+}
+
+static void
+tui_resize(void)
+{
+ size_t x, y, i;
+
+ screenw = (size_t) getmaxx(stdscr);
+ screenh = (size_t) getmaxy(stdscr);
+
+ for (y = 0; y < tpu_cell_rows; y++) {
+ for (x = 0; x < tpu_cell_cols; x++) {
+ i = y * tpu_cell_cols + x;
+ tpu_cells[i].x = 2 + x * (TCELL_W + 4);
+ tpu_cells[i].y = 2 + y * (TCELL_H + 2);
+ }
+ }
+}
+
+int
+main(int argc, const char **argv)
+{
+ size_t x, y, i;
+ bool quit;
+ int key;
+
+ setlocale(LC_ALL, "");
+
+ initscr();
+
+ raw();
+ noecho();
+ keypad(stdscr, TRUE);
+ start_color();
+ curs_set(0);
+
+ /* TODO load like tis-as */
+
+ tpu_cells = calloc(tpu_cell_rows * tpu_cell_cols, sizeof(struct tpu_cell));
+ if (!tpu_cells) die("malloc:");
+
+ for (y = 0; y < tpu_cell_rows; y++) {
+ for (x = 0; x < tpu_cell_cols; x++) {
+ i = y * tpu_cell_cols + x;
+ tpu_cells[i].enabled = true;
+ tpu_init(&tpu_cells[i].tpu);
+ memset((void *) tpu_cells[i].source, 0,
+ TCELL_INPUT_ROWS * (TCELL_INPUT_COLS + 1));
+ }
+ }
+
+ tui_resize();
+ quit = false;
+ while (!quit) {
+ tui_draw();
+ key = getch();
+ switch (key) {
+ case KEY_RESIZE:
+ tui_resize();
+ break;
+ case KEY_CTRL('c'):
+ quit = true;
+ break;
+ }
+ }
+
+ for (i = 0; i < TCELL_CNT; i++)
+ tpu_deinit(&tpu_cells[i].tpu);
+ free(tpu_cells);
+
+ endwin();
+}
diff --git a/tpu.c b/tpu.c
@@ -0,0 +1,27 @@
+#include "tpu.h"
+
+void
+tpu_init(struct tpu *tpu)
+{
+
+}
+
+void
+tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst,
+ int op1, uint8_t op1_lit, int op2, uint8_t op2_lit)
+{
+
+}
+
+void
+tpu_step(struct tpu *tpu, uint8_t *up, uint8_t *right,
+ uint8_t *down, uint8_t *left)
+{
+
+}
+
+void
+tpu_deinit(struct tpu *tpu)
+{
+
+}
diff --git a/tpu.h b/tpu.h
@@ -0,0 +1,82 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#define TPU_MAP_BUCKETS 64
+
+enum tpu_mode {
+ MODE_IDLE, MODE_RUN, MODE_READ, MODE_WRITE
+};
+
+enum tpu_inst_type {
+ INST_NOP, INST_MOV, INST_SWP, INST_SAV,
+ INST_ADD, INST_SUB, INST_NEG, INST_JMP,
+ INST_JEZ, INST_JNZ, INST_JLZ, INST_JRO
+};
+
+enum tpu_inst_op_type {
+ OP_LIT, OP_UP, OP_DOWN, OP_LEFT, OP_RIGHT,
+ OP_ACC, OP_BAK, OP_NIL, OP_ANY, OP_LAST
+};
+
+enum tpu_port_dir {
+ DIR_UP, DIR_RIGHT, DIR_DOWN, DIR_LEFT
+};
+
+enum tpu_port_type {
+ PORT_IN = 0b01, PORT_OUT = 0b10, PORT_BIDI = 0b11
+};
+
+struct tpu_inst_op {
+ enum tpu_inst_op_type type;
+ uint8_t lit;
+};
+
+struct tpu_inst {
+ enum tpu_inst_type type;
+ struct tpu_inst_op ops[2];
+};
+
+struct tpu_port {
+ struct tpu *dst_tpu;
+ enum tpu_port_type type;
+ struct tpu_port *dst_port;
+ bool write, read;
+ uint8_t val;
+};
+
+struct tpu {
+ struct tpu_port ports[4];
+ uint8_t acc, bak;
+ int x, y;
+
+ size_t pc;
+ struct inst *inst;
+ size_t inst_cap;
+ size_t inst_cnp;
+
+};
+
+struct tpu_map_link {
+ size_t x, y;
+ struct tpu *tpu;
+ struct tpu_map_link *next;
+};
+
+struct tpu_map {
+ struct tpu_map_link *buckets[TPU_MAP_BUCKETS];
+};
+
+void tpu_init(struct tpu *tpu);
+void tpu_add_inst(struct tpu *tpu, enum tpu_inst_type inst,
+ int op1, uint8_t op1_lit, int op2, uint8_t op2_lit);
+void tpu_step(struct tpu *tpu, uint8_t *up, uint8_t *right,
+ uint8_t *down, uint8_t *left);
+void tpu_deinit(struct tpu *tpu);
+
+void tpu_map_init(struct tpu_map *map);
+void tpu_map_add(struct tpu_map *map, struct tpu *tpu);
+struct tpu *tpu_map_get(int x, int y);
+void tpu_map_deinit(struct tpu_map *map);