summary refs log tree commit diff
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2025-10-20 01:04:34 -0700
committerIrene Knapp <ireneista@irenes.space>2025-10-20 01:04:34 -0700
commit102ea8415a0170ef6bbde4363cda115afa602c23 (patch)
treece53369554ecf8bacecc25ef75dcd17ce7303e56
parent66cdcc19b820a871c5eca435bbabf958a09014a9 (diff)
implement Forth EXIT HEAD main
this is the final word called by interpreted words, to return

Force-Push: yes
Change-Id: I8301fa31009915e4beb069664c9bd16cdf33d879
-rw-r--r--quine.asm41
1 files changed, 36 insertions, 5 deletions
diff --git a/quine.asm b/quine.asm
index ed0be32..e1f91c6 100644
--- a/quine.asm
+++ b/quine.asm
@@ -236,7 +236,7 @@ macro mov.qreg.indirect.qreg target, source
     qwordreg sreg, source
     qwordreg treg, target
     rex.w
-    rb 0x8B
+    db 0x8B
     modrm 1, treg, sreg
     db 0
   end match
@@ -295,7 +295,7 @@ macro mov.oreg.qreg target, source
   owordreg treg, target
   qwordreg sreg, source
   rex.wr
-  rb 0x8B
+  db 0x8B
   modrm 3, treg, sreg
 end macro
 
@@ -319,7 +319,7 @@ macro mov.qreg.oreg target, source
   qwordreg treg, target
   owordreg sreg, source
   rex.wr
-  rb 0x89
+  db 0x89
   modrm 3, sreg, treg
 end macro
 
@@ -632,6 +632,14 @@ macro syscall
 end macro
 
 
+; Halts the CPU. We can't actually run this in userspace, but the kernel will
+; kill our process or the debugger will break, and those are the outcomes we
+; actually want.
+macro hlt
+  db 0xf4
+end macro
+
+
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Executable file format ;;;
@@ -1129,6 +1137,16 @@ cold_start:
   dq QUIT
 
 ;;;
+;;;   This is the mechanism to "return" from a word interpreted by DOCOL.
+;;; We pop the control stack, and then, since this is threaded execution, we
+;;; do the next thing the caller wants to do, by inlining NEXT.
+;;;
+EXIT:
+  dq $ + 0x8                     ; codeword
+  POPCONTROL rsi
+  NEXT
+
+;;;
 ;;;   One of the most charming naming traditions in Forth is that the
 ;;; top-level word that stays running forever, is called "quit".
 ;;;
@@ -1158,18 +1176,31 @@ QUIT:
   ;;; If the repl ever exits, do it all again.
   ;;;
   ;dq BRANCH, QUIT - $
+  dq SYS_EXIT
 
 
-END_PROCESS:
+;;;
+;;; This does the Linux exit() system call, passing it exit code zero.
+;;;
+SYS_EXIT:
   dq $ + 0x8                     ; codeword
+
   mov.b rax, 60                  ; syscall number
   mov.b rdi, 0                   ; exit code
   syscall
 
+  ; In the event we're still here, let's minmize confusion.
+  hlt
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; (new) Implementation strategy ;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;
 QUINE:
   dq DOCOL                       ; codeword
   dq OLD_CODE
-  dq END_PROCESS
+  dq EXIT
 
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;