From a2268b0dee73f5407315f6c7c3d5ca3f718db40c Mon Sep 17 00:00:00 2001 From: Irene Knapp Date: Mon, 11 May 2026 18:03:11 -0700 Subject: implement all the core Forth stuff in Evocation-assembly also, add support for ;asm and stuff Force-Push: yes Change-Id: I904bc0c31e7e4c8b0abc7790f3af5d20c275f2a5 --- execution.e | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 3 deletions(-) (limited to 'execution.e') 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 + ; + -- cgit 1.4.1