summary refs log tree commit diff
path: root/execution.e
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-05-11 18:03:11 -0700
committerIrene Knapp <ireneista@irenes.space>2026-05-11 18:03:45 -0700
commita2268b0dee73f5407315f6c7c3d5ca3f718db40c (patch)
treec2a0b53f7c03387bd3fa1428c725e2c1d0499dae /execution.e
parent86606391c738c5b9022f3bf3c1fe52f2fb27f292 (diff)
implement all the core Forth stuff in Evocation-assembly
also, add support for ;asm and stuff

Force-Push: yes
Change-Id: I904bc0c31e7e4c8b0abc7790f3af5d20c275f2a5
Diffstat (limited to 'execution.e')
-rw-r--r--execution.e81
1 files changed, 78 insertions, 3 deletions
diff --git a/execution.e b/execution.e
index f6e5978..fb83688 100644
--- a/execution.e
+++ b/execution.e
@@ -174,7 +174,7 @@
 ~ * DF = 0 is required
 ~
 ~ (base address -- new base address)
-: next
+: pack-next
   ~ Copy the next word's address from *rsi into rax. Increment rsi (as per the
   ~ DF flag).
   lods64
@@ -204,7 +204,7 @@
 ~ eventually getting around to inlining "next". Hence the name.
 ~
 ~ (target address, base address -- new base address)
-: beforenext
+: pack-beforenext
   ~ Do a permanent transfer of control by setting rax and invoking the
   ~ codeword. Of course, we could jump to docol ourselves but this will work
   ~ regardless of what the receiving codeword is.
@@ -464,7 +464,7 @@
   ~   We are about to set up rsi, we did rbp already, and rsp came to us
   ~ already set up. That's all that "next" needs, so take it away!
   L@' warm-start :rsi mov-reg64-imm64
-  next ;
+  pack-next ;
 
 ~ Routine warm-start
 ~ ~~~~~~~~~~~~~~~~~~
@@ -537,3 +537,78 @@
   ~ dq early_latest, litstring, "latest", early_variable
   ~ dq early_here, litstring, "here", early_variable
   ;
+
+
+~ (previous entry address, output point, name string pointer
+~  -- new entry address, output point)
+: output-create
+  3roll dup 4 roll swap pack64
+  ~ (string pointer, new entry address, output point)
+  0 pack8
+  0 pack8
+  roll3 packstring
+  ~ (new entry address, output point)
+  8 packalign
+  ;
+
+
+~ Routine docol
+~ ~~~~~~~~~~~~~
+~
+~   Reference this via its label as the codeword of a word to make it an
+~ "interpreted" word. Concretely, it saves rsi (the "instruction pointer")
+~ to the control stack, takes the address of the codeword from rax and
+~ increments it in-place to form the new instruction pointer, and copies
+~ that to rsi.
+~
+~   Having then done this, we're now in the state that normal execution
+~ expects, so docol ends by it using "next" to begin the callee's execution,
+~ kicking off a nested call.
+~
+~   The name is said to be short for "do colon", because Forth high-level
+~ code begins word definitions with a colon.
+~
+~ Registers in:
+~
+~ * rsi is the caller's instruction pointer
+~ * rbp is the control stack pointer
+~ * rax is the address of the callee's codeword
+~
+~ Registers out:
+~
+~ * rsi is the callee's instruction pointer
+~ * rbp is the control stack pointer
+~
+~ (previous entry address, output point)
+: output-docol
+  s" docol" output-create
+
+  ~ Evaluated as a word, docol is a constant which returns a pointer.
+  L@' docol :rax mov-reg64-imm64
+  :rax push-reg64
+  pack-next
+  8 packalign
+
+  ~ Since docol is not a normal word, the label points to the value we care
+  ~ about from the assembly side of things, which is the address we use as the
+  ~ codeword.
+  L!' docol
+  :rsi pack-pushcontrol
+  8 :rax add-reg64-imm8
+  :rax :rsi mov-reg64-reg64
+  pack-next
+  ;
+
+~   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".
+~
+~ (previous entry address, output point
+~  -- new entry address, output point)
+: output-exit
+  s" exit" output-create
+  L!' exit
+  :rsi pack-popcontrol
+  pack-next
+  ;
+