Finished rough draft

This commit is contained in:
Louis Burke 2023-12-21 20:12:37 -05:00
parent e2642ec3ac
commit c990114723
4 changed files with 557 additions and 56 deletions

View file

@ -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

View file

@ -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 ;

View file

@ -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
View 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