diff --git a/quine.asm b/quine.asm
index 3663dde..d588b1c 100644
--- a/quine.asm
+++ b/quine.asm
@@ -2000,10 +2000,288 @@ cold_start:
; store, but the only thing early_variable is doing is returning an
; address.)
+ ; Now we define a bunch of ordinary Forth words. Since we'll only ever be
+ ; calling these copies from within Forth, we're no longer limited by
+ ; flatassembler's syntax, so a lot of them have slightly different names
+ ; than they've had up to now. This will be noted below.
+
dq litstring, "exit", early_create, early_self_codeword, early_here, fetch
dq rsi, pack_popcontrol, pack_next
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "swap", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "drop", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "drop2".
+ dq litstring, "2drop", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "roll", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; Jonesforth calls this "-roll" and we could do that, but honestly the name
+ ; unroll sounds nicer and it's only a single character longer. You might say
+ ; it rolls off the tongue better.
+ dq litstring, "unroll", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "roll3".
+ dq litstring, "3roll", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "unroll3".
+ dq litstring, "3unroll", early_create, early_self_codeword, early_here
+ dq fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "dup", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "dup2".
+ dq litstring, "2dup", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "add".
+ dq litstring, "+", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "sub".
+ dq litstring, "-", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "mul".
+ dq litstring, "*", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "divmod". Jonesforth calls it "/mod" but % is widely recognized
+ ; and has no special Forth significance.
+ dq litstring, "/%", early_create, early_self_codeword, early_here, fetch
+ ; TODO
dq lit, 8, packalign, early_here_store
+ ; This was "eq". Jonesforth calls it "="; most languages would call it "==".
+ dq litstring, "=", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "ne". Jonesforth calls it "<>", but even most modern SQL dialects
+ ; recognize C's legacy and allow "!=" these days. As someone who learned C
+ ; in childhood, this is not actually a hard call for us.
+ dq litstring, "!=", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "gt".
+ dq litstring, ">", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "lt".
+ dq litstring, "<", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "ge".
+ dq litstring, ">=", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "le".
+ dq litstring, "<=", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "and", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "or", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "xor", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "invert", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "lit", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "litstring", early_create, early_self_codeword, early_here
+ dq fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This is "store", but since we're finally in Forth we're no longer limited
+ ; by flatassembler's syntax, so we call it by its usual Forth name.
+ dq litstring, "!", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This is "fetch".
+ dq litstring, "@", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This is "addstore".
+ dq litstring, "+!", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This is "substore".
+ dq litstring, "-!", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "store8". Jonesforth calls it "c!" but we categorically reject
+ ; the use of letters that are meant to indicate byte sizes. It's unfriendly
+ ; to newcomers. There's some risk that this name will be confused for
+ ; meaning "store a value of 8", but that would not be a useful task, so
+ ; hopefully it'll be okay.
+ dq litstring, "8!", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "fetch8".
+ dq litstring, "8@", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "store16".
+ dq litstring, "16!", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "fetch16".
+ dq litstring, "16@", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "store32".
+ dq litstring, "32!", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "fetch32".
+ dq litstring, "32@", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "memcopy", early_create, early_self_codeword, early_here
+ dq fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; TODO why does this crash?
+ ;dq litstring, "stringlen", early_create, early_self_codeword, early_here
+ ;dq fetch
+ ; TODO
+ ;dq lit, 8, packalign, early_here_store
+
+ dq litstring, "branch", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; This was "zbranch".
+ dq litstring, "0branch", early_create, early_self_codeword, early_here
+ dq fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; TODO why does this crash?
+ ;dq litstring, "sys_exit", early_create, early_self_codeword, early_here
+ ;dq fetch
+ ; TODO
+ ;dq lit, 8, packalign, early_here_store
+
+ dq litstring, "sys_write", early_create, early_self_codeword, early_here
+ dq fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "emitstring", early_create, early_self_codeword, early_here
+ ; TODO this is actually in Forth
+ dq fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "crash", early_create, early_self_codeword, early_here, fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; We could in theory call this 64pack, by analogy to 32! and so on, but it's
+ ; kept like this to be more similar to reg64, imm64 etc.
+ ;
+ ; Also, unlike with ! we specify the size even for the 64-bit version,
+ ; because the user of pack64 and its variants is always doing something
+ ; where exact byte sizes are crucial.
+ dq litstring, "pack64", early_create, early_self_codeword, early_here, fetch
+ ; TODO this is actually in Forth
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "pack32", early_create, early_self_codeword, early_here, fetch
+ ; TODO this is actually in Forth
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "pack16", early_create, early_self_codeword, early_here, fetch
+ ; TODO this is actually in Forth
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "pack8", early_create, early_self_codeword, early_here, fetch
+ ; TODO this is actually in Forth
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "packstring", early_create, early_self_codeword, early_here
+ dq fetch
+ ; TODO this is actually in Forth
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "packalign", early_create, early_self_codeword, early_here
+ dq fetch
+ ; TODO this is actually in Forth
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "litpack64", early_create, early_self_codeword, early_here
+ dq fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "litpack32", early_create, early_self_codeword, early_here
+ dq fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ dq litstring, "litpack16", early_create, early_self_codeword, early_here
+ dq fetch
+ ; TODO
+ dq lit, 8, packalign, early_here_store
+
+ ; TODO why does this crash?
+ ;dq litstring, "litpack8", early_create, early_self_codeword, early_here
+ ;dq fetch
+ ; TODO
+ ;dq lit, 8, packalign, early_here_store
+
;;; For triage's sake, here's an inventory of everything else in the file.
;;;
;;; Macros:
@@ -2020,7 +2298,7 @@ cold_start:
;;; lit, litstring
;;; store, fetch
;;; addstore, substore, store8, fetch8, store16, fetch16, store32, fetch32
- ;;; ccopy, stringlen
+ ;;; memcopy, stringlen
;;; no dependencies except next for any of these
;;; branch, zbranch
;;; sorta needs a label but might be avoidable
@@ -2688,17 +2966,25 @@ defword fetch32, 0
; logic, see roll and unroll. This always copies at byte granularity, for ease
; of implementation.
;
-; Jonesforth calls this CMOVE and has a ccopy which is a single byte. POSIX,
+; Jonesforth calls this CMOVE and has a CCOPY which is a single byte. POSIX,
; however, has memcpy() for non-overlapping blocks and memmove() for
; overlapping blocks. We follow the latter convention, because it feels like
; the more important distinction.
;
+; Also, the "c" was meant to indicate that it works at one-byte granularity,
+; but that isn't, uh... actually an important property here, and as a blanket
+; call we're not using letters to denote data sizes. So we call it "memcopy".
+; Apologies to C programmers but vowels are good, actually.
+;
+; Jonesforth also offers C@C! as another name for its CCOPY, but neither
+; "@!" nor "mem@mem!" seems particulaly nice.
+;
; Stack in:
; destination
; source
; length
; (top)
-defword ccopy, 0
+defword memcopy, 0
dq $ + 8
; We need to save and restore rsi; the other registers we can trample.
mov.qreg.qreg rdx, rsi
@@ -2877,7 +3163,7 @@ defword packstring, 0
; destination, source, length, length, base/destination
dq add, lit, 4, unroll
; new base, destination, source, length
- dq ccopy
+ dq memcopy
dq exit
; Stack in:
@@ -4334,7 +4620,7 @@ defword self_raw, 0
; destination destination source length
dq dup, lit, 4, roll, add, lit, 4, unroll
; result destination source length
- dq ccopy
+ dq memcopy
dq exit
|