Implemented syscalls
This commit is contained in:
parent
2836e25e65
commit
c1e7ecec44
13
.gitignore
vendored
13
.gitignore
vendored
|
@ -1,3 +1,16 @@
|
||||||
build/
|
build/
|
||||||
/arctic
|
/arctic
|
||||||
htmldocs
|
htmldocs
|
||||||
|
acdump
|
||||||
|
src/arctic/handle_syscalls.nim
|
||||||
|
syscalls.json
|
||||||
|
|
||||||
|
# Documentation artefacts
|
||||||
|
doc/documentation.html
|
||||||
|
doc/documentation.tex
|
||||||
|
doc/documentation.pdf
|
||||||
|
|
||||||
|
# LaTeX garbage
|
||||||
|
*.log
|
||||||
|
*.aux
|
||||||
|
*.out
|
||||||
|
|
|
@ -15,5 +15,12 @@ requires "nim >= 2.0.0"
|
||||||
requires "bio"
|
requires "bio"
|
||||||
requires "itertools"
|
requires "itertools"
|
||||||
|
|
||||||
|
before build:
|
||||||
|
exec "./generate_handle_syscalls.sh"
|
||||||
|
|
||||||
task docs, "docs":
|
task docs, "docs":
|
||||||
exec "nim doc --project --index:on --outdir:src/htmldocs src/arctic.nim"
|
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"
|
||||||
|
|
1
doc/arctic-begin.tex
Normal file
1
doc/arctic-begin.tex
Normal file
|
@ -0,0 +1 @@
|
||||||
|
\begin{document}
|
1
doc/arctic-footer.tex
Normal file
1
doc/arctic-footer.tex
Normal file
|
@ -0,0 +1 @@
|
||||||
|
\end{document}
|
12
doc/arctic-leader.tex
Normal file
12
doc/arctic-leader.tex
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
\documentclass{article}
|
||||||
|
|
||||||
|
\usepackage{hyperref}
|
||||||
|
\usepackage{tabularx}
|
||||||
|
\usepackage{tabulary}
|
||||||
|
\usepackage{booktabs}
|
||||||
|
\usepackage[normalem]{ulem}
|
||||||
|
\usepackage{glossaries}
|
||||||
|
\usepackage{soul}
|
||||||
|
|
||||||
|
\setcounter{secnumdepth}{0}
|
||||||
|
%\renewcommand{\chapternumberline}[1]{}% Gobble chapter numbers in TOC
|
|
@ -1,7 +1,12 @@
|
||||||
---
|
---
|
||||||
Title: ARCTIC Documentation
|
Title: ARCTIC Documentation
|
||||||
Author: Louis A. Burke
|
Author: Louis A. Burke
|
||||||
|
Language: en
|
||||||
CSS: documentation.css
|
CSS: documentation.css
|
||||||
|
LaTeX Leader: arctic-leader.tex
|
||||||
|
LaTeX Begin: arctic-begin.tex
|
||||||
|
LaTeX Footer: arctic-footer.tex
|
||||||
|
LaTeX Header Level: 3
|
||||||
---
|
---
|
||||||
|
|
||||||
# ARCTIC Code
|
# ARCTIC Code
|
||||||
|
@ -343,7 +348,7 @@ instruction, indexed by an immediate integer based on the following table:
|
||||||
|
|
||||||
Immediate | Operation
|
Immediate | Operation
|
||||||
-----------|--------------------------------------------------------------------
|
-----------|--------------------------------------------------------------------
|
||||||
0 | ???
|
0 | ???
|
||||||
|
|
||||||
### Type Conversions
|
### Type Conversions
|
||||||
|
|
||||||
|
@ -569,7 +574,7 @@ $ |VALU| … | ⇒ | … \* | load constant value
|
||||||
|
|
||||||
### Summary
|
### Summary
|
||||||
|
|
||||||
| -0 | -1 | -2 | -3 | -4 | -5 | -6 | -7
|
. | -0 | -1 | -2 | -3 | -4 | -5 | -6 | -7
|
||||||
---:|:------:|:------:|:------:|:------:|:------:|:------:|:------:|:------:
|
---:|:------:|:------:|:------:|:------:|:------:|:------:|:------:|:------:
|
||||||
000-|`0 BNEZ`|`1 LDAB`|`2 LDAS`|`3 LDAI`|`4 LDAW`|`5 STAB`|`6 STAS`|`7 STAI`
|
000-|`0 BNEZ`|`1 LDAB`|`2 LDAS`|`3 LDAI`|`4 LDAW`|`5 STAB`|`6 STAS`|`7 STAI`
|
||||||
001-|`8 STAW`|`9 CASS`|`A PUTA`|`B PUTB`|`C PUTC`|`D MCLR`|`E FTOI`|`F BMIS`
|
001-|`8 STAW`|`9 CASS`|`A PUTA`|`B PUTB`|`C PUTC`|`D MCLR`|`E FTOI`|`F BMIS`
|
||||||
|
@ -579,7 +584,7 @@ $ |VALU| … | ⇒ | … \* | load constant value
|
||||||
101-|`e SROT`|`f FMOD`|`g FINV`|`h OVER`|`i GETI`|`j FNEG`|`k SPOP`|`l BITC`
|
101-|`e SROT`|`f FMOD`|`g FINV`|`h OVER`|`i GETI`|`j FNEG`|`k SPOP`|`l BITC`
|
||||||
110-|`m FSUB`|`n GETN`|`o LDOB`|`p FMUL`|`q FDIV`|`r FREM`|`s FADD`|`t SWAP`
|
110-|`m FSUB`|`n GETN`|`o LDOB`|`p FMUL`|`q FDIV`|`r FREM`|`s FADD`|`t SWAP`
|
||||||
111-|`u USHR`|`v FABS`|`w SDUP`|`x GETX`|`y GETY`|`z GETZ`|`_ INEG`|`. ITOF`
|
111-|`u USHR`|`v FABS`|`w SDUP`|`x GETX`|`y GETY`|`z GETZ`|`_ INEG`|`. ITOF`
|
||||||
200-|`+ IADD`|`- ISUB`|`* IMUL`|`/ IDIV`|`% IMOD`|`\ IREM`|`| IABS`|`$ VALU`
|
200-|`+ IADD`|`- ISUB`|`* IMUL`|`/ IDIV`|`% IMOD`|`\ IREM`|`\| IABS`|`$ VALU`
|
||||||
201-|`@ CALL`|`< BLTZ`|`{ BLEZ`|`= BEQZ`|`} BGEZ`|`> BGTZ`|`, JUMP`|`; RTRN`
|
201-|`@ CALL`|`< BLTZ`|`{ BLEZ`|`= BEQZ`|`} BGEZ`|`> BGTZ`|`, JUMP`|`; RTRN`
|
||||||
210-|`& BAND`|`^ BXOR`|`! BNOT`|`[ ROTR`|`] BSHR`|`? CMPI`|`~ CMPF`|`: LABL`
|
210-|`& BAND`|`^ BXOR`|`! BNOT`|`[ ROTR`|`] BSHR`|`? CMPI`|`~ CMPF`|`: LABL`
|
||||||
211-|`( DPTH`|`) PACK`|`' DATA`|`" SECT`|`\` BIFC`|`␣ NOP`|`# COMM`|`¶ BEAT`
|
211-|`( DPTH`|`) PACK`|`' DATA`|`" SECT`|`\` BIFC`|`␣ NOP`|`# COMM`|`¶ BEAT`
|
||||||
|
|
147
generate_handle_syscalls.jq
Normal file
147
generate_handle_syscalls.jq
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
# run this as: jq -r -f SELF syscalls.json
|
||||||
|
# download syscalls.json from https://syscalls.mebeim.net/db/x86/64/x64/v6.6/table.json
|
||||||
|
|
||||||
|
def asargs: join(", ");
|
||||||
|
def csig: "\(.name)(\(.signature | asargs))";
|
||||||
|
def indent(w): w + (split("\n") | join("\n" + w));
|
||||||
|
def getargs: .signature | map(capture("(?<type>.*[^a-zA-Z_0-9]+)(?<name>[a-zA-Z_0-9]*)"));
|
||||||
|
def strim: sub("^[[:space:]]+"; "") | sub("[[:space:]]+$"; "");
|
||||||
|
def rawtype: gsub("const"; "") | strim;
|
||||||
|
|
||||||
|
# returns false if the given type may contain or be a pointer
|
||||||
|
def isflat: [.] | inside([
|
||||||
|
"char",
|
||||||
|
"unsigned char",
|
||||||
|
"int",
|
||||||
|
"struct cachestat_range",
|
||||||
|
"struct stat",
|
||||||
|
"struct pollfd",
|
||||||
|
"sigset_t",
|
||||||
|
"fd_set",
|
||||||
|
"struct __kernel_old_timeval",
|
||||||
|
"struct __kernel_old_itimerval",
|
||||||
|
"struct __kernel_timespec",
|
||||||
|
"struct sockaddr",
|
||||||
|
"void",
|
||||||
|
"loff_t",
|
||||||
|
"struct rusage",
|
||||||
|
"struct new_utsname",
|
||||||
|
"struct sembuf",
|
||||||
|
"struct msqid_ds", # unused pointers
|
||||||
|
"struct linux_dirent",
|
||||||
|
"struct timezone",
|
||||||
|
"struct rlimit",
|
||||||
|
"struct sysinfo",
|
||||||
|
"struct tms",
|
||||||
|
"gid_t",
|
||||||
|
"uid_t",
|
||||||
|
"siginfo_t",
|
||||||
|
"struct utimbuf",
|
||||||
|
"struct ustat",
|
||||||
|
"struct statfs",
|
||||||
|
"struct sched_param",
|
||||||
|
"struct __kernel_timex",
|
||||||
|
"__kernel_old_time_t",
|
||||||
|
"u32",
|
||||||
|
"unsigned long",
|
||||||
|
"aio_context_t",
|
||||||
|
"struct io_event",
|
||||||
|
"struct iocb",
|
||||||
|
"struct linux_dirent64",
|
||||||
|
"timer_t",
|
||||||
|
"struct __kernel_itimerspec",
|
||||||
|
"struct epoll_event",
|
||||||
|
"struct mq_attr",
|
||||||
|
"unsigned int",
|
||||||
|
"struct siginfo",
|
||||||
|
"size_t",
|
||||||
|
"struct perf_event_attr",
|
||||||
|
"struct rlimit64",
|
||||||
|
"struct file_handle",
|
||||||
|
"struct getcpu_cache",
|
||||||
|
"struct sched_attr",
|
||||||
|
"union bpf_attr",
|
||||||
|
"struct statx",
|
||||||
|
"struct __aio_sigset",
|
||||||
|
"struct rseq",
|
||||||
|
"struct io_uring_params",
|
||||||
|
"struct clone_args",
|
||||||
|
"struct open_how",
|
||||||
|
"struct mount_attr",
|
||||||
|
"struct landlock_ruleset_attr",
|
||||||
|
"struct futex_waitv",
|
||||||
|
""
|
||||||
|
]);
|
||||||
|
|
||||||
|
# returns true if the given type definitely contains a pointer
|
||||||
|
def isntflat: [.] | inside([
|
||||||
|
"struct sigaction",
|
||||||
|
"struct iovec",
|
||||||
|
"struct shmid_ds",
|
||||||
|
"struct user_msghdr",
|
||||||
|
"struct msgbuf",
|
||||||
|
"stack_t",
|
||||||
|
"struct sigevent",
|
||||||
|
"struct kexec_segment",
|
||||||
|
"struct robust_list_head",
|
||||||
|
"struct mmsghdr",
|
||||||
|
""
|
||||||
|
]);
|
||||||
|
|
||||||
|
def nimtype: rawtype |
|
||||||
|
if . == "" then null
|
||||||
|
|
||||||
|
# pointers
|
||||||
|
elif endswith("*") then rtrimstr("*") | strim |
|
||||||
|
if isflat then "pointer"
|
||||||
|
elif isntflat then "pointer #[ TODO \(.) is not a flat type ]#"
|
||||||
|
elif endswith("*") then "pointer #[ TODO \(.) is a nested pointer ]#"
|
||||||
|
else error("\(.) is of dubious flatness!") end
|
||||||
|
|
||||||
|
# scalar types
|
||||||
|
elif startswith("enum") then "cint"
|
||||||
|
elif [.] | inside(["int", "key_t", "pid_t", "clockid_t", "timer_t", "mqd_t", "__s32", "rwf_t"]) then "cint"
|
||||||
|
elif [.] | inside(["size_t"]) then "csize_t"
|
||||||
|
elif [.] | inside(["umode_t"]) then "cushort"
|
||||||
|
elif [.] | inside(["unsigned int", "uid_t", "gid_t", "qid_t", "u32", "__u32"]) then "cuint"
|
||||||
|
elif [.] | inside(["unsigned long", "off_t"]) then "clong"
|
||||||
|
elif [.] | inside(["aio_context_t", "__u64"]) then "culong"
|
||||||
|
elif [.] | inside(["loff_t"]) then "clonglong"
|
||||||
|
elif [.] | inside(["key_serial_t"]) then "int32"
|
||||||
|
elif [.] | inside(["cap_user_header_t", "cap_user_data_t"]) then "pointer"
|
||||||
|
else error("\(.) is unknown as a nimtype") end;
|
||||||
|
|
||||||
|
def nimstack: rawtype |
|
||||||
|
if . == "" then null
|
||||||
|
|
||||||
|
# pointers
|
||||||
|
elif endswith("*") then rtrimstr("*") | strim |
|
||||||
|
if isflat then "state.memory.raw_address(state.stack.pop.p)"
|
||||||
|
elif isntflat then "nil # TODO \(.) is not a flat type"
|
||||||
|
elif endswith("*") then "nil # TODO \(.) is a nested pointer"
|
||||||
|
else error("\(.) is of dubious flatness!") end
|
||||||
|
|
||||||
|
# scalar types
|
||||||
|
elif startswith("enum") then "state.stack.pop.i.cint"
|
||||||
|
elif [.] | inside(["int", "key_t", "pid_t", "clockid_t", "timer_t", "mqd_t", "__s32", "rwf_t"]) then "state.stack.pop.i.cint"
|
||||||
|
elif [.] | inside(["size_t"]) then "state.stack.pop.u.csize_t"
|
||||||
|
elif [.] | inside(["umode_t"]) then "state.stack.pop.i.cushort"
|
||||||
|
elif [.] | inside(["unsigned int", "uid_t", "gid_t", "qid_t", "u32", "__u32"]) then "state.stack.pop.u.cuint"
|
||||||
|
elif [.] | inside(["unsigned long", "off_t"]) then "state.stack.pop.i.clong"
|
||||||
|
elif [.] | inside(["aio_context_t", "__u64"]) then "state.stack.pop.u.culong"
|
||||||
|
elif [.] | inside(["loff_t"]) then "state.stack.pop.i.clonglong"
|
||||||
|
elif [.] | inside(["key_serial_t"]) then "state.stack.pop.i.int32"
|
||||||
|
elif [.] | inside(["cap_user_header_t", "cap_user_data_t"]) then "state.memory.raw_address(state.stack.pop.p)"
|
||||||
|
else error("\(.) is unknown as a nimtype") end;
|
||||||
|
|
||||||
|
|
||||||
|
def letstr: getargs | map("let syscall_\(.name | gsub("_"; "")): \(.type | nimtype) = \(.type | nimstack)") | join("\n");
|
||||||
|
|
||||||
|
def argcomma: if ( getargs | length ) == 0 then "" else ", " end;
|
||||||
|
def argstr: getargs | map("syscall_" + (.name | gsub("_"; ""))) | join(", ");
|
||||||
|
|
||||||
|
.syscalls[] |
|
||||||
|
" of \(.number): # \(csig)\n" +
|
||||||
|
"\(letstr | indent(" "))\n" +
|
||||||
|
" let retval: clong = syscall(\(.number)\(argcomma)\(argstr))\n" +
|
||||||
|
" state.stack.add ArcticType(i: retval.int64)\n"
|
27
generate_handle_syscalls.sh
Executable file
27
generate_handle_syscalls.sh
Executable file
|
@ -0,0 +1,27 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ -e src/arctic/handle_syscalls.nim ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -e syscalls.json ]; then
|
||||||
|
curl 'https://syscalls.mebeim.net/db/x86/64/x64/v6.6/table.json' > syscalls.json
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat <<EOF > src/arctic/handle_syscalls.nim
|
||||||
|
import types
|
||||||
|
import memory
|
||||||
|
|
||||||
|
proc syscall(number: clong): clong {.importcpp: "syscall(@)", header: "<unistd.h>", varargs.}
|
||||||
|
|
||||||
|
template handle_syscall*(state: var ArcticState, number: int64) =
|
||||||
|
case number:
|
||||||
|
EOF
|
||||||
|
|
||||||
|
jq -r -f generate_handle_syscalls.jq < syscalls.json >> src/arctic/handle_syscalls.nim
|
||||||
|
|
||||||
|
cat <<EOF >> src/arctic/handle_syscalls.nim
|
||||||
|
else:
|
||||||
|
# TODO: invalid syscall
|
||||||
|
discard
|
||||||
|
EOF
|
|
@ -3,8 +3,7 @@
|
||||||
@main
|
@main
|
||||||
|
|
||||||
"data"
|
"data"
|
||||||
:message '"Hello, World!\x00"'
|
:message '"Hello, World!\x0A"'
|
||||||
|
|
||||||
"code"
|
"code"
|
||||||
:main T3 kk # main is called as: &argv[0] argc retaddr
|
:main $15 $message $1 `1 $0 ;
|
||||||
$message `putstrln $0 ;
|
|
||||||
|
|
|
@ -14,18 +14,33 @@ macro arctic_builtin(builtin: typed): untyped =
|
||||||
`builtin`
|
`builtin`
|
||||||
DefaultBuiltins[`namestr`] = `nameid`
|
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.} =
|
proc putstrln(state: var ArcticState): ArcticStepResult {.arctic_builtin.} =
|
||||||
var p = state.stack.pop.p
|
var p = state.stack.pop.p
|
||||||
while state.memory[p] != 0:
|
while state.memory[p] != 0:
|
||||||
stdout.write(state.memory[p])
|
stdout.write(state.memory[p].char)
|
||||||
|
inc p
|
||||||
stdout.write('\n')
|
stdout.write('\n')
|
||||||
return CONTINUE
|
return CONTINUE
|
||||||
|
|
||||||
|
proc debugdump(state: var ArcticState): ArcticStepResult {.arctic_builtin_secret.} =
|
||||||
|
echo state
|
||||||
|
return CONTINUE
|
||||||
|
|
||||||
proc parseCmdLine(): (File, seq[string]) =
|
proc parseCmdLine(): (File, seq[string]) =
|
||||||
let argv = commandLineParams()
|
var argv = commandLineParams()
|
||||||
|
|
||||||
if len(argv) > 0:
|
if len(argv) > 0:
|
||||||
return (open(argv[0]), argv[1..^0])
|
let fname = argv[0]
|
||||||
|
argv.delete(0)
|
||||||
|
return (open(fname), argv)
|
||||||
else:
|
else:
|
||||||
return (stdin, @[])
|
return (stdin, @[])
|
||||||
|
|
||||||
|
@ -47,9 +62,9 @@ when isMainModule:
|
||||||
for (i, a) in enumerate(argv):
|
for (i, a) in enumerate(argv):
|
||||||
state.memory.write(x + 8 * i, cast[uint64](a.int64).serialize(littleEndian))
|
state.memory.write(x + 8 * i, cast[uint64](a.int64).serialize(littleEndian))
|
||||||
state.memory.write(x + 8 * args.len, 0.uint64.serialize(littleEndian))
|
state.memory.write(x + 8 * args.len, 0.uint64.serialize(littleEndian))
|
||||||
state.stack.add ArcticType(i: 0) # argv
|
state.stack.add ArcticType(i: x) # argv
|
||||||
state.stack.add ArcticType(i: args.len) # argc
|
state.stack.add ArcticType(i: args.len) # argc
|
||||||
state.stack.add ArcticType(i: 0) # return address: null
|
state.stack.add ArcticType(i: -1) # return address: special "exit"
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
case state.step(builtins):
|
case state.step(builtins):
|
||||||
|
|
|
@ -128,7 +128,8 @@ func load*(code: string): ArcticState =
|
||||||
of ImmediateOps, '#', ':', '\"', '\'':
|
of ImmediateOps, '#', ':', '\"', '\'':
|
||||||
token &= next
|
token &= next
|
||||||
of PlainOps, '\n':
|
of PlainOps, '\n':
|
||||||
result.code.add(section, raw_op(next))
|
if section.iscode:
|
||||||
|
result.code.add(section, raw_op(next))
|
||||||
else:
|
else:
|
||||||
discard
|
discard
|
||||||
else:
|
else:
|
||||||
|
@ -136,7 +137,8 @@ func load*(code: string): ArcticState =
|
||||||
of '#': # comment
|
of '#': # comment
|
||||||
if next == '\n':
|
if next == '\n':
|
||||||
token = ""
|
token = ""
|
||||||
result.code.add(section, raw_op(next))
|
if section.iscode:
|
||||||
|
result.code.add(section, raw_op(next))
|
||||||
|
|
||||||
of '"': # section switch
|
of '"': # section switch
|
||||||
if next == '"' and token[^1] != '\\':
|
if next == '"' and token[^1] != '\\':
|
||||||
|
@ -151,7 +153,8 @@ func load*(code: string): ArcticState =
|
||||||
if section.iscode:
|
if section.iscode:
|
||||||
result.symbols[idx] = result.code.current(section)
|
result.symbols[idx] = result.code.current(section)
|
||||||
else:
|
else:
|
||||||
result.symbols[idx] = result.code.current(section)
|
result.memory.register(section)
|
||||||
|
result.symbols[idx] = result.memory.current(section)
|
||||||
token = ""
|
token = ""
|
||||||
else:
|
else:
|
||||||
token.add next
|
token.add next
|
||||||
|
@ -174,17 +177,19 @@ func load*(code: string): ArcticState =
|
||||||
if quoted or escaped:
|
if quoted or escaped:
|
||||||
token.add next
|
token.add next
|
||||||
else:
|
else:
|
||||||
result.memory.add(section, parse_data(token[1..^1]))
|
if not section.iscode:
|
||||||
|
result.memory.add(section, parse_data(token[1..^1]))
|
||||||
token = ""
|
token = ""
|
||||||
else:
|
else:
|
||||||
token.add next
|
token.add next
|
||||||
|
|
||||||
of ImmediateOps:
|
of ImmediateOps:
|
||||||
if next in " \n":
|
if next in " \n":
|
||||||
result.code.add(section, ArcticOperation(
|
if section.iscode:
|
||||||
code: token[0],
|
result.code.add(section, ArcticOperation(
|
||||||
immediate: parse_immediate(token[1..^1], section),
|
code: token[0],
|
||||||
bigendian: isbigendian(section)))
|
immediate: parse_immediate(token[1..^1], section),
|
||||||
|
bigendian: isbigendian(section)))
|
||||||
token = ""
|
token = ""
|
||||||
else:
|
else:
|
||||||
token.add next
|
token.add next
|
||||||
|
|
|
@ -49,6 +49,13 @@ proc van_der_corput(n: int): int =
|
||||||
|
|
||||||
return q
|
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) =
|
proc add*[T](memory: var Memory[T], section: string, value: T) =
|
||||||
## Adds value to the end of memory in section.
|
## Adds value to the end of memory in section.
|
||||||
if not (section in memory.sects):
|
if not (section in memory.sects):
|
||||||
|
@ -106,6 +113,24 @@ proc contains*[T](memory: Memory[T], address: int): bool =
|
||||||
let (blkid, offset) = divmod(address - HUG_BLOCK_START, HUG_BLOCK_SIZE)
|
let (blkid, offset) = divmod(address - HUG_BLOCK_START, HUG_BLOCK_SIZE)
|
||||||
return memory.hugmem[blkid].len >= offset
|
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 =
|
proc `[]`*[T](memory: Memory[T], address: int): T =
|
||||||
## Accesses the underlying memory item for the given address, failing if it
|
## Accesses the underlying memory item for the given address, failing if it
|
||||||
## does not exist
|
## does not exist
|
||||||
|
|
|
@ -2,6 +2,7 @@ import std/[bitops, critbits, math]
|
||||||
|
|
||||||
import memory
|
import memory
|
||||||
import types
|
import types
|
||||||
|
import handle_syscalls
|
||||||
|
|
||||||
proc branch(state: var ArcticState, count: int) =
|
proc branch(state: var ArcticState, count: int) =
|
||||||
var n = 0
|
var n = 0
|
||||||
|
@ -16,10 +17,13 @@ proc branch(state: var ArcticState, count: int) =
|
||||||
if state.code[state.pc].code == '\n':
|
if state.code[state.pc].code == '\n':
|
||||||
n.dec
|
n.dec
|
||||||
|
|
||||||
|
|
||||||
proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): ArcticStepResult =
|
proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): ArcticStepResult =
|
||||||
if not (state.pc in state.code):
|
if not (state.pc in state.code):
|
||||||
return EXIT
|
return EXIT
|
||||||
|
|
||||||
|
if state.pc == 0:
|
||||||
|
return EXIT
|
||||||
let op = state.code[state.pc]
|
let op = state.code[state.pc]
|
||||||
state.pc.inc
|
state.pc.inc
|
||||||
|
|
||||||
|
@ -723,7 +727,7 @@ proc step*(state: var ArcticState, builtins: CritBitTree[ArcticBuiltin]): Arctic
|
||||||
of VARIABLE:
|
of VARIABLE:
|
||||||
discard
|
discard
|
||||||
of INTEGER:
|
of INTEGER:
|
||||||
discard # TODO: integer "syscalls" (probably just syscall(n, ...)
|
state.handle_syscall(op.immediate.i)
|
||||||
of NUMBER:
|
of NUMBER:
|
||||||
discard
|
discard
|
||||||
of SYMBOL:
|
of SYMBOL:
|
||||||
|
|
|
@ -52,6 +52,10 @@ type
|
||||||
|
|
||||||
ArcticBuiltin* = proc (state: var ArcticState): ArcticStepResult {.nimcall.}
|
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 =
|
proc `$`*(variable: ArcticVariableIndex): string =
|
||||||
case variable:
|
case variable:
|
||||||
of VARIABLE_A: return "A"
|
of VARIABLE_A: return "A"
|
||||||
|
@ -78,33 +82,35 @@ proc `$`*(state: ArcticState): string =
|
||||||
for idx in ArcticVariableIndex:
|
for idx in ArcticVariableIndex:
|
||||||
result &= &" {idx} = {state.registers[idx]}\n"
|
result &= &" {idx} = {state.registers[idx]}\n"
|
||||||
|
|
||||||
result &= "Stack:\n"
|
result &= "Stack (upside-down):\n"
|
||||||
|
|
||||||
for item in state.stack:
|
for item in state.stack:
|
||||||
result &= &" {item}\n"
|
result &= &" {item}\n"
|
||||||
|
|
||||||
result &= "Sections:\n"
|
result &= "Code:\n"
|
||||||
|
|
||||||
for section in state.code.sections:
|
for section in state.code.sections:
|
||||||
result &= "\n section "
|
result &= "\n section "
|
||||||
result &= section
|
result &= &"«{section}»"
|
||||||
result &= ":\n"
|
result &= ":\n"
|
||||||
for (i, m) in state.code.data(section).pairs:
|
for (i, m) in state.code.data(section).pairs:
|
||||||
for (label, location) in state.symbols.pairs:
|
for (label, location) in state.symbols.pairs:
|
||||||
if -location == state.code.address(section, i):
|
if location == state.code.address(section, i):
|
||||||
result &= &":{label} "
|
result &= &"«:{label}@{location:016x}» "
|
||||||
if state.pc == state.code.address(section, i):
|
if state.pc == state.code.address(section, i):
|
||||||
result &= ">"
|
result &= "⋄"
|
||||||
if m.code != ' ':
|
if m.code != ' ':
|
||||||
result &= $m
|
result &= &"{m} "
|
||||||
|
|
||||||
|
result &= "\nData:\n"
|
||||||
|
|
||||||
for section in state.memory.sections:
|
for section in state.memory.sections:
|
||||||
result &= "\n section "
|
result &= "\n section "
|
||||||
result &= section
|
result &= &"«{section}»"
|
||||||
result &= ":\n"
|
result &= ":\n"
|
||||||
for (i, m) in state.memory.data(section).pairs:
|
for (i, m) in state.memory.data(section).pairs:
|
||||||
for (label, location) in state.symbols.pairs:
|
for (label, location) in state.symbols.pairs:
|
||||||
if location == state.memory.address(section, i):
|
if location == state.memory.address(section, i):
|
||||||
result &= &":{label} "
|
result &= &"«:{label}@{location:016x}» "
|
||||||
result &= &"{m} "
|
result &= &"{m:02x}"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue