diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d541bee --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +.PHONY: default + +default: docs + +DOCUMENTS=$(shell find doc/ -name '*.md') + +HTMLDOCS=$(patsubst %.md,%.html,$(DOCUMENTS)) +PDFDOCS=$(patsubst %.md,%.pdf,$(DOCUMENTS)) + +docs: $(HTMLDOCS) $(PDFDOCS) + +%.html: %.md + multimarkdown -t html $^ -o $@ + +%.tex: %.md + multimarkdown -t latex $^ -o $@ + +%.pdf: %.tex doc/arctic-leader.tex doc/arctic-begin.tex doc/arctic-footer.tex + cd $$(dirname $<) && xelatex -interaction=batchmode $< + +print-%: + @echo '$*=$($*)' diff --git a/arctic.nimble b/arctic.nimble deleted file mode 100644 index 50792ac..0000000 --- a/arctic.nimble +++ /dev/null @@ -1,26 +0,0 @@ -# Package - -version = "0.1.0" -author = "Louis Burke" -description = "ARCTIC in Nim" -license = "Apache-2.0" -srcDir = "src" -installExt = @["nim"] -bin = @["arctic", "arctic/load"] -namedBin = {"arctic": "arctic", "arctic/load": "acdump"}.toTable() - -# Dependencies - -requires "nim >= 2.0.0" -requires "bio" -requires "itertools" - -before build: - exec "./generate_handle_syscalls.sh" - -task docs, "docs": - exec "nim doc --project --index:on --outdir:src/htmldocs src/arctic.nim" - exec "multimarkdown -t html doc/documentation.md -o doc/documentation.html" - exec "multimarkdown -t latex doc/documentation.md -o doc/documentation.tex" - exec "sed -i 's/^\\[/{\\[}/' doc/documentation.tex" - exec "cd doc && xelatex -interaction=batchmode documentation.tex" diff --git a/src/arctic.c b/src/arctic.c deleted file mode 100644 index f356038..0000000 --- a/src/arctic.c +++ /dev/null @@ -1,122 +0,0 @@ -#include "arctic.h" - -#include - -const char ARCTIC_CODE_PAGE[97] = - "0123456789ABCDEF" - "GHIJKLMNOPQRSTUV" - "WXYZabcdefghijkl" - "mnopqrstuvwxyz_." - "+-*/%\\|$@<{=}>,;" - "&^![]?~:()'\"` #\n" -; - -/* ops with an immediate argument */ -#define FOR_IMMEDIATE_OPS(X) \ - X('0') X('G') X('H') X('L') X('M') X('P') X('Q') X('d') X('o') X('u') \ - X('@') X('<') X('{') X('=') X('}') X('>') X(',') X(';') X('[') X(']') - -#define FOR_PLAIN_OPS(X) \ - X('1') X('2') X('3') X('4') X('5') X('6') X('7') X('8') X('9') X('A') \ - X('B') X('C') X('D') X('E') X('F') X('I') X('J') X('K') X('N') X('O') \ - X('R') X('S') X('U') X('V') X('W') X('X') X('Y') X('Z') X('a') X('b') \ - X('c') X('e') X('f') X('g') X('h') X('i') X('j') X('k') X('l') X('m') \ - X('n') X('p') X('q') X('r') X('s') X('t') X('v') X('w') X('x') X('y') \ - X('z') X('_') X('.') X('+') X('-') X('*') X('/') X('%') X('\\') X('|') \ - X('&') X('^') X('!') X('?') X('(') X(')') X('`') - -#define CASE(X, ...) case X: - -#define chrncat(str, chr, n, fail) do { \ - char *last; \ - for (last = str; *last; last++) { \ - if (last >= str + n) { \ - fail; \ - } \ - } \ - *last++ = chr; \ - *last = 0; \ -} while (0) - -enum ArcticErrorCode arctic_scan(struct ArcticScanner *scanner, char next) { - switch (scanner->buf[0]) { - case 0: /* initial state */ - switch (next) { - case ' ': - return ARCTIC_OK; - - FOR_IMMEDIATE_OPS(CASE) - case '#': - case ':': - case '\"': - case '\'': - scanner->buf[0] = next; - scanner->buf[1] = 0; - return ARCTIC_OK; - - FOR_PLAIN_OPS(CASE) - case '\n': - scanner->op_callback(next, 0, scanner->data); - return ARCTIC_OK; - - default: - return ARCTIC_UNEXPECTED_CHAR; - } - - case '#': /* comment */ - if (next == '\n') - scanner->buf[0] = 0; - return ARCTIC_OK; - - case '"': /* section switch */ - if (next == '"') { - scanner->section_callback(scanner->buf + 1, scanner->data); - scanner->buf[0] = 0; - } else { - chrncat( - scanner->buf, next, ARCTIC_BUFSIZE, - return ARCTIC_BUFFER_FULL - ); - } - return ARCTIC_OK; - - case ':': /* label name */ - if (next == ' ' || next == '\n' || next == '#') { - scanner->label_callback(scanner->buf + 1, scanner->data); - scanner->buf[0] = (next == '#' ? '#' : 0); - } else { - chrncat( - scanner->buf, next, ARCTIC_BUFSIZE, - return ARCTIC_BUFFER_FULL - ); - } - return ARCTIC_OK; - - case '\'': /* data injection */ - if (next == '\'') { - scanner->data_callback(scanner->buf + 1, scanner->data); - scanner->buf[0] = 0; - } else { - chrncat( - scanner->buf, next, ARCTIC_BUFSIZE, - return ARCTIC_BUFFER_FULL - ); - } - return ARCTIC_OK; - - FOR_IMMEDIATE_OPS(CASE) /* immediate ops */ - if (next == ' ' || next == '\n' || next == '#') { - scanner->op_callback(scanner->buf[0], scanner->buf + 1, scanner->data); - scanner->buf[0] = (next == '#' ? '#' : 0); - } else { - chrncat( - scanner->buf, next, ARCTIC_BUFSIZE, - return ARCTIC_BUFFER_FULL - ); - } - return ARCTIC_OK; - - default: - return ARCTIC_INVALID_STATE; - } -} diff --git a/src/arctic.h b/src/arctic.h deleted file mode 100644 index 6e043e1..0000000 --- a/src/arctic.h +++ /dev/null @@ -1,59 +0,0 @@ -/* ARCTIC library header. To be used as a utility by interpreters and compilers. - * Author: Louis A. Burke - * - * Does not require dynamic memory or a c standard library, so as to be easy to - * use on e.g. microcontrollers. - */ -#ifndef ARCTIC_H -#define ARCTIC_H - -#ifndef ARCTIC_BUFSIZE -#define ARCTIC_BUFSIZE 1024 -#endif /* ARCTIC_BUFSIZE */ - -/* encoding/decoding */ -extern const char ARCTIC_CODE_PAGE[97]; - -/* scanning */ -enum ArcticImmediateKind { - ARCTIC_NONE, ARCTIC_NAME, ARCTIC_INTEGER, ARCTIC_NUMBER -}; - -struct ArcticScanner { - void *data; /* callback data pointer */ - - void (*section_callback)( - const char *name, /* the name of the section */ - void *data /* callback data */ - ); - - void (*label_callback)( - const char *id, /* the identifier itself */ - void *data /* callback data */ - ); - - void (*op_callback)( - char opcode, /* the character code of the operation */ - const char *im, /* the immediate value, if it exists */ - void *data /* callback data */ - ); - - void (*data_callback)( - const char *init, /* initialization code */ - void *data /* callback data */ - ); - - char buf[ARCTIC_BUFSIZE]; -}; - -enum ArcticErrorCode { - ARCTIC_OK = 0, - ARCTIC_UNEXPECTED_CHAR, /* not necessarily an error */ - ARCTIC_INVALID_STATE, - ARCTIC_BUFFER_FULL -}; - -/* returns 0 on success, or an error code */ -enum ArcticErrorCode arctic_scan(struct ArcticScanner *scanner, char next); - -#endif /* ARCTIC_H */ diff --git a/src/arctic.nim b/src/arctic.nim deleted file mode 100644 index adc3ccc..0000000 --- a/src/arctic.nim +++ /dev/null @@ -1,78 +0,0 @@ -import std/[critbits, enumerate, macros, os, tables] - -import bio - -import arctic/[load, memory, step, types] - -var DefaultBuiltins* {.compileTime.}: CritBitTree[ArcticBuiltin] - -macro arctic_builtin(builtin: typed): untyped = - let nameid = builtin.name - let namestr = newLit(nameid.strVal) - - result = quote do: - `builtin` - DefaultBuiltins[`namestr`] = `nameid` - -macro arctic_builtin_secret(builtin: typed): untyped = - let nameid = builtin.name - let namestr = newLit(nameid.strVal & "_") - - result = quote do: - `builtin` - DefaultBuiltins[`namestr`] = `nameid` - -proc putstrln(state: var ArcticState): ArcticStepResult {.arctic_builtin.} = - var p = state.stack.pop.p - while state.memory[p] != 0: - stdout.write(state.memory[p].char) - inc p - stdout.write('\n') - return CONTINUE - -proc debugdump(state: var ArcticState): ArcticStepResult {.arctic_builtin_secret.} = - echo state - return CONTINUE - -proc parseCmdLine(): (File, seq[string]) = - var argv = commandLineParams() - - if len(argv) > 0: - let fname = argv[0] - argv.delete(0) - return (open(fname), argv) - else: - return (stdin, @[]) - - - -when isMainModule: - let (ifile, args) = parseCmdLine() - var state = ifile.readAll.load - let builtins = DefaultBuiltins - - var argv: seq[int] = @[] - for arg in args: - let a = state.memory.allocate(arg.len + 1) - for i in 0 .. arg.len: - state.memory[a + i] = arg[i].uint8 - state.memory[a + arg.len] = 0 - argv.add a - let x = state.memory.allocate((args.len + 1) * 8) - for (i, a) in enumerate(argv): - state.memory.write(x + 8 * i, cast[uint64](a.int64).serialize(littleEndian)) - state.memory.write(x + 8 * args.len, 0.uint64.serialize(littleEndian)) - state.stack.add ArcticType(i: x) # argv - state.stack.add ArcticType(i: args.len) # argc - state.stack.add ArcticType(i: -1) # return address: special "exit" - - while true: - case state.step(builtins): - of CONTINUE: - continue - of BREAKPOINT: - echo state - of EXIT: - break - of ERROR: - break diff --git a/src/arctic/constants.nim b/src/arctic/constants.nim deleted file mode 100644 index 74aab20..0000000 --- a/src/arctic/constants.nim +++ /dev/null @@ -1,3 +0,0 @@ -const - ImmediateOps*: set[char] = {'0', 'E', 'F', 'G', 'H', 'L', 'M', 'P', 'Q', 'd', 'o', 'u', '$', '@', '<', '{', '=', '}', '>', ',', ';', '[', ']', '`'} - PlainOps*: set[char] = { '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'I', 'J', 'K', 'N', 'O', 'R', 'S', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z', '_', '.', '+', '-', '*', '/', '%', '\\', '|', '&', '^', '!', '?', '(', ')' } diff --git a/src/arctic/load.nim b/src/arctic/load.nim deleted file mode 100644 index 262c34b..0000000 --- a/src/arctic/load.nim +++ /dev/null @@ -1,202 +0,0 @@ -import std/[critbits, re, strutils, strmisc] - -import bio -import itertools - -import constants -import memory -import types - -proc tovar(code: char): ArcticVariableIndex = - case code.toLowerAscii: - of 'a': VARIABLE_A - of 'b': VARIABLE_B - of 'c': VARIABLE_C - of 'i': VARIABLE_I - of 'n': VARIABLE_N - of 'x': VARIABLE_X - of 'y': VARIABLE_Y - of 'z': VARIABLE_Z - else: raise new ValueError - -proc parse_immediate(imm: string, section: string): ArcticImmediate = - if imm.match(re"^\d+$"): - return ArcticImmediate(kind: INTEGER, i: imm.parseInt) - elif imm.match(re"^[AaBbCcIiNnXxYyZz]$"): - return ArcticImmediate(kind: VARIABLE, v: imm[0].tovar) - elif imm.len > 0 and imm[0] in "0123456789.": - return ArcticImmediate(kind: NUMBER, n: imm.parseFloat) - else: - if imm.len > 0 and imm[0] == '_': - return ArcticImmediate(kind: SYMBOL, s: section & " " & imm) - else: - return ArcticImmediate(kind: SYMBOL, s: imm) - -func grabnum(data: string): (string, string) = - ## Returns the numeric literal at the start of data, then the rest of data - var i = 0 - while i < data.len and data[i] in "0123456789.": - result[0] &= data[i] - i += 1 - - result[1] = data[i..^1] - -proc parse_data(data: string): seq[uint8] = - if data.len == 0: - return - - template insertInt(itype, utype, endianness) = - let (text, rest) = data[1..^1].grabnum - - if text[0] == '-': - let val: itype = itype(-text[1..^1].parseBiggestInt) - result.add cast[utype](val).serialize(endianness) - else: - let val: utype = utype(text.parseBiggestUInt) - result.add val.serialize(endianness) - - result.add parse_data(rest) - - case data[0]: - of 'i': insertInt(int64, uint64, littleEndian) - of 'I': insertInt(int64, uint64, bigEndian) - of 'w': insertInt(int32, uint32, littleEndian) - of 'W': insertInt(int32, uint32, bigEndian) - of 's': insertInt(int16, uint16, littleEndian) - of 'S': insertInt(int16, uint16, bigEndian) - of 'b', 'B': # bytes don't have an endianness - let (text, rest) = data[1..^1].grabnum - - if text[0] == '-': - let val: int8 = int8(-text[1..^1].parseBiggestInt) - result.add cast[uint8](val) - else: - let val: uint8 = uint8(text.parseBiggestUInt) - result.add val - result.add parse_data(rest) - - of 'f': - let (text, rest) = data[1..^1].grabnum - result.add cast[uint64](text.parseFloat).serialize(littleEndian) - result.add parse_data(rest) - - of 'F': - let (text, rest) = data[1..^1].grabnum - result.add cast[uint64](text.parseFloat).serialize(bigEndian) - result.add parse_data(rest) - - of 'x': # hexadecimal byte constant - let (hex, _, rest) = data[1..^1].partition("x") - for pair in hex.chunked(2): - result.add uint8(parseHexInt(pair.join)) - result.add parse_data(rest) - - of '"': # utf-8 string constant with escapes - let strlen = data.matchLen(re"^""([^""]|\\"")*""") - assert strlen >= 0 - for c in unescape(data[1..strlen - 2], prefix="", suffix=""): - result.add c.uint8 - result.add parse_data(data[strlen..^1]) - - else: - result.add parse_data(data[1..^1]) - -func iscode(secname: string): bool = - if secname.len == 0: - return true - return secname[0] in "cC" - -func isbigendian(secname: string): bool = - if secname.len == 0: - return false - return secname[0] in "C" - -func raw_op(code: char): ArcticOperation = - result.code = code - result.immediate = ArcticImmediate(kind: PLAIN) - -func load*(code: string): ArcticState = - var - section: string = "" - token: string = "" - - result.pc = 1 - - for next in code: - if token.len == 0: # initial state - case next: - of ImmediateOps, '#', ':', '\"', '\'': - token &= next - of PlainOps, '\n': - if section.iscode: - result.code.add(section, raw_op(next)) - else: - discard - else: - case token[0]: - of '#': # comment - if next == '\n': - token = "" - if section.iscode: - result.code.add(section, raw_op(next)) - - of '"': # section switch - if next == '"' and token[^1] != '\\': - section = token[1..^1] - token = "" - else: - token.add next - - of ':': # label name - if next == ' ' or next == '\n': - let idx = if token[1] == '_': section & " " & token[1..^1] else: token[1..^1] - if section.iscode: - result.symbols[idx] = result.code.current(section) - else: - result.memory.register(section) - result.symbols[idx] = result.memory.current(section) - token = "" - else: - token.add next - - of '\'': # data injection - if next == '\'': - var - quoted = false - escaped = false - for c in token: - if c == '"': - if not escaped: - quoted = not quoted - escaped = false - elif c == '\\': - escaped = true - else: - escaped = false - - if quoted or escaped: - token.add next - else: - if not section.iscode: - result.memory.add(section, parse_data(token[1..^1])) - token = "" - else: - token.add next - - of ImmediateOps: - if next in " \n": - if section.iscode: - result.code.add(section, ArcticOperation( - code: token[0], - immediate: parse_immediate(token[1..^1], section), - bigendian: isbigendian(section))) - token = "" - else: - token.add next - - else: - discard - -when isMainModule: - let state = stdin.readAll.load - echo state diff --git a/src/arctic/memory.nim b/src/arctic/memory.nim deleted file mode 100644 index 2627e06..0000000 --- a/src/arctic/memory.nim +++ /dev/null @@ -1,336 +0,0 @@ -import std/[critbits, math, tables] - -type - Memory*[T] = object - ## Memory holds a set of sections and maps addresses in those sections - ## to the range (0, int.high) via a low discrepancy sequence (in this - ## case, the van der corput sequence) - chunks: seq[seq[T]] - sects: CritBitTree[int] # which chunk is the section - # TODO: keep track of lengths and "skip" vdc indices that would overlap - # (only an issue where e.g. section 0 is huge and there are lots - # of sections) - smlmem: Table[int, seq[T]] # index -> buffer - midmem: Table[int, seq[T]] # index -> buffer - bigmem: Table[int, seq[T]] # index -> buffer - hugmem: Table[int, seq[T]] # index -> buffer - # dynamic addresses are: - # (1 shl 18)-element blocks x (1 shl 42) starting from (int.high shr 1) - # (1 shl 26)-element blocks x (1 shl 34) starting from (int.high shr 1) + (1 shl 60) - # (1 shl 34)-element blocks x (1 shl 26) starting from (int.high shr 1) + 2 * (1 shl 60) - # (1 shl 42)-element blocks x (1 shl 18) starting from (int.high shr 1) + 3 * (1 shl 60) - -const - HUG_BLOCK_SIZE = 1 shl 42 - BIG_BLOCK_SIZE = 1 shl 34 - MID_BLOCK_SIZE = 1 shl 26 - SML_BLOCK_SIZE = 1 shl 18 - - HUG_BLOCK_COUNT = 1 shl 18 - BIG_BLOCK_COUNT = 1 shl 26 - MID_BLOCK_COUNT = 1 shl 34 - SML_BLOCK_COUNT = 1 shl 42 - - SML_BLOCK_START = int.high shr 1 - MID_BLOCK_START = SML_BLOCK_START + (1 shl 60) - BIG_BLOCK_START = MID_BLOCK_START + (1 shl 60) - HUG_BLOCK_START = BIG_BLOCK_START + (1 shl 60) - -proc van_der_corput(n: int): int = - var - q = 1 # 0 is reserved for null - i = n - b = int.high shr 2 # int.high/2 .. int.high is reserved for dynmem - - while i > 0: - q += (i and 1) * b - i = i shr 1 - b = b shr 1 - - return q - -proc register*[T](memory: var Memory[T], section: string) = - ## Registers a section as existing in this memory space, without adding any - ## data to it - if not (section in memory.sects): - memory.sects[section] = memory.chunks.len - memory.chunks.add @[] - -proc add*[T](memory: var Memory[T], section: string, value: T) = - ## Adds value to the end of memory in section. - if not (section in memory.sects): - memory.sects[section] = memory.chunks.len - memory.chunks.add @[] - - memory.chunks[memory.sects[section]].add value - -proc add*[T](memory: var Memory[T], section: string, values: openarray[T]) = - ## Adds value to the end of memory in section. - if not (section in memory.sects): - memory.sects[section] = memory.chunks.len - memory.chunks.add @[] - - memory.chunks[memory.sects[section]].add values - -proc address*[T](memory: Memory[T], section: string, offset: int): int = - ## Computes the "real" address of a given section and offset - return van_der_corput(memory.sects[section]) + offset - -proc current*[T](memory: Memory[T], section: string): int = - ## Computes the "real" address of the "next" element in the section - let i = memory.sects[section] - return van_der_corput(i) + len(memory.chunks[i]) - -proc addrinfo[T](memory: Memory[T], address: int): (int, int) = - ## Calculates which section index an address points to and the offset in it - var - index = 0 - start = van_der_corput(index) - - for i in 1 .. memory.chunks.len: - let corput = van_der_corput(i) - if (corput < address) and (corput > start): - index = i - start = corput - - return (index, address - start) - -proc contains*[T](memory: Memory[T], address: int): bool = - ## Checks if the given address is a valid allocated address - if address < SML_BLOCK_START: - let (idx, off) = memory.addrinfo(address) - return memory.chunks[idx].len >= off - elif address < MID_BLOCK_START: - let (blkid, offset) = divmod(address - SML_BLOCK_START, SML_BLOCK_SIZE) - return memory.smlmem[blkid].len >= offset - elif address < BIG_BLOCK_START: - let (blkid, offset) = divmod(address - MID_BLOCK_START, MID_BLOCK_SIZE) - return memory.midmem[blkid].len >= offset - elif address < HUG_BLOCK_START: - let (blkid, offset) = divmod(address - BIG_BLOCK_START, BIG_BLOCK_SIZE) - return memory.bigmem[blkid].len >= offset - else: - let (blkid, offset) = divmod(address - HUG_BLOCK_START, HUG_BLOCK_SIZE) - return memory.hugmem[blkid].len >= offset - -proc raw_address*[T](memory: var Memory[T], address: int): ptr T = - ## Returns the "raw" address of a given section and offset - if address < SML_BLOCK_START: - let (idx, off) = memory.addrinfo(address) - return addr memory.chunks[idx][off] - elif address < MID_BLOCK_START: - let (blkid, offset) = divmod(address - SML_BLOCK_START, SML_BLOCK_SIZE) - return addr memory.smlmem[blkid][offset] - elif address < BIG_BLOCK_START: - let (blkid, offset) = divmod(address - MID_BLOCK_START, MID_BLOCK_SIZE) - return addr memory.midmem[blkid][offset] - elif address < HUG_BLOCK_START: - let (blkid, offset) = divmod(address - BIG_BLOCK_START, BIG_BLOCK_SIZE) - return addr memory.bigmem[blkid][offset] - else: - let (blkid, offset) = divmod(address - HUG_BLOCK_START, HUG_BLOCK_SIZE) - return addr memory.hugmem[blkid][offset] - -proc `[]`*[T](memory: Memory[T], address: int): T = - ## Accesses the underlying memory item for the given address, failing if it - ## does not exist - if address < SML_BLOCK_START: - let (idx, off) = memory.addrinfo(address) - return memory.chunks[idx][off] - elif address < MID_BLOCK_START: - let (blkid, offset) = divmod(address - SML_BLOCK_START, SML_BLOCK_SIZE) - return memory.smlmem[blkid][offset] - elif address < BIG_BLOCK_START: - let (blkid, offset) = divmod(address - MID_BLOCK_START, MID_BLOCK_SIZE) - return memory.midmem[blkid][offset] - elif address < HUG_BLOCK_START: - let (blkid, offset) = divmod(address - BIG_BLOCK_START, BIG_BLOCK_SIZE) - return memory.bigmem[blkid][offset] - else: - let (blkid, offset) = divmod(address - HUG_BLOCK_START, HUG_BLOCK_SIZE) - return memory.hugmem[blkid][offset] - -proc `[]`*[T](memory: var Memory[T], address: int): var T = - ## Accesses the underlying memory item for the given address, failing if it - ## does not exist - if address < SML_BLOCK_START: - let (idx, off) = memory.addrinfo(address) - return memory.chunks[idx][off] - elif address < MID_BLOCK_START: - let (blkid, offset) = divmod(address - SML_BLOCK_START, SML_BLOCK_SIZE) - return memory.smlmem[blkid][offset] - elif address < BIG_BLOCK_START: - let (blkid, offset) = divmod(address - MID_BLOCK_START, MID_BLOCK_SIZE) - return memory.midmem[blkid][offset] - elif address < HUG_BLOCK_START: - let (blkid, offset) = divmod(address - BIG_BLOCK_START, BIG_BLOCK_SIZE) - return memory.bigmem[blkid][offset] - else: - let (blkid, offset) = divmod(address - HUG_BLOCK_START, HUG_BLOCK_SIZE) - return memory.hugmem[blkid][offset] - -proc `[]=`*[T](memory: var Memory[T], address: int, value: T) = - ## Writes to the underlying memory item for a given address, failing if it - ## does not exist - if address < SML_BLOCK_START: - let (idx, off) = memory.addrinfo(address) - memory.chunks[idx][off] = value - elif address < MID_BLOCK_START: - let (blkid, offset) = divmod(address - SML_BLOCK_START, SML_BLOCK_SIZE) - memory.smlmem[blkid][offset] = value - elif address < BIG_BLOCK_START: - let (blkid, offset) = divmod(address - MID_BLOCK_START, MID_BLOCK_SIZE) - memory.midmem[blkid][offset] = value - elif address < HUG_BLOCK_START: - let (blkid, offset) = divmod(address - BIG_BLOCK_START, BIG_BLOCK_SIZE) - memory.bigmem[blkid][offset] = value - else: - let (blkid, offset) = divmod(address - HUG_BLOCK_START, HUG_BLOCK_SIZE) - memory.hugmem[blkid][offset] = value - -proc write*[T](memory: var Memory[T], address: int, values: openArray[T]) = - ## Writes to the underlying memory item for a given address, failing if it - ## does not exist - var a = address - for i in values: - memory[a] = i - inc a - -proc section*[T](memory: Memory[T], address: int): string = - ## Calculates which section a given address points to (warning: slow) - let (idx, off) = memory.addrinfo(address) - - for (section, index) in memory.sects.pairs: - if index == idx: - return section - - return "" - -iterator sections*[T](memory: Memory[T]): string = - for section in memory.sects.keys: - yield section - -proc data*[T](memory: Memory[T], section: string): seq[T] = - return memory.chunks[memory.sects[section]] - -proc allocate*[T](memory: var Memory[T], count: int): int = - ## Allocates a block of count values that can be addressed starting from the - ## returned value - if count < SML_BLOCK_SIZE: - var i = 0 - while i in memory.smlmem: - inc i - if i > SML_BLOCK_COUNT: - raise new ResourceExhaustedError - memory.smlmem[i] = newSeq[T](count) - return SML_BLOCK_START + SML_BLOCK_SIZE * i - elif count < MID_BLOCK_SIZE: - var i = 0 - while i in memory.smlmem: - inc i - if i > MID_BLOCK_COUNT: - raise new ResourceExhaustedError - memory.smlmem[i] = newSeq[T](count) - return MID_BLOCK_START + MID_BLOCK_SIZE * i - elif count < BIG_BLOCK_SIZE: - var i: int = 0 - while i in memory.smlmem: - inc i - if i > BIG_BLOCK_COUNT: - raise new ResourceExhaustedError - memory.smlmem[i] = newSeq[T](count) - return BIG_BLOCK_START + BIG_BLOCK_SIZE * i - else: - var i = 0 - while i in memory.smlmem: - inc i - if i > HUG_BLOCK_COUNT: - raise new ResourceExhaustedError - memory.smlmem[i] = newSeq[T](count) - return HUG_BLOCK_START + HUG_BLOCK_SIZE * i - -proc deallocate*[T](memory: var Memory[T], address: int) = - ## Deallocates the block containing address - if address < SML_BLOCK_START: - discard # Can't deallocate static memory - elif address < MID_BLOCK_START: - let blkid = (address - SML_BLOCK_START) div SML_BLOCK_SIZE - memory.smlmem[blkid].setLen(0) - memory.smlmem.del(blkid) - elif address < BIG_BLOCK_START: - let blkid = (address - MID_BLOCK_START) div MID_BLOCK_SIZE - memory.midmem[blkid].setLen(0) - memory.midmem.del(blkid) - elif address < HUG_BLOCK_START: - let blkid = (address - BIG_BLOCK_START) div BIG_BLOCK_SIZE - memory.bigmem[blkid].setLen(0) - memory.bigmem.del(blkid) - else: - let blkid = (address - HUG_BLOCK_START) div HUG_BLOCK_SIZE - memory.hugmem[blkid].setLen(0) - memory.hugmem.del(blkid) - -proc reallocate*[T](memory: var Memory[T], address: int, count: int): int = - ## Reallocates the block containing address to store up to count items - var theseq: seq[T] - if address < SML_BLOCK_START: - return address # Can't reallocate static memory - elif address < MID_BLOCK_START: - let blkid = (address - SML_BLOCK_START) div SML_BLOCK_SIZE - if count <= SML_BLOCK_SIZE: - memory.smlmem[blkid].setLen(count) - return address - assert memory.smlmem.pop(blkid, theseq) - elif address < BIG_BLOCK_START: - let blkid = (address - MID_BLOCK_START) div MID_BLOCK_SIZE - if count <= MID_BLOCK_SIZE: - memory.midmem[blkid].setLen(count) - return address - assert memory.midmem.pop(blkid, theseq) - elif address < HUG_BLOCK_START: - let blkid = (address - BIG_BLOCK_START) div BIG_BLOCK_SIZE - if count <= BIG_BLOCK_SIZE: - memory.bigmem[blkid].setLen(count) - return address - assert memory.bigmem.pop(blkid, theseq) - else: - let blkid = (address - HUG_BLOCK_START) div HUG_BLOCK_SIZE - if count <= HUG_BLOCK_SIZE: - memory.hugmem[blkid].setLen(count) - return address - assert memory.hugmem.pop(blkid, theseq) - - theseq.setLen(count) - - if count < SML_BLOCK_SIZE: - var i = 0 - while i in memory.smlmem: - inc i - if i > SML_BLOCK_COUNT: - raise new ResourceExhaustedError - memory.smlmem[i] = theseq - return SML_BLOCK_START + SML_BLOCK_SIZE * i - elif count < MID_BLOCK_SIZE: - var i = 0 - while i in memory.smlmem: - inc i - if i > MID_BLOCK_COUNT: - raise new ResourceExhaustedError - memory.smlmem[i] = theseq - return MID_BLOCK_START + MID_BLOCK_SIZE * i - elif count < BIG_BLOCK_SIZE: - var i = 0 - while i in memory.smlmem: - inc i - if i > BIG_BLOCK_COUNT: - raise new ResourceExhaustedError - memory.smlmem[i] = theseq - return BIG_BLOCK_START + BIG_BLOCK_SIZE * i - else: - var i = 0 - while i in memory.smlmem: - inc i - if i > HUG_BLOCK_COUNT: - raise new ResourceExhaustedError - memory.smlmem[i] = theseq - return HUG_BLOCK_START + HUG_BLOCK_SIZE * i diff --git a/src/arctic/step.nim b/src/arctic/step.nim deleted file mode 100644 index 5fe413d..0000000 --- a/src/arctic/step.nim +++ /dev/null @@ -1,746 +0,0 @@ -import std/[bitops, critbits, math] - -import memory -import types -import handle_syscalls - -proc branch(state: var ArcticState, count: int) = - var n = 0 - if count > 0: - while n < count: - state.pc.inc - if state.code[state.pc].code == '\n': - n.inc - else: - while n > count: - state.pc.dec - if state.code[state.pc].code == '\n': - n.dec - - -proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): ArcticStepResult = - if not (state.pc in state.code): - return EXIT - - if state.pc == 0: - return EXIT - let op = state.code[state.pc] - state.pc.inc - - case op.code: - # Memory Ops ----------------------------------------------------------- - of '1': # LDAB - let p = state.stack.pop.p - state.stack.add ArcticType(i: state.memory[p].int64) - - of '2': # LDAS - let - p = state.stack.pop.p - a = state.memory[p].int64 - b = state.memory[p+1].int64 - if op.bigendian: - state.stack.add ArcticType(i: a or b shl 8) - else: - state.stack.add ArcticType(i: b or a shl 8) - - of '3': # LDAI - let - p = state.stack.pop.p - a = state.memory[p].int64 - b = state.memory[p+1].int64 - c = state.memory[p+2].int64 - d = state.memory[p+3].int64 - if op.bigendian: - state.stack.add ArcticType(i: d or c shl 8 or b shl 16 or a shl 24) - else: - state.stack.add ArcticType(i: a or b shl 8 or c shl 16 or d shl 24) - - of '4': # LDAW - let - p = state.stack.pop.p - a = state.memory[p].int64 - b = state.memory[p+1].int64 - c = state.memory[p+2].int64 - d = state.memory[p+3].int64 - e = state.memory[p+4].int64 - f = state.memory[p+5].int64 - g = state.memory[p+6].int64 - h = state.memory[p+7].int64 - if op.bigendian: - state.stack.add ArcticType(i: h or g shl 8 or f shl 16 or e shl 24 or d shl 32 or c shl 40 or b shl 48 or a shl 56) - else: - state.stack.add ArcticType(i: a or b shl 8 or c shl 16 or d shl 24 or e shl 32 or f shl 40 or g shl 48 or h shl 56) - - of 'o': # LDOB - assert op.immediate.kind == INTEGER - let p = state.stack.pop.p - state.stack.add ArcticType(i: state.memory[p+op.immediate.i].int64) - - of 'H': # LDOS - assert op.immediate.kind == INTEGER - let - p = state.stack.pop.p + op.immediate.i - a = state.memory[p].int64 - b = state.memory[p+1].int64 - if op.bigendian: - state.stack.add ArcticType(i: a or b shl 8) - else: - state.stack.add ArcticType(i: b or a shl 8) - - of 'G': # LDOI - let - p = state.stack.pop.p + op.immediate.i - a = state.memory[p].int64 - b = state.memory[p+1].int64 - c = state.memory[p+2].int64 - d = state.memory[p+3].int64 - if op.bigendian: - state.stack.add ArcticType(i: d or c shl 8 or b shl 16 or a shl 24) - else: - state.stack.add ArcticType(i: a or b shl 8 or c shl 16 or d shl 24) - - of 'Q': # LDOW - let - p = state.stack.pop.p - a = state.memory[p].int64 - b = state.memory[p+1].int64 - c = state.memory[p+2].int64 - d = state.memory[p+3].int64 - e = state.memory[p+4].int64 - f = state.memory[p+5].int64 - g = state.memory[p+6].int64 - h = state.memory[p+7].int64 - if op.bigendian: - state.stack.add ArcticType(i: h or g shl 8 or f shl 16 or e shl 24 or d shl 32 or c shl 40 or b shl 48 or a shl 56) - else: - state.stack.add ArcticType(i: a or b shl 8 or c shl 16 or d shl 24 or e shl 32 or f shl 40 or g shl 48 or h shl 56) - - of '5': # STAB - let - x = cast[uint8](state.stack.pop.b) - p = state.stack.pop.p - state.memory[p] = x - - of '6': # STAS - let - x = cast[uint16](state.stack.pop.s) - p = state.stack.pop.p - if op.bigendian: - state.memory[p] = uint8(x and 0xFF) - state.memory[p+1] = uint8(x shr 8) - else: - state.memory[p] = uint8(x shr 8) - state.memory[p+1] = uint8(x and 0xFF) - - of '7': # STAI - let - x = cast[uint32](state.stack.pop.i) - p = state.stack.pop.p - if op.bigendian: - state.memory[p] = uint8(x and 0xFF) - state.memory[p+1] = uint8((x shr 8) and 0xFF) - state.memory[p+2] = uint8((x shr 16) and 0xFF) - state.memory[p+3] = uint8((x shr 24) and 0xFF) - else: - state.memory[p] = uint8((x shr 24) and 0xFF) - state.memory[p+1] = uint8((x shr 16) and 0xFF) - state.memory[p+2] = uint8((x shr 8) and 0xFF) - state.memory[p+3] = uint8(x and 0xFF) - - of '8': # STAW - let - x = cast[uint64](state.stack.pop.i) - p = state.stack.pop.p - if op.bigendian: - state.memory[p] = uint8(x and 0xFF) - state.memory[p+1] = uint8((x shr 8) and 0xFF) - state.memory[p+2] = uint8((x shr 16) and 0xFF) - state.memory[p+3] = uint8((x shr 24) and 0xFF) - state.memory[p+4] = uint8((x shr 32) and 0xFF) - state.memory[p+5] = uint8((x shr 40) and 0xFF) - state.memory[p+6] = uint8((x shr 48) and 0xFF) - state.memory[p+7] = uint8((x shr 56) and 0xFF) - else: - state.memory[p] = uint8((x shr 56) and 0xFF) - state.memory[p+1] = uint8((x shr 48) and 0xFF) - state.memory[p+2] = uint8((x shr 40) and 0xFF) - state.memory[p+3] = uint8((x shr 32) and 0xFF) - state.memory[p+4] = uint8((x shr 24) and 0xFF) - state.memory[p+5] = uint8((x shr 16) and 0xFF) - state.memory[p+6] = uint8((x shr 8) and 0xFF) - state.memory[p+7] = uint8(x and 0xFF) - - of 'D': # MCLR - let - x = state.stack.pop.i - p = state.stack.pop.p - for i in 0 .. x: - state.memory[p+i] = 0 - - of 'd': # MSET - assert op.immediate.kind == INTEGER - let - x = state.stack.pop.i - p = state.stack.pop.p - b = op.immediate.i.uint8 - for i in 0 .. x: - state.memory[p+i] = b - - of 'K': # MCPY - let - x = state.stack.pop.i - q = state.stack.pop.p - p = state.stack.pop.p - for i in 0 .. x: - state.memory[q+i] = state.memory[p+i] - - of 'J': # MOFF - let - x = state.stack.pop.i - p = state.stack.pop.p - state.stack.add ArcticType(p: p + x) - - of 'M': # MALL - assert op.immediate.kind == INTEGER - let - top = state.stack.pop - n = op.immediate.i - - if n == 0: - if top.i != 0: - state.memory.deallocate(top.p) - state.stack.add ArcticType(i: 0) - elif n > 0: - if top.i == 0: - state.stack.add ArcticType(p: state.memory.allocate(n)) - else: - state.stack.add ArcticType(p: state.memory.reallocate(top.p, n)) - else: - discard # realloc negative is a nop - - of 'R': # REAL - let - top = state.stack.pop - x = state.stack.pop.i - - if x == 0: - if top.i != 0: - state.memory.deallocate(top.p) - state.stack.add ArcticType(i: 0) - elif x > 0: - if top.i == 0: - state.stack.add ArcticType(p: state.memory.allocate(x)) - else: - state.stack.add ArcticType(p: state.memory.reallocate(top.p, x)) - else: - discard # realloc negative is a nop - - of '9': # CASS - # TODO: Actually CAS? need to use Atomic[T] for that... - # implementation would probably require an "atomic" memory - # section - let - y = state.stack.pop.i - x = state.stack.pop.i - p = state.stack.pop.p - a = state.memory[p].int64 - b = state.memory[p+1].int64 - c = state.memory[p+2].int64 - d = state.memory[p+3].int64 - e = state.memory[p+4].int64 - f = state.memory[p+5].int64 - g = state.memory[p+6].int64 - h = state.memory[p+7].int64 - - var old: int64 - if op.bigendian: - old = h or g shl 8 or f shl 16 or e shl 24 or d shl 32 or c shl 40 or b shl 48 or a shl 56 - else: - old = a or b shl 8 or c shl 16 or d shl 24 or e shl 32 or f shl 40 or g shl 48 or h shl 56 - - if x == old: - state.stack.add ArcticType(i: 1) - if op.bigendian: - state.memory[p] = uint8(y and 0xFF) - state.memory[p+1] = uint8((y shr 8) and 0xFF) - state.memory[p+2] = uint8((y shr 16) and 0xFF) - state.memory[p+3] = uint8((y shr 24) and 0xFF) - state.memory[p+4] = uint8((y shr 32) and 0xFF) - state.memory[p+5] = uint8((y shr 40) and 0xFF) - state.memory[p+6] = uint8((y shr 48) and 0xFF) - state.memory[p+7] = uint8((y shr 56) and 0xFF) - else: - state.memory[p] = uint8((y shr 56) and 0xFF) - state.memory[p+1] = uint8((y shr 48) and 0xFF) - state.memory[p+2] = uint8((y shr 40) and 0xFF) - state.memory[p+3] = uint8((y shr 32) and 0xFF) - state.memory[p+4] = uint8((y shr 24) and 0xFF) - state.memory[p+5] = uint8((y shr 16) and 0xFF) - state.memory[p+6] = uint8((y shr 8) and 0xFF) - state.memory[p+7] = uint8(y and 0xFF) - else: - state.stack.add ArcticType(i: 0) - - - # Math Ops ----------------------------------------------------------- - of '+': # IADD - let - y = state.stack.pop.i - x = state.stack.pop.i - - state.stack.add ArcticType(i: x + y) - - of '-': # ISUB - let - y = state.stack.pop.i - x = state.stack.pop.i - - state.stack.add ArcticType(i: x - y) - - of '*': # IMUL - let - y = state.stack.pop.i - x = state.stack.pop.i - - state.stack.add ArcticType(i: x * y) - - of '/': # IDIV - let - y = state.stack.pop.i - x = state.stack.pop.i - - state.stack.add ArcticType(i: int(x / y)) - - of '%': # IMOD - let - y = state.stack.pop.i - x = state.stack.pop.i - - state.stack.add ArcticType(i: x.floorMod(y)) - - of '\\': # IREM - let - y = state.stack.pop.i - x = state.stack.pop.i - - state.stack.add ArcticType(i: x mod y) - - of '_': # INEG - let x = state.stack.pop.i - state.stack.add ArcticType(i: -x) - - of '|': # IABS - let x = state.stack.pop.i - state.stack.add ArcticType(i: x.abs) - - of 's': # FADD - let - b = state.stack.pop.d - a = state.stack.pop.d - - state.stack.add ArcticType(d: a + b) - - of 'm': # FSUB - let - b = state.stack.pop.d - a = state.stack.pop.d - - state.stack.add ArcticType(d: a - b) - - of 'p': # FMUL - let - b = state.stack.pop.d - a = state.stack.pop.d - - state.stack.add ArcticType(d: a * b) - - of 'q': # FDIV - let - b = state.stack.pop.d - a = state.stack.pop.d - - state.stack.add ArcticType(d: a / b) - - of 'f': # FMOD - let - b = state.stack.pop.d - a = state.stack.pop.d - - state.stack.add ArcticType(d: floorMod(a, b)) - - of 'r': # FREM - let - b = state.stack.pop.d - a = state.stack.pop.d - - state.stack.add ArcticType(d: a mod b) - - of 'j': # FNEG - let - a = state.stack.pop.d - - state.stack.add ArcticType(d: -a) - - of 'v': # FABS - let - a = state.stack.pop.d - - state.stack.add ArcticType(d: a.abs) - - of 'V': # BIOR - let - y = state.stack.pop.i - x = state.stack.pop.i - - state.stack.add ArcticType(i: x or y) - - of '&': # BAND - let - y = state.stack.pop.i - x = state.stack.pop.i - - state.stack.add ArcticType(i: x and y) - - of '^': # BXOR - let - y = state.stack.pop.i - x = state.stack.pop.i - - state.stack.add ArcticType(i: x xor y) - - of 'l': # BITC - let - y = state.stack.pop.i - x = state.stack.pop.i - - state.stack.add ArcticType(i: x and (not y)) - - of '!': # BNOT - let x = state.stack.pop.i - - state.stack.add ArcticType(i: not x) - - of 'u': # USHR - let x = state.stack.pop.i - var i: int64 - case op.immediate.kind: - of INTEGER: - i = op.immediate.i - of VARIABLE: - let v = op.immediate.v - i = state.registers[v].i - else: - echo "Unexpected immediate: ", op - assert false - - if i > 0: - state.stack.add ArcticType(i: x shr i) - else: - state.stack.add ArcticType(i: x shl (-i)) - - of '[': # ROTR - let x = state.stack.pop.u - var i: int64 - case op.immediate.kind: - of INTEGER: - i = op.immediate.i - of VARIABLE: - let v = op.immediate.v - i = state.registers[v].i - else: - assert false - - if i > 0: - state.stack.add ArcticType(u: rotateRightBits(x, i)) - else: - state.stack.add ArcticType(u: rotateLeftBits(x, -i)) - - of ']': # BSHR - let x = state.stack.pop.u - var i: int64 - case op.immediate.kind: - of INTEGER: - i = op.immediate.i - of VARIABLE: - let v = op.immediate.v - i = state.registers[v].i - else: - assert false - - if i > 0: - state.stack.add ArcticType(u: rotateRightBits(x, i)) - else: - state.stack.add ArcticType(u: rotateLeftBits(x, -i)) - - of '?': # CMPI - let - y = state.stack.pop.i - x = state.stack.pop.i - if x > y: - state.stack.add ArcticType(i: 1) - elif y > x: - state.stack.add ArcticType(i: -1) - else: - state.stack.add ArcticType(i: 0) - - of '~': # CMPF - assert op.immediate.kind == INTEGER - let - b = state.stack.pop.d - a = state.stack.pop.d - if almostEqual(a, b, op.immediate.i.Natural): - state.stack.add ArcticType(d: 0.0) - elif a > b: - state.stack.add ArcticType(d: 1.0) - else: - state.stack.add ArcticType(d: -1.0) - - of 'U': # CMPU - let - y = state.stack.pop.u - x = state.stack.pop.u - if x > y: - state.stack.add ArcticType(i: 1) - elif y > x: - state.stack.add ArcticType(i: -1) - else: - state.stack.add ArcticType(i: 0) - - of 'F': # BMIS - discard # TODO: define BMIS - - # Type Conversion Ops -------------------------------------------------- - of 'E': # FTOI - let a = state.stack.pop.d - state.stack.add ArcticType(i: a.int64) - - of 'O': # ITOC - let x = state.stack.pop.b - state.stack.add ArcticType(i: x.int64) - - of 'S': # ITOS - let x = state.stack.pop.s - state.stack.add ArcticType(i: x.int64) - - of 'W': # ITOW - let x = state.stack.pop.i - state.stack.add ArcticType(i: x.int64) - - of '.': # ITOF - let x = state.stack.pop.i - state.stack.add ArcticType(d: x.float64) - - # Stack Ops ------------------------------------------------------------ - of 'w': # SDUP - let x = state.stack.pop - state.stack.add x - state.stack.add x - - of 'k': # SPOP - discard state.stack.pop - - of 't': # SWAP - let - y = state.stack.pop - x = state.stack.pop - state.stack.add y - state.stack.add x - - of 'h': # OVER - let - y = state.stack.pop - x = state.stack.pop - state.stack.add x - state.stack.add y - state.stack.add x - - of 'e': # SROT - let - z = state.stack.pop - y = state.stack.pop - x = state.stack.pop - state.stack.add y - state.stack.add z - state.stack.add x - - of 'P': # PICK - assert op.immediate.kind == INTEGER - let val = state.stack[^op.immediate.i] - state.stack.add val - - of 'L': # ROLL - assert op.immediate.kind == INTEGER - let idx: int = state.stack.len - op.immediate.i # TODO: check for OBOEs - state.stack.delete(idx) - - of 'T': # PUSH - assert op.immediate.kind == INTEGER - let - idx: int = state.stack.len - op.immediate.i # TODO: check for OBOEs - x = state.stack.pop - state.stack.insert(x, idx) - - of '(': # DPTH - state.stack.add ArcticType(i: state.stack.len) - - of ')': # PACK - let x = state.stack.pop.i - var p = state.stack.pop.p - - for i in countdown(x - 1, 0): - var n = state.stack[^i].u - for _ in 0 .. 8: - state.memory[p] = uint8(n and 0xFF) - n = n shr 8 - inc p - - # Control Ops ---------------------------------------------------------- - of '=': # BEQZ - assert op.immediate.kind == INTEGER - let cond = state.stack.pop.i - - if cond == 0: - state.branch op.immediate.i - - of '0': # BNEZ - assert op.immediate.kind == INTEGER - let cond = state.stack.pop.i - - if cond != 0: - state.branch op.immediate.i - - of '<': # BLTZ - assert op.immediate.kind == INTEGER - let cond = state.stack.pop.i - - if cond < 0: - state.branch op.immediate.i - - of '>': # BGTZ - assert op.immediate.kind == INTEGER - let cond = state.stack.pop.i - - if cond > 0: - state.branch op.immediate.i - - of '{': # BLEZ - assert op.immediate.kind == INTEGER - let cond = state.stack.pop.i - - if cond <= 0: - state.branch op.immediate.i - - of '}': # BGEZ - assert op.immediate.kind == INTEGER - let cond = state.stack.pop.i - - if cond >= 0: - state.branch op.immediate.i - - of 'g': # FINV - let f = state.stack.pop.f - state.stack.add ArcticType(f: state.pc) - state.pc = f - - of '@': # CALL - assert op.immediate.kind == SYMBOL - let f = state.symbols[op.immediate.s] - state.stack.add ArcticType(f: state.pc) - state.pc = f - - of ',': # JUMP - assert op.immediate.kind == SYMBOL - let f = state.symbols[op.immediate.s] - state.pc = f - - of ';': # RETN - let f = state.stack.pop.f - state.pc = f - - # Variable Ops --------------------------------------------------------- - of 'A': # PUTA - state.registers[VARIABLE_A] = state.stack.pop - - of 'B': # PUTB - state.registers[VARIABLE_B] = state.stack.pop - - of 'C': # PUTC - state.registers[VARIABLE_C] = state.stack.pop - - of 'I': # PUTI - state.registers[VARIABLE_I] = state.stack.pop - - of 'N': # PUTN - state.registers[VARIABLE_N] = state.stack.pop - - of 'X': # PUTX - state.registers[VARIABLE_X] = state.stack.pop - - of 'Y': # PUTY - state.registers[VARIABLE_Y] = state.stack.pop - - of 'Z': # PUTZ - state.registers[VARIABLE_Z] = state.stack.pop - - of 'a': # GETA - state.stack.add state.registers[VARIABLE_A] - - of 'b': # GETB - state.stack.add state.registers[VARIABLE_B] - - of 'c': # GETC - state.stack.add state.registers[VARIABLE_C] - - of 'i': # GETI - state.stack.add state.registers[VARIABLE_I] - - of 'n': # GETN - state.stack.add state.registers[VARIABLE_N] - - of 'x': # GETX - state.stack.add state.registers[VARIABLE_X] - - of 'y': # GETY - state.stack.add state.registers[VARIABLE_Y] - - of 'z': # GETZ - state.stack.add state.registers[VARIABLE_Z] - - # Miscellaneous Ops ---------------------------------------------------- - of '$': # VALU - case op.immediate.kind: - of PLAIN: - state.stack.add ArcticType(i: 0) - of VARIABLE: - state.stack.add state.registers[op.immediate.v] - of INTEGER: - state.stack.add ArcticType(i: op.immediate.i) - of NUMBER: - state.stack.add ArcticType(d: op.immediate.n) - of SYMBOL: - state.stack.add ArcticType(p: state.symbols[op.immediate.s]) - - of '`': # BIFC - case op.immediate.kind: - of PLAIN: - discard - of VARIABLE: - discard - of INTEGER: - state.handle_syscall(op.immediate.i) - of NUMBER: - discard - of SYMBOL: - let callback = builtins[op.immediate.s] - return callback(state) - - of ' ': # NOOP - discard - - of '\n': # BEAT - discard - - else: # Unknown opcode - discard - - return CONTINUE diff --git a/src/arctic/types.nim b/src/arctic/types.nim deleted file mode 100644 index 99d70d0..0000000 --- a/src/arctic/types.nim +++ /dev/null @@ -1,116 +0,0 @@ -import std/[critbits, strformat, tables] - -import memory - -type - ArcticPointer* = int64 - - ArcticType* {.union.} = object - b*: int8 - s*: int16 - w*: int32 - i*: int64 - u*: uint64 - d*: float64 - p*: ArcticPointer - f*: ArcticPointer - - ArcticVariableIndex* = enum - VARIABLE_A, VARIABLE_B, VARIABLE_C, - VARIABLE_I, VARIABLE_N, - VARIABLE_X, VARIABLE_Y, VARIABLE_Z - - ArcticImmediateKind* = enum - PLAIN, VARIABLE, INTEGER, NUMBER, SYMBOL - - ArcticImmediate* = object - case kind*: ArcticImmediateKind - of PLAIN: nil - of VARIABLE: v*: ArcticVariableIndex - of INTEGER: i*: int64 - of NUMBER: n*: float64 - of SYMBOL: s*: string - - ArcticOperation* = object - code*: char - immediate*: ArcticImmediate - bigendian*: bool - - ArcticStack* = seq[ArcticType] - - ArcticState* = object - memory*: Memory[uint8] - code*: Memory[ArcticOperation] - symbols*: CritBitTree[ArcticPointer] # as name or section _name - stack*: ArcticStack - pc*: ArcticPointer # NOT negative! - registers*: array[ArcticVariableIndex, ArcticType] - dynmem*: Table[ArcticPointer, int] # pointer -> length - - ArcticStepResult* = enum - CONTINUE, BREAKPOINT, EXIT, ERROR - - ArcticBuiltin* = proc (state: var ArcticState): ArcticStepResult {.nimcall.} - -proc `$`*(value: ArcticType): string = - return &"{value.u:016X}" - # return &"(b:0x{value.b:2X}/{value.b}/'{value.b.char}',s:0x{value.s:4X}/{value.s},w:0x{value.w:8X}/{value.w},i:{value.i},u:{value.u},d:{value.d},p/f:{value.u:016X})" - -proc `$`*(variable: ArcticVariableIndex): string = - case variable: - of VARIABLE_A: return "A" - of VARIABLE_B: return "B" - of VARIABLE_C: return "C" - of VARIABLE_I: return "I" - of VARIABLE_N: return "N" - of VARIABLE_X: return "X" - of VARIABLE_Y: return "Y" - of VARIABLE_Z: return "Z" - -proc `$`*(op: ArcticOperation): string = - result &= op.code - - case op.immediate.kind: - of PLAIN: discard - of VARIABLE: result &= $op.immediate.v - of INTEGER: result &= $op.immediate.i - of NUMBER: result &= $op.immediate.n - of SYMBOL: result &= $op.immediate.s - -proc `$`*(state: ArcticState): string = - result &= "Registers:\n" - for idx in ArcticVariableIndex: - result &= &" {idx} = {state.registers[idx]}\n" - - result &= "Stack (upside-down):\n" - - for item in state.stack: - result &= &" {item}\n" - - result &= "Code:\n" - - for section in state.code.sections: - result &= "\n section " - result &= &"«{section}»" - result &= ":\n" - for (i, m) in state.code.data(section).pairs: - for (label, location) in state.symbols.pairs: - if location == state.code.address(section, i): - result &= &"«:{label}@{location:016x}» " - if state.pc == state.code.address(section, i): - result &= "⋄" - if m.code != ' ': - result &= &"{m} " - - result &= "\nData:\n" - - for section in state.memory.sections: - result &= "\n section " - result &= &"«{section}»" - result &= ":\n" - for (i, m) in state.memory.data(section).pairs: - for (label, location) in state.symbols.pairs: - if location == state.memory.address(section, i): - result &= &"«:{label}@{location:016x}» " - result &= &"{m:02x}" -