From e3299e135f4a137892db12e58bf3a6490871eaf4 Mon Sep 17 00:00:00 2001 From: Irene Knapp Date: Mon, 3 Nov 2025 20:07:47 -0800 Subject: move the output helpers and assembly-in-forth stuff earlier in the file this better reflects the logical dependencies, per the new plan Force-Push: yes Change-Id: I2caa0e6bb1c722a7839f6695c48b05d0b2cfad25 --- quine.asm | 429 ++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 222 insertions(+), 207 deletions(-) diff --git a/quine.asm b/quine.asm index 7568b37..9be965d 100644 --- a/quine.asm +++ b/quine.asm @@ -2555,6 +2555,226 @@ zbranch_after_jmp: next +;;;;;;;;;;;;;;;;;;;;;; +;;; Ouptut helpers ;;; +;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; These routines are for building up data structures in-memory. Sometimes +;;; they're used for structures that are meant to stay in memory; other times +;;; it's a buffer that will become output. +;;; +;;; The general pattern is that each routine takes an output address and +;;; some specific datum, and returns the output address adjusted to point +;;; after the new datum. That makes them easy to chain together. + +; In: base address, value +; Out: new base address +defword pack64, 0 + dq docol + dq swap, dup, unroll3, store, lit, 8, add + dq exit +defword pack32, 0 + dq docol + dq swap, dup, unroll3, store32, lit, 4, add + dq exit +defword pack16, 0 + dq docol + dq swap, dup, unroll3, store16, lit, 2, add + dq exit +defword pack8, 0 + dq docol + dq swap, dup, unroll3, store8, lit, 1, add + dq exit + +; This works on C-style strings, which are characters followed by a null +; terminator. The packed data includes the null terminator. +; +; Stack in: +; base address, string pointer +; Stack out: +; new base address +defword packstring, 0 + dq docol + dq dup, stringlen, dup + ; base/destination, source, length, length + dq lit, 4, roll, dup, lit, 5, unroll + ; destination, source, length, length, base/destination + dq add, lit, 4, unroll + ; new base, destination, source, length + dq ccopy + dq exit + +; Stack in: +; base address +; byte size +; Stack out: +; new base address +defword packalign, 0 + dq docol + dq dup2, divmod, drop, zbranch, 8*8 + dq swap, lit, 0, pack8, swap + dq branch, -11*8 + dq drop, exit + +; In the interests of reducing our executable's size, since a lot of it goes +; to pack* invocations, we define words that combine lit with pack*. This +; shaves roughly 700 bytes as of when it was added. +defword litpack64, 0 + dq $ + 8 + lodsq + push.qreg rax + beforenext pack64 +defword litpack32, 0 + dq $ + 8 + lodsq + push.qreg rax + beforenext pack32 +defword litpack16, 0 + dq $ + 8 + lodsq + push.qreg rax + beforenext pack16 +defword litpack8, 0 + dq $ + 8 + lodsq + push.qreg rax + beforenext pack8 + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Assembly language, but in Forth ;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; +;;; It's all backwards and stuff. +;;; +;;; These routines use the output helpers, defined above. They're called in +;;; the same way: an output address, followed by data items specific to what's +;;; being output. + +; We define a bunch of keywords, which evaluate to their own codeword +; addresses. +defword rax, 0 + dq docol, lit, rax, exit +defword rcx, 0 + dq docol, lit, rcx, exit +defword rdx, 0 + dq docol, lit, rdx, exit +defword rbx, 0 + dq docol, lit, rbx, exit +defword rsp, 0 + dq docol, lit, rsp, exit +defword rbp, 0 + dq docol, lit, rbp, exit +defword rsi, 0 + dq docol, lit, rsi, exit +defword rdi, 0 + dq docol, lit, rdi, exit +defword r8, 0 + dq docol, lit, r8, exit +defword r9, 0 + dq docol, lit, r9, exit +defword r10, 0 + dq docol, lit, r10, exit +defword r11, 0 + dq docol, lit, r11, exit +defword r12, 0 + dq docol, lit, r12, exit +defword r13, 0 + dq docol, lit, r13, exit +defword r14, 0 + dq docol, lit, r14, exit +defword r15, 0 + dq docol, lit, r15, exit + +; Stack in: +; register name +; Stack out: +; 3-bit encoded value for register +defword reg64, 0 + dq docol + dq dup, rax, eq, zbranch, 5*8, drop, lit, 0, exit + dq dup, rcx, eq, zbranch, 5*8, drop, lit, 1, exit + dq dup, rdx, eq, zbranch, 5*8, drop, lit, 2, exit + dq dup, rbx, eq, zbranch, 5*8, drop, lit, 3, exit + dq dup, rsp, eq, zbranch, 5*8, drop, lit, 4, exit + dq dup, rbp, eq, zbranch, 5*8, drop, lit, 5, exit + dq dup, rsi, eq, zbranch, 5*8, drop, lit, 6, exit + dq dup, rdi, eq, zbranch, 5*8, drop, lit, 7, exit + dq sys_exit + +; Stack in: +; register name +; Stack out: +; 3-bit encoded value for register +defword extrareg64, 0 + dq docol + dq dup, r8, eq, zbranch, 5*8, drop, lit, 0, exit + dq dup, r9, eq, zbranch, 5*8, drop, lit, 1, exit + dq dup, r10, eq, zbranch, 5*8, drop, lit, 2, exit + dq dup, r11, eq, zbranch, 5*8, drop, lit, 3, exit + dq dup, r12, eq, zbranch, 5*8, drop, lit, 4, exit + dq dup, r13, eq, zbranch, 5*8, drop, lit, 5, exit + dq dup, r14, eq, zbranch, 5*8, drop, lit, 6, exit + dq dup, r15, eq, zbranch, 5*8, drop, lit, 7, exit + dq sys_exit + +; Stack: +; output point +defword rex_w, 0 + dq docol, lit, 0x48, pack8, exit +defword rex_wb, 0 + dq docol, lit, 0x49, pack8, exit + +; Stack: +; output point +; 3-bit encoded value for register +; opcode byte +defword opcodereg, 0 + dq docol, or, pack8, exit + +; Stack +; output point +; mode ("mod") field +; register/opcode field +; register/memory ("RM") field +defword modrm, 0 + dq docol, swap, lit, 8, mul, or, swap, lit, 64, mul, or, pack8, exit + +; Stack: +; output point +defword cld, 0 + dq docol, lit, 0xFC, pack8, exit + +; Stack: +; output point +; immediate value +; register name +defword mov_reg64_imm64, 0 + dq docol + dq roll3, rex_w, swap, reg64, lit, 0xB8, opcodereg, swap, pack64 + dq exit +defword mov_extrareg64_imm64, 0 + dq docol + dq roll3, rex_wb, swap, extrareg64, lit, 0xB8, opcodereg, swap, pack64 + dq exit + +; Stack: +; output point +; source register name +; target register name +defword mov_reg64_reg64, 0 + dq docol + dq roll3, rex_w, lit, 0x89, pack8, unroll3 + dq reg64, swap, reg64, swap, lit, 3, unroll3, modrm + dq exit + +; Stack: +; output point +defword syscall, 0 + dq docol, lit, 0x0F, pack8, lit, 0x05, pack8, exit + + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Runtime word definition ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -2675,6 +2895,7 @@ defword early_self_codeword, 0 defword early_here_store, 0 dq docol, swap, early_here, swap, unroll3, store, exit + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Now.... what was our original goal, again? ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -2767,83 +2988,6 @@ defword sys_write, 0 next -;;;;;;;;;;;;;;;;;;;;;; -;;; Ouptut helpers ;;; -;;;;;;;;;;;;;;;;;;;;;; - -; In: base address, value -; Out: new base address -defword pack64, 0 - dq docol - dq swap, dup, unroll3, store, lit, 8, add - dq exit -defword pack32, 0 - dq docol - dq swap, dup, unroll3, store32, lit, 4, add - dq exit -defword pack16, 0 - dq docol - dq swap, dup, unroll3, store16, lit, 2, add - dq exit -defword pack8, 0 - dq docol - dq swap, dup, unroll3, store8, lit, 1, add - dq exit - -; Includes the null terminator. -; -; Stack in: -; base address, string pointer -; Stack out: -; new base address -defword packstring, 0 - dq docol - dq dup, stringlen, dup - ; base/destination, source, length, length - dq lit, 4, roll, dup, lit, 5, unroll - ; destination, source, length, length, base/destination - dq add, lit, 4, unroll - ; new base, destination, source, length - dq ccopy - dq exit - -; Stack in: -; base address -; byte size -; Stack out: -; new base address -defword packalign, 0 - dq docol - dq dup2, divmod, drop, zbranch, 8*8 - dq swap, lit, 0, pack8, swap - dq branch, -11*8 - dq drop, exit - -; In the interests of reducing our executable's size, since a lot of it goes -; to PACK* invocations, we define words that combine lit with PACK*. This -; shaves roughly 700 bytes as of when it was added. -defword litpack64, 0 - dq $ + 8 - lodsq - push.qreg rax - beforenext pack64 -defword litpack32, 0 - dq $ + 8 - lodsq - push.qreg rax - beforenext pack32 -defword litpack16, 0 - dq $ + 8 - lodsq - push.qreg rax - beforenext pack16 -defword litpack8, 0 - dq $ + 8 - lodsq - push.qreg rax - beforenext pack8 - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; (new) Implementation strategy ;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -3092,136 +3236,7 @@ defword self_raw, 0 dq exit -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; Assembly language, but in Forth ;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; -;;; It's all backwards and stuff. - -; We define a bunch of keywords, which evaluate to their own codeword -; addresses. -defword rax, 0 - dq docol, lit, rax, exit -defword rcx, 0 - dq docol, lit, rcx, exit -defword rdx, 0 - dq docol, lit, rdx, exit -defword rbx, 0 - dq docol, lit, rbx, exit -defword rsp, 0 - dq docol, lit, rsp, exit -defword rbp, 0 - dq docol, lit, rbp, exit -defword rsi, 0 - dq docol, lit, rsi, exit -defword rdi, 0 - dq docol, lit, rdi, exit -defword r8, 0 - dq docol, lit, r8, exit -defword r9, 0 - dq docol, lit, r9, exit -defword r10, 0 - dq docol, lit, r10, exit -defword r11, 0 - dq docol, lit, r11, exit -defword r12, 0 - dq docol, lit, r12, exit -defword r13, 0 - dq docol, lit, r13, exit -defword r14, 0 - dq docol, lit, r14, exit -defword r15, 0 - dq docol, lit, r15, exit - -; Stack in: -; register name -; Stack out: -; 3-bit encoded value for register -defword reg64, 0 - dq docol - dq dup, rax, eq, zbranch, 5*8, drop, lit, 0, exit - dq dup, rcx, eq, zbranch, 5*8, drop, lit, 1, exit - dq dup, rdx, eq, zbranch, 5*8, drop, lit, 2, exit - dq dup, rbx, eq, zbranch, 5*8, drop, lit, 3, exit - dq dup, rsp, eq, zbranch, 5*8, drop, lit, 4, exit - dq dup, rbp, eq, zbranch, 5*8, drop, lit, 5, exit - dq dup, rsi, eq, zbranch, 5*8, drop, lit, 6, exit - dq dup, rdi, eq, zbranch, 5*8, drop, lit, 7, exit - dq sys_exit - -; Stack in: -; register name -; Stack out: -; 3-bit encoded value for register -defword extrareg64, 0 - dq docol - dq dup, r8, eq, zbranch, 5*8, drop, lit, 0, exit - dq dup, r9, eq, zbranch, 5*8, drop, lit, 1, exit - dq dup, r10, eq, zbranch, 5*8, drop, lit, 2, exit - dq dup, r11, eq, zbranch, 5*8, drop, lit, 3, exit - dq dup, r12, eq, zbranch, 5*8, drop, lit, 4, exit - dq dup, r13, eq, zbranch, 5*8, drop, lit, 5, exit - dq dup, r14, eq, zbranch, 5*8, drop, lit, 6, exit - dq dup, r15, eq, zbranch, 5*8, drop, lit, 7, exit - dq sys_exit - -; Stack: -; output point -defword rex_w, 0 - dq docol, lit, 0x48, pack8, exit -defword rex_wb, 0 - dq docol, lit, 0x49, pack8, exit - -; Stack: -; output point -; 3-bit encoded value for register -; opcode byte -defword opcodereg, 0 - dq docol, or, pack8, exit - -; Stack -; output point -; mode ("mod") field -; register/opcode field -; register/memory ("RM") field -defword modrm, 0 - dq docol, swap, lit, 8, mul, or, swap, lit, 64, mul, or, pack8, exit - -; Stack: -; output point -defword cld, 0 - dq docol, lit, 0xFC, pack8, exit - -; Stack: -; output point -; immediate value -; register name -defword mov_reg64_imm64, 0 - dq docol - dq roll3, rex_w, swap, reg64, lit, 0xB8, opcodereg, swap, pack64 - dq exit -defword mov_extrareg64_imm64, 0 - dq docol - dq roll3, rex_wb, swap, extrareg64, lit, 0xB8, opcodereg, swap, pack64 - dq exit - -; Stack: -; output point -; source register name -; target register name -defword mov_reg64_reg64, 0 - dq docol - dq roll3, rex_w, lit, 0x89, pack8, unroll3 - dq reg64, swap, reg64, swap, lit, 3, unroll3, modrm - dq exit - -; Stack: -; output point -defword syscall, 0 - dq docol, lit, 0x0F, pack8, lit, 0x05, pack8, exit - - -final_word_name = syscall_name +final_word_name = self_raw code_size = $ - code_start file_size = $ - $$ -- cgit 1.4.1