; vi: ft=fasm
use64
format ELF64
public start as '_start'
; RSP = data stack
; RSI = virtual instruction stream
;; system calls
SYS_WRITE = 1
SYS_EXIT = 60
;; standard file handles
STDIN = 0
STDOUT = 1
;;
ADDR_SIZE = 8
macro defcode name {
align ADDR_SIZE
name:
}
;; push/pop data stack
macro pushd r {
lea rsp, [rsp + ADDR_SIZE]
mov [rsp], r
}
macro popd r {
mov r, [rsp]
lea rsp, [rsp - ADDR_SIZE]
}
;; interpret next instruction pointed to by RSI
macro next {
mov rax, qword [rsi]
lea rsi, [rsi + ADDR_SIZE]
jmp qword rax
}
IMMEDIATE = 0
COMPILE = 1
var_STATE: db IMMEDIATE
section '.text' ; readable executable
defcode drop
popd rax
next
defcode swap
popd rax
popd rbx
pushd rbx
pushd rax
next
defcode sdup
popd rax
pushd rax
pushd rax
next
defcode lit
mov rax, [rsi]
pushd rax
lea rsi, [rsi + ADDR_SIZE]
next
defcode lbrac
mov [var_STATE], byte IMMEDIATE
next
defcode rbrac
mov [var_STATE], byte COMPILE
next
defcode emit
mov r8, rsi ; backup rsi since we'll clobber it
mov rax, SYS_WRITE
mov rdi, STDOUT
lea rsi, [rsp]
mov rdx, 1
syscall
popd rax
mov rsi, r8 ; restore rsi
next
defcode mstore
popd rbx ; addr to store at
popd rax ; value to store at addr
mov [rbx], rax
next
defcode mfetch
popd rbx
mov rax, [rbx]
pushd rax
next
defcode mstoreb
popd rbx
popd rax
mov [ebx], byte al
next
defcode mfetchb
popd rbx
xor rax, rax
mov al, byte [ebx]
pushd rax
next
defcode exit
mov rax, SYS_EXIT
mov rdi, 0
syscall
defcode branch
add esi, [esi]
next
start:
cld
mov rsi, instrs
next
instrs:
dq lit, '*'
dq emit
dq branch, -32
dq exit