Terminate program correctly
[rrq/jonasforth.git] / main.asm
index 537796de252a2c12db2f3597825afb3a1614f4ea..c6ada7329cbd4b320947c8b925203ad448ac162d 100644 (file)
--- a/main.asm
+++ b/main.asm
@@ -12,9 +12,97 @@ macro next {
     jmp qword [rax]         ; Jump to the codeword of the current word
 }
 
+;; pushr and popr work on the return stack, whose location is stored in the
+;; register RBP.
+macro pushr x {
+    sub rbp, 8
+    mov qword [rbp], x
+}
+macro popr x {
+    mov x, [rbp]
+    add rbp, 8
+}
+
 segment readable executable
 
-start:
-    jmp $
+main:
+    cld                        ; Clear direction flag so LODSQ does the right thing.
+    mov rbp, return_stack_top  ; Initialize return stack
+
+    mov rsi, program
+    next
+
+program: dq MAIN
+
+;; The codeword is the code that will be executed at the beginning of a forth
+;; word. It needs to save the old RSI and update it to point to the next word to
+;; execute.
+docol:
+    pushr rsi            ; Save old value of RSI on return stack; we will continue execution there after we are done executing this word
+    lea rsi, [rax + 8]   ; RAX currently points to the address of the codeword, so we want to continue at RAX+8
+    next                 ; Execute word pointed to by RSI
+
+;; This word is called at the end of a Forth definition. It just needs to
+;; restore the old value of RSI (saved by 'docol') and resume execution.
+EXIT:
+    dq .start
+.start:
+    popr rsi
+    next
+
+EMIT:
+    dq .start
+.start:
+    pushr rsi
+    pushr rax
+    mov rax, 1
+    mov rdi, 1
+    lea rsi, [rsp]
+    mov rdx, 1
+    syscall
+    add rsp, 8
+    popr rax
+    popr rsi
+    next
+
+PUSH_HELLO_CHARS:
+    dq .start
+.start:
+    push $A
+    push 'o'
+    push 'l'
+    push 'l'
+    push 'e'
+    push 'H'
+    next
+
+HELLO:
+    dq docol
+    dq PUSH_HELLO_CHARS
+    dq EMIT
+    dq EMIT
+    dq EMIT
+    dq EMIT
+    dq EMIT
+    dq EMIT
+    dq EXIT
+
+TERMINATE:
+    dq .start
+.start:
+    mov rax, $3C
+    mov rdi, 0
+    syscall
+
+MAIN:
+    dq docol
+    dq HELLO
+    dq HELLO
+    dq HELLO
+    dq TERMINATE
+
+segment readable writable
 
-segment readable
+;; Return stack
+rq $2000
+return_stack_top: