Finished rough draft
This commit is contained in:
parent
e2642ec3ac
commit
c990114723
|
@ -465,7 +465,7 @@ These can be combined to store the entire stack in a new array via: `(w$0 Rt)`
|
|||
{ |BLEZ| … x| ⇒ | … | branch to immediate if x is less than or equal to zero
|
||||
} |BGEZ| … x| ⇒ | … | branch to immediate if x is greater or equal to zero
|
||||
g |FINV| … f| → | f … | invoke f, saving return address on stack
|
||||
@ |CALL| …| → | f … | call immediate name
|
||||
@ |CALL| …| ⇒ | f … | call immediate name
|
||||
, |JUMP| …| ⇒ | … | jump to immediate without pushing return address
|
||||
; |RETN| … f| → | … | return from subroutine (jump but for stack)
|
||||
\:|LABL| … | ↔ | … | label code location
|
||||
|
|
|
@ -2,12 +2,9 @@
|
|||
|
||||
@main
|
||||
|
||||
"with stdio"
|
||||
|
||||
"data"
|
||||
:message 'Hello, World!'
|
||||
:message '"Hello, World!\x00"'
|
||||
|
||||
"code"
|
||||
:main T3 kk # main is called as: &argv[0] argc retaddr
|
||||
$message @putstrln $0;
|
||||
|
||||
$message `putstrln $0 ;
|
||||
|
|
301
src/arctic.nim
301
src/arctic.nim
|
@ -1,4 +1,4 @@
|
|||
import std/[atomics, bitops, critbits, strformat, strutils, strmisc, tables, math, re]
|
||||
import std/[bitops, critbits, macros, strformat, strutils, strmisc, os, tables, math, re] # atomics
|
||||
import bio
|
||||
import itertools
|
||||
|
||||
|
@ -14,9 +14,8 @@ type
|
|||
i: int64
|
||||
u: uint64
|
||||
d: float64
|
||||
p: ArcticPointer # always positive (null is 0)
|
||||
f: ArcticPointer # always negative (null is 0)
|
||||
# TODO: check that appropriate p/f is used (there are a lot of legacy .f's hanging around)
|
||||
p: ArcticPointer
|
||||
f: ArcticPointer
|
||||
|
||||
ArcticVariableIndex = enum
|
||||
VARIABLE_A, VARIABLE_B, VARIABLE_C,
|
||||
|
@ -51,13 +50,13 @@ type
|
|||
dynmem: Table[ArcticPointer, int] # pointer -> length
|
||||
|
||||
ArcticStepResult* = enum
|
||||
CONTINUE, BREAKPOINT, ERROR
|
||||
CONTINUE, BREAKPOINT, EXIT, ERROR
|
||||
|
||||
ArcticBuiltin* = proc (state: var ArcticState): ArcticStepResult
|
||||
ArcticBuiltin* = proc (state: var ArcticState): ArcticStepResult {.nimcall.}
|
||||
|
||||
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', '_', '.', '+', '-', '*', '/', '%', '\\', '|', '&', '^', '!', '?', '(', ')', '`' }
|
||||
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', '_', '.', '+', '-', '*', '/', '%', '\\', '|', '&', '^', '!', '?', '(', ')' }
|
||||
|
||||
proc `$`*(variable: ArcticVariableIndex): string =
|
||||
case variable:
|
||||
|
@ -78,9 +77,7 @@ proc `$`*(op: ArcticOperation): string =
|
|||
of VARIABLE: result &= $op.immediate.v
|
||||
of INTEGER: result &= $op.immediate.i
|
||||
of NUMBER: result &= $op.immediate.n
|
||||
of SYMBOL: result &= "$" & $op.immediate.s
|
||||
|
||||
result &= " "
|
||||
of SYMBOL: result &= $op.immediate.s
|
||||
|
||||
proc `$`*(state: ArcticState): string =
|
||||
result &= "Registers:\n"
|
||||
|
@ -92,27 +89,31 @@ proc `$`*(state: ArcticState): string =
|
|||
for item in state.stack:
|
||||
result &= &" {item}\n"
|
||||
|
||||
result &= "Sections:\n"
|
||||
|
||||
for section in state.code.sections:
|
||||
result &= "\n"
|
||||
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} "
|
||||
if state.pc == state.code.address(section, i):
|
||||
result &= ">"
|
||||
if m.code != ' ':
|
||||
result &= $m
|
||||
|
||||
for section in state.memory.sections:
|
||||
result &= "\n"
|
||||
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} "
|
||||
result &= &"{m} "
|
||||
|
||||
proc op(code: char, immediate: ArcticImmediate = ArcticImmediate(kind: PLAIN)): ArcticOperation =
|
||||
return ArcticOperation(code: code, immediate: immediate)
|
||||
|
||||
proc tovar(code: char): ArcticVariableIndex =
|
||||
case code.toLowerAscii:
|
||||
of 'a': VARIABLE_A
|
||||
|
@ -130,13 +131,13 @@ proc parse_immediate(imm: string, section: string): ArcticImmediate =
|
|||
return ArcticImmediate(kind: INTEGER, i: imm.parseInt)
|
||||
elif imm.match(re"^[AaBbCcIiNnXxYyZz]$"):
|
||||
return ArcticImmediate(kind: VARIABLE, v: imm[0].tovar)
|
||||
elif imm[0] == '$':
|
||||
if imm.len == 1 or imm[1] == '_':
|
||||
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)
|
||||
else:
|
||||
return ArcticImmediate(kind: NUMBER, n: imm.parseFloat)
|
||||
|
||||
func grabnum(data: string): (string, string) =
|
||||
## Returns the numeric literal at the start of data, then the rest of data
|
||||
|
@ -192,7 +193,7 @@ proc parse_data(data: string): seq[uint8] =
|
|||
result.add parse_data(rest)
|
||||
|
||||
of 'x': # hexadecimal byte constant
|
||||
let (hex, x, rest) = data[1..^1].partition("x")
|
||||
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)
|
||||
|
@ -200,7 +201,7 @@ proc parse_data(data: string): seq[uint8] =
|
|||
of '"': # utf-8 string constant with escapes
|
||||
let strlen = data.matchLen(re"^""([^""]|\\"")*""")
|
||||
assert strlen >= 0
|
||||
for c in unescape(data[1..strlen]):
|
||||
for c in unescape(data[1..strlen - 2], prefix="", suffix=""):
|
||||
result.add c.uint8
|
||||
result.add parse_data(data[strlen..^1])
|
||||
|
||||
|
@ -219,7 +220,7 @@ func isbigendian(secname: string): bool =
|
|||
|
||||
func raw_op(code: char): ArcticOperation =
|
||||
result.code = code
|
||||
result.immediate.kind = PLAIN
|
||||
result.immediate = ArcticImmediate(kind: PLAIN)
|
||||
|
||||
func load*(code: string): ArcticState =
|
||||
var
|
||||
|
@ -229,7 +230,6 @@ func load*(code: string): ArcticState =
|
|||
result.pc = 1
|
||||
|
||||
for next in code:
|
||||
debug_echo "token: ", token, ", next: ", next
|
||||
if token.len == 0: # initial state
|
||||
case next:
|
||||
of ImmediateOps, '#', ':', '\"', '\'':
|
||||
|
@ -256,7 +256,7 @@ func load*(code: string): ArcticState =
|
|||
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)
|
||||
result.symbols[idx] = result.code.current(section)
|
||||
else:
|
||||
result.symbols[idx] = result.code.current(section)
|
||||
token = ""
|
||||
|
@ -287,7 +287,7 @@ func load*(code: string): ArcticState =
|
|||
token.add next
|
||||
|
||||
of ImmediateOps:
|
||||
if next == ' ':
|
||||
if next in " \n":
|
||||
result.code.add(section, ArcticOperation(
|
||||
code: token[0],
|
||||
immediate: parse_immediate(token[1..^1], section),
|
||||
|
@ -299,7 +299,40 @@ func load*(code: string): ArcticState =
|
|||
else:
|
||||
discard
|
||||
|
||||
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
|
||||
|
||||
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`
|
||||
|
||||
proc putstrln(state: var ArcticState): ArcticStepResult {.arctic_builtin.} =
|
||||
var p = state.stack.pop.p
|
||||
while state.memory[p] != 0:
|
||||
stdout.write(state.memory[p])
|
||||
stdout.write('\n')
|
||||
return CONTINUE
|
||||
|
||||
proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): ArcticStepResult =
|
||||
if not (state.pc in state.code):
|
||||
return EXIT
|
||||
|
||||
let op = state.code[state.pc]
|
||||
state.pc.inc
|
||||
|
||||
|
@ -311,7 +344,7 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
|
||||
of '2': # LDAS
|
||||
let
|
||||
p = state.stack.pop.f
|
||||
p = state.stack.pop.p
|
||||
a = state.memory[p].int64
|
||||
b = state.memory[p+1].int64
|
||||
if op.bigendian:
|
||||
|
@ -321,7 +354,7 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
|
||||
of '3': # LDAI
|
||||
let
|
||||
p = state.stack.pop.f
|
||||
p = state.stack.pop.p
|
||||
a = state.memory[p].int64
|
||||
b = state.memory[p+1].int64
|
||||
c = state.memory[p+2].int64
|
||||
|
@ -333,7 +366,7 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
|
||||
of '4': # LDAW
|
||||
let
|
||||
p = state.stack.pop.f
|
||||
p = state.stack.pop.p
|
||||
a = state.memory[p].int64
|
||||
b = state.memory[p+1].int64
|
||||
c = state.memory[p+2].int64
|
||||
|
@ -349,13 +382,13 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
|
||||
of 'o': # LDOB
|
||||
assert op.immediate.kind == INTEGER
|
||||
let p = state.stack.pop.f
|
||||
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.f + op.immediate.i
|
||||
p = state.stack.pop.p + op.immediate.i
|
||||
a = state.memory[p].int64
|
||||
b = state.memory[p+1].int64
|
||||
if op.bigendian:
|
||||
|
@ -365,7 +398,7 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
|
||||
of 'G': # LDOI
|
||||
let
|
||||
p = state.stack.pop.f + op.immediate.i
|
||||
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
|
||||
|
@ -377,7 +410,7 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
|
||||
of 'Q': # LDOW
|
||||
let
|
||||
p = state.stack.pop.f
|
||||
p = state.stack.pop.p
|
||||
a = state.memory[p].int64
|
||||
b = state.memory[p+1].int64
|
||||
c = state.memory[p+2].int64
|
||||
|
@ -394,13 +427,13 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
of '5': # STAB
|
||||
let
|
||||
x = cast[uint8](state.stack.pop.b)
|
||||
p = state.stack.pop.f
|
||||
p = state.stack.pop.p
|
||||
state.memory[p] = x
|
||||
|
||||
of '6': # STAS
|
||||
let
|
||||
x = cast[uint16](state.stack.pop.s)
|
||||
p = state.stack.pop.f
|
||||
p = state.stack.pop.p
|
||||
if op.bigendian:
|
||||
state.memory[p] = uint8(x and 0xFF)
|
||||
state.memory[p+1] = uint8(x shr 8)
|
||||
|
@ -411,7 +444,7 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
of '7': # STAI
|
||||
let
|
||||
x = cast[uint32](state.stack.pop.i)
|
||||
p = state.stack.pop.f
|
||||
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)
|
||||
|
@ -426,7 +459,7 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
of '8': # STAW
|
||||
let
|
||||
x = cast[uint64](state.stack.pop.i)
|
||||
p = state.stack.pop.f
|
||||
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)
|
||||
|
@ -449,7 +482,7 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
of 'D': # MCLR
|
||||
let
|
||||
x = state.stack.pop.i
|
||||
p = state.stack.pop.f
|
||||
p = state.stack.pop.p
|
||||
for i in 0 .. x:
|
||||
state.memory[p+i] = 0
|
||||
|
||||
|
@ -457,7 +490,7 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
assert op.immediate.kind == INTEGER
|
||||
let
|
||||
x = state.stack.pop.i
|
||||
p = state.stack.pop.f
|
||||
p = state.stack.pop.p
|
||||
b = op.immediate.i.uint8
|
||||
for i in 0 .. x:
|
||||
state.memory[p+i] = b
|
||||
|
@ -465,8 +498,8 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
of 'K': # MCPY
|
||||
let
|
||||
x = state.stack.pop.i
|
||||
q = state.stack.pop.f
|
||||
p = state.stack.pop.f
|
||||
q = state.stack.pop.p
|
||||
p = state.stack.pop.p
|
||||
for i in 0 .. x:
|
||||
state.memory[q+i] = state.memory[p+i]
|
||||
|
||||
|
@ -518,7 +551,7 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
let
|
||||
y = state.stack.pop.i
|
||||
x = state.stack.pop.i
|
||||
p = state.stack.pop.f
|
||||
p = state.stack.pop.p
|
||||
a = state.memory[p].int64
|
||||
b = state.memory[p+1].int64
|
||||
c = state.memory[p+2].int64
|
||||
|
@ -706,6 +739,7 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
let v = op.immediate.v
|
||||
i = state.registers[v].i
|
||||
else:
|
||||
echo "Unexpected immediate: ", op
|
||||
assert false
|
||||
|
||||
if i > 0:
|
||||
|
@ -859,18 +893,185 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
|||
state.stack.add ArcticType(i: state.stack.len)
|
||||
|
||||
of ')': # PACK
|
||||
let
|
||||
x = state.stack.pop.i
|
||||
p = state.stack.pop.f
|
||||
# TODO: Can't implement this until we have unified addresses
|
||||
# Once we have the addresses, can pack x items of stack at p+...
|
||||
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 ----------------------------------------------------------
|
||||
# TODO
|
||||
of '=': # BEQZ
|
||||
assert op.immediate.kind == INTEGER
|
||||
let cond = state.stack.pop.i
|
||||
|
||||
# TODO
|
||||
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:
|
||||
discard # TODO: integer "syscalls" (probably just syscall(n, ...)
|
||||
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
|
||||
|
||||
when isMainModule:
|
||||
let state = stdin.readAll.load
|
||||
for fname in DefaultBuiltins.keys:
|
||||
echo fname
|
||||
var state = stdin.readAll.load
|
||||
let builtins = DefaultBuiltins
|
||||
|
||||
# TODO: Actually allocate memory and push pointers to cli args
|
||||
state.stack.add ArcticType(i: 0)
|
||||
state.stack.add ArcticType(i: 0)
|
||||
|
||||
echo state
|
||||
|
||||
while true:
|
||||
case state.step(builtins):
|
||||
of CONTINUE:
|
||||
continue
|
||||
of BREAKPOINT:
|
||||
echo state
|
||||
of EXIT:
|
||||
break
|
||||
of ERROR:
|
||||
break
|
||||
|
||||
|
|
303
src/memory.nim
Normal file
303
src/memory.nim
Normal file
|
@ -0,0 +1,303 @@
|
|||
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 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 `[]`*[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 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
|
Loading…
Reference in a new issue