Removed Nim stuff
This commit is contained in:
parent
c1e7ecec44
commit
222cf580e0
22
Makefile
Normal file
22
Makefile
Normal file
|
@ -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 '$*=$($*)'
|
|
@ -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"
|
122
src/arctic.c
122
src/arctic.c
|
@ -1,122 +0,0 @@
|
|||
#include "arctic.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
59
src/arctic.h
59
src/arctic.h
|
@ -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 */
|
|
@ -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
|
|
@ -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', '_', '.', '+', '-', '*', '/', '%', '\\', '|', '&', '^', '!', '?', '(', ')' }
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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}"
|
||||
|
Loading…
Reference in a new issue