diff options
| author | Irene Knapp <ireneista@irenes.space> | 2026-05-11 18:03:11 -0700 |
|---|---|---|
| committer | Irene Knapp <ireneista@irenes.space> | 2026-05-11 18:03:45 -0700 |
| commit | a2268b0dee73f5407315f6c7c3d5ca3f718db40c (patch) | |
| tree | c2a0b53f7c03387bd3fa1428c725e2c1d0499dae /execution.e | |
| parent | 86606391c738c5b9022f3bf3c1fe52f2fb27f292 (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.e | 81 |
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 + ; + |