this is the first-ever release! wow :33333 have fun y'all!!!! Force-Push: yes Change-Id: Ifc95e4e63e4ee477b4c23d83a82f7a1e050f7925
12390 lines
517 KiB
NASM
12390 lines
517 KiB
NASM
;;; QUINE
|
|
;;;
|
|
;;; This file is formatted to be read at 80-columns or wider.
|
|
;;;
|
|
;;; There's some tabular information, but diagrams have been avoided, in an
|
|
;;; attempt to make this manageable in screen readers. Feedback welcome.
|
|
;;;
|
|
;;; First the hex
|
|
;;; Second the spark
|
|
;;; Third the words
|
|
;;; Then tie the knot
|
|
;;; [draft]
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;
|
|
;;; What is this? ;;;
|
|
;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; This file was the original version of Evocation, used before the
|
|
;;; self-hosting version existed. It's unlikely to ever be needed again, but
|
|
;;; Irenes are proud of it and have kept it here for historical, sentimental
|
|
;;; reasons.
|
|
;;;
|
|
;;; Those reasons are also why it's called "quine". It is not a Quine, in
|
|
;;; the sense that it is not a program that outputs its own source. Since it
|
|
;;; is of purely historical interest, this misnomer does not matter.
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;
|
|
;;; Workflow tips ;;;
|
|
;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; This is not fully self-hosting; it is based on flatassembler[1]. A minimal
|
|
;;; command to build and run it is:
|
|
;;;
|
|
;;; $ fasmg quine.asm quine && chmod 755 quine && ./quine; echo $?
|
|
;;;
|
|
;;; A workflow you may wish to use for debugging is:
|
|
;;;
|
|
;;; $ rm quine2; fasmg quine.asm quine && chmod 755 quine && ./quine > quine2; echo "exit code:" $?; echo; hexdump -C quine; echo; hexdump -C quine2; echo; cmp -l quine quine2 ; echo cmp: $?
|
|
;;;
|
|
;;; The reason this removes the old one first is that otherwise, there's a
|
|
;;; risk the error message will be scrolled off the top of the screen and
|
|
;;; you'll see stale output and not realize.
|
|
;;;
|
|
;;; You may also wish to do:
|
|
;;;
|
|
;;; $ objdump --disassemble quine
|
|
;;; $ ZydisDisasm -64 quine
|
|
;;;
|
|
;;; This relies on GNU binutils, and on zydis, respectively.
|
|
;;;
|
|
;;; [1] https://flatassembler.net/
|
|
;;;
|
|
;;;
|
|
;;; gdb
|
|
;;; ---
|
|
;;;
|
|
;;; You can run gdb on it if you want; there's no symbols, but if you are
|
|
;;; familiar with the hex it should be readable. Keep a hexdump of the program
|
|
;;; handy to look up what addresses are.
|
|
;;;
|
|
;;; If you want to see a routine implemented in assembly, look at the hexdump
|
|
;;; of the overall file, find it by looking at the ASCII names, skip past the
|
|
;;; codeword, and do ie
|
|
;;;
|
|
;;; (gdb) disassemble/r 0x80007c0,+32
|
|
;;;
|
|
;;; If you want to see the value stack, you can do
|
|
;;;
|
|
;;; (gdb) x/16xg $rsp
|
|
;;;
|
|
;;; The same will work with $rbp for the control stack, and don't forget that
|
|
;;; the "instruction pointer" is rsi. To see all the registers, do
|
|
;;;
|
|
;;; (gdb) info registers
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;; Assembly language ;;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; Before doing any actual code, we define macros for writing x86-64
|
|
;;; assembly language. This is built from scratch, relying only on
|
|
;;; flatassembler's built-in semantics. No include files of any kind are used
|
|
;;; for it.
|
|
|
|
macro pad: bytes
|
|
if bytes > 0
|
|
db 0x00
|
|
pad (bytes - 1)
|
|
end if
|
|
end macro
|
|
|
|
macro align: bytes
|
|
if bytes > 0
|
|
if $ mod bytes <> 0
|
|
db 0x00
|
|
align bytes
|
|
end if
|
|
end if
|
|
end macro
|
|
|
|
; The way these are all spelled out like this is slightly ridiculous, there
|
|
; must be a better way.
|
|
macro rex.0
|
|
db 0x40
|
|
end macro
|
|
macro rex.w
|
|
db 0x48
|
|
end macro
|
|
macro rex.r
|
|
db 0x44
|
|
end macro
|
|
macro rex.x
|
|
db 0x42
|
|
end macro
|
|
macro rex.b
|
|
db 0x41
|
|
end macro
|
|
macro rex.wr
|
|
db 0x4C
|
|
end macro
|
|
macro rex.wx
|
|
db 0x4A
|
|
end macro
|
|
macro rex.wb
|
|
db 0x49
|
|
end macro
|
|
macro rex.rx
|
|
db 0x46
|
|
end macro
|
|
macro rex.rb
|
|
db 0x45
|
|
end macro
|
|
macro rex.xb
|
|
db 0x43
|
|
end macro
|
|
macro rex.wrx
|
|
db 0x4E
|
|
end macro
|
|
macro rex.wrb
|
|
db 0x4D
|
|
end macro
|
|
macro rex.wxb
|
|
db 0x4B
|
|
end macro
|
|
macro rex.rxb
|
|
db 0x47
|
|
end macro
|
|
macro rex.wrxb
|
|
db 0x4F
|
|
end macro
|
|
|
|
macro modrm mod, reg, rm
|
|
assert mod >= 0 & mod < 4
|
|
assert reg >= 0 & reg < 8
|
|
assert rm >= 0 & rm < 8
|
|
db (mod shl 6) OR (reg shl 3) OR rm
|
|
end macro
|
|
|
|
macro sib scale, index, base
|
|
assert scale >= 0 & scale < 4
|
|
assert index >= 0 & index < 8
|
|
assert base >= 0 & index < 8
|
|
db (scale shl 6) OR (index shl 3) OR base
|
|
end macro
|
|
|
|
macro opcodereg opcode, reg
|
|
assert opcode >= 0 & opcode < 256 & opcode AND 7 = 0
|
|
assert reg >= 0 & reg < 8
|
|
db opcode OR reg
|
|
end macro
|
|
|
|
macro opcodecc opcode, cc
|
|
assert opcode >= 0 & opcode < 256 & opcode AND 15 = 0
|
|
assert cc >= 0 & cc < 16
|
|
db opcode OR cc
|
|
end macro
|
|
|
|
macro scalefield sfield, scale
|
|
if 1 = scale
|
|
sfield = 0
|
|
else if 2 = scale
|
|
sfield = 1
|
|
else if 4 = scale
|
|
sfield = 2
|
|
else if 8 = scale
|
|
sfield = 3
|
|
else
|
|
assert 0
|
|
end if
|
|
end macro
|
|
|
|
; Yep, there sure is a lot of duplication in these. This is based on Intel's
|
|
; documented mnemonics...
|
|
;
|
|
; "Above" and "below" are for unsigned comparisons. "Greater" and "less" are
|
|
; for signed comparisons.
|
|
;
|
|
; This is documented on the individual opcode pages, and also in B.1.4.7.
|
|
macro conditioncode cc, condition
|
|
match =above, condition
|
|
cc = 0x07
|
|
else match =above_equal, condition
|
|
cc = 0x03
|
|
else match =below, condition
|
|
cc = 0x02
|
|
else match =below_equal, condition
|
|
cc = 0x06
|
|
else match =carry, condition
|
|
cc = 0x02
|
|
else match =equal, condition
|
|
cc = 0x04
|
|
else match =greater, condition
|
|
cc = 0x0F
|
|
else match =greater_equal, condition
|
|
cc = 0x0D
|
|
else match =less, condition
|
|
cc = 0x0C
|
|
else match =less_equal, condition
|
|
cc = 0x0E
|
|
else match =not_above, condition
|
|
cc = 0x06
|
|
else match =not_above_equal, condition
|
|
cc = 0x02
|
|
else match =not_below, condition
|
|
cc = 0x03
|
|
else match =not_below_equal, condition
|
|
cc = 0x07
|
|
else match =not_carry, condition
|
|
cc = 0x03
|
|
else match =not_equal, condition
|
|
cc = 0x05
|
|
else match =not_greater, condition
|
|
cc = 0x0E
|
|
else match =not_greater_equal, condition
|
|
cc = 0x0C
|
|
else match =not_less, condition
|
|
cc = 0x0D
|
|
else match =not_less_equal, condition
|
|
cc = 0x0F
|
|
else match =not_overflow, condition
|
|
cc = 0x01
|
|
else match =not_parity, condition
|
|
cc = 0x0B
|
|
else match =not_sign, condition
|
|
cc = 0x09
|
|
else match =not_zero, condition
|
|
cc = 0x05
|
|
else match =overflow, condition
|
|
cc = 0x00
|
|
else match =parity, condition
|
|
cc = 0x0A
|
|
else match =parity_even, condition
|
|
cc = 0x0A
|
|
else match =parity_odd, condition
|
|
cc = 0x0B
|
|
else match =sign, condition
|
|
cc = 0x08
|
|
else match =zero, condition
|
|
cc = 0x04
|
|
else
|
|
assert 0
|
|
end match
|
|
end macro
|
|
|
|
|
|
;;; On registers
|
|
;;; ------------
|
|
;;;
|
|
;;; The x86 architecture has been around a while, it has been through
|
|
;;; several transitions from smaller word sizes to larger ones. Therefore it
|
|
;;; has different names for the "same" registers, depending on how much of
|
|
;;; them you're using.
|
|
;;;
|
|
;;; TODO there's more to write here
|
|
|
|
macro bytereg result, register
|
|
match =al?, register
|
|
result = 0
|
|
else match =cl?, register
|
|
result = 1
|
|
else match =dl?, register
|
|
result = 2
|
|
else match =bl?, register
|
|
result = 3
|
|
else match =ah?, register
|
|
result = 4
|
|
else match =ch?, register
|
|
result = 5
|
|
else match =dh?, register
|
|
result = 6
|
|
else match =bh?, register
|
|
result = 7
|
|
else
|
|
assert 0
|
|
end match
|
|
end macro
|
|
|
|
macro wordreg result, register
|
|
match =ax?, register
|
|
result = 0
|
|
else match =cx?, register
|
|
result = 1
|
|
else match =dx?, register
|
|
result = 2
|
|
else match =bx?, register
|
|
result = 3
|
|
else match =sp?, register
|
|
result = 4
|
|
else match =bp?, register
|
|
result = 5
|
|
else match =si?, register
|
|
result = 6
|
|
else match =di?, register
|
|
result = 7
|
|
else
|
|
assert 0
|
|
end match
|
|
end macro
|
|
|
|
macro dwordreg result, register
|
|
match =eax?, register
|
|
result = 0
|
|
else match =ecx?, register
|
|
result = 1
|
|
else match =edx?, register
|
|
result = 2
|
|
else match =ebx?, register
|
|
result = 3
|
|
else match =esp?, register
|
|
result = 4
|
|
else match =ebp?, register
|
|
result = 5
|
|
else match =esi?, register
|
|
result = 6
|
|
else match =edi?, register
|
|
result = 7
|
|
else
|
|
assert 0
|
|
end match
|
|
end macro
|
|
|
|
macro qwordreg result, register
|
|
match =rax?, register
|
|
result = 0
|
|
else match =rcx?, register
|
|
result = 1
|
|
else match =rdx?, register
|
|
result = 2
|
|
else match =rbx?, register
|
|
result = 3
|
|
else match =rsp?, register
|
|
result = 4
|
|
else match =rbp?, register
|
|
result = 5
|
|
else match =rsi?, register
|
|
result = 6
|
|
else match =rdi?, register
|
|
result = 7
|
|
else
|
|
assert 0
|
|
end match
|
|
end macro
|
|
|
|
macro owordreg result, register
|
|
match =r8?, register
|
|
result = 0
|
|
else match =r9?, register
|
|
result = 1
|
|
else match =r10?, register
|
|
result = 2
|
|
else match =r11?, register
|
|
result = 3
|
|
else match =r12?, register
|
|
result = 4
|
|
else match =r13?, register
|
|
result = 5
|
|
else match =r14?, register
|
|
result = 6
|
|
else match =r15?, register
|
|
result = 7
|
|
else
|
|
assert 0
|
|
end match
|
|
end macro
|
|
|
|
|
|
;;; Instructions
|
|
;;; ------------
|
|
|
|
|
|
macro mov.dreg.dimm target, source
|
|
dwordreg treg, target
|
|
opcodereg 0xB8, treg
|
|
dd source
|
|
end macro
|
|
|
|
|
|
macro mov.qreg.dimm target, source
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0xC7
|
|
modrm 3, 0, treg
|
|
dd source
|
|
end macro
|
|
|
|
|
|
macro mov.qreg.qimm target, source
|
|
qwordreg treg, target
|
|
rex.w
|
|
opcodereg 0xB8, treg
|
|
dq source
|
|
end macro
|
|
|
|
|
|
; Notice the use of REX.B here; this instruction puts the register number in
|
|
; the opcode field, so it uses Table 3-1.
|
|
macro mov.oreg.qimm target, source
|
|
owordreg treg, target
|
|
rex.wb
|
|
opcodereg 0xB8, treg
|
|
dq source
|
|
end macro
|
|
|
|
|
|
macro mov.qreg.qreg target, source
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
rex.w
|
|
db 0x89
|
|
modrm 3, sreg, treg
|
|
end macro
|
|
|
|
|
|
; Take a 64-bit source register, treat it as an address and look up the 64-bit
|
|
; value it points to, store that into a 64-bit target register.
|
|
;
|
|
; For a source of rbp, the only modes available also have displacement; we
|
|
; disallow that. Use mov.qreg.disp8.qreg for that case, and set a displacement
|
|
; of 0.
|
|
;
|
|
; In understanding this, pay close attention to the Op/En column in the opcode
|
|
; table. The "RM" variant means the ModRM byte's R/M field (the third one)
|
|
; is the source, while its reg field (the middle one) is the target. This is
|
|
; what we want, because the R/M field is the one that gets indirection applied
|
|
; to it. Opcode 0x8B with an REX.W prefix is the all-64-bit RM variant.
|
|
; [Intel] volume 2B, chapter 4, section 4-3, "MOV".
|
|
;
|
|
; For the indirection modes, don't be confused by the many similar tables.
|
|
; 64-bit mode is encoded the same as 32-bit mode except for adding a REX.W
|
|
; prefix, as per 2.2.1.1, so you want table 2-2 to understand the ModRM byte.
|
|
; The presence or absence of an SIB byte is determined by where in that table
|
|
; we fall, and we aren't using a mode that has one. [Intel] volume 2A,
|
|
; chapter 2, section 2-1.5, table 2-2.
|
|
;
|
|
; We disallow rsp as a source because that's the mode that would want an SIB.
|
|
macro mov.qreg.indirect.qreg target, source
|
|
match =rbp, source
|
|
assert 0
|
|
end match
|
|
qwordreg sreg, source
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0x8B
|
|
modrm 0, treg, sreg
|
|
match =rsp, source
|
|
; R/M = rsp is the SIB case
|
|
sib 0, 4, sreg
|
|
; no scaling, no indexing, source as base
|
|
end match
|
|
end macro
|
|
|
|
|
|
macro mov.qreg.disp8.qreg target, offset, source
|
|
qwordreg sreg, source
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0x8B
|
|
modrm 1, treg, sreg
|
|
match =rsp, source
|
|
; R/M = rsp is the SIB case
|
|
sib 0, 4, sreg
|
|
; no scaling, no indexing, source as base
|
|
end match
|
|
db offset
|
|
end macro
|
|
|
|
|
|
; Take a 64-bit source register, store its value into the address pointed to
|
|
; by a 64-bit target register.
|
|
;
|
|
; For a target of rbp, the only modes available also have displacement; we
|
|
; disallow that. Use mov.disp8.qreg.qreg for that case, and set a displacement
|
|
; of 0.
|
|
;
|
|
; In understanding this, pay close attention to the Op/En column in the opcode
|
|
; table. The "MR" variant means the ModRM byte's reg field (the middle one)
|
|
; is the source, while its R/M field (the third one) is the target. This is
|
|
; what we want, because the R/M field is the one that gets indirection applied
|
|
; to it. Opcode 0x89 with an REX.W prefix is the all-64-bit MR variant.
|
|
; [Intel] volume 2B, chapter 4, section 4-3, "MOV".
|
|
;
|
|
; For the indirection modes, don't be confused by the many similar tables.
|
|
; 64-bit mode is encoded the same as 32-bit mode except for adding a REX.W
|
|
; prefix, as per 2.2.1.1, so you want table 2-2 to understand the ModRM byte.
|
|
; The presence or absence of an SIB byte is determined by where in that table
|
|
; we fall, and we aren't using a mode that has one. [Intel] volume 2A,
|
|
; chapter 2, section 2-1.5, table 2-2.
|
|
;
|
|
; We disallow rsp as a target because that's the mode that would want an SIB.
|
|
; When you look at other addressing modes, be aware that the special treatment
|
|
; is for whichever register is specified in the R/M field. Sometimes that's
|
|
; the source, and sometimes it's the target, depending on the opcode.
|
|
macro mov.indirect.qreg.qreg target, source
|
|
match =rbp, target
|
|
assert 0
|
|
end match
|
|
qwordreg sreg, source
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0x89
|
|
modrm 0, sreg, treg
|
|
match =rsp, target
|
|
; R/M = rsp is the SIB case
|
|
sib 0, 4, treg
|
|
; no scaling, no indexing, target as base
|
|
end match
|
|
end macro
|
|
|
|
|
|
; 8-bit source register
|
|
macro mov.indirect.qreg.breg target, source
|
|
match =rsp, target
|
|
assert 0
|
|
; The SIB case.
|
|
else match =rbp, target
|
|
assert 0
|
|
; An unrelated addressing mode.
|
|
else
|
|
bytereg sreg, source
|
|
qwordreg treg, target
|
|
db 0x88
|
|
modrm 0, sreg, treg
|
|
end match
|
|
end macro
|
|
|
|
macro mov.breg.indirect.qreg target, source
|
|
match =rsp, source
|
|
assert 0
|
|
; The SIB case.
|
|
else match =rbp, source
|
|
assert 0
|
|
; An unrelated addressing mode.
|
|
else
|
|
qwordreg sreg, source
|
|
bytereg treg, target
|
|
db 0x8A
|
|
modrm 0, treg, sreg
|
|
end match
|
|
end macro
|
|
|
|
; We use the operand-size prefix to specify 16-bit. No REX.W. Table 3-4.
|
|
macro mov.indirect.qreg.wreg target, source
|
|
match =rsp, target
|
|
assert 0
|
|
; The SIB case.
|
|
else match =rbp, target
|
|
assert 0
|
|
; An unrelated addressing mode.
|
|
else
|
|
wordreg sreg, source
|
|
qwordreg treg, target
|
|
db 0x66
|
|
db 0x89
|
|
modrm 0, sreg, treg
|
|
end match
|
|
end macro
|
|
|
|
; We use the operand-size prefix to specify 16-bit. No REX.W. Table 3-4.
|
|
macro mov.wreg.indirect.qreg target, source
|
|
match =rsp, source
|
|
assert 0
|
|
; The SIB case.
|
|
else match =rbp, source
|
|
assert 0
|
|
; An unrelated addressing mode.
|
|
else
|
|
qwordreg sreg, source
|
|
wordreg treg, target
|
|
db 0x66
|
|
db 0x8B
|
|
modrm 0, treg, sreg
|
|
end match
|
|
end macro
|
|
|
|
; It defaults to 32-bit, no prefix needed, also no REX.W. Table 3-4.
|
|
macro mov.indirect.qreg.dreg target, source
|
|
match =rsp, target
|
|
assert 0
|
|
; The SIB case.
|
|
else match =rbp, target
|
|
assert 0
|
|
; An unrelated addressing mode.
|
|
else
|
|
dwordreg sreg, source
|
|
qwordreg treg, target
|
|
db 0x89
|
|
modrm 0, sreg, treg
|
|
end match
|
|
end macro
|
|
|
|
; It defaults to 32-bit, no prefix needed, also no REX.W. Table 3-4.
|
|
macro mov.dreg.indirect.qreg target, source
|
|
match =rsp, source
|
|
assert 0
|
|
; The SIB case.
|
|
else match =rbp, source
|
|
assert 0
|
|
; An unrelated addressing mode.
|
|
else
|
|
qwordreg sreg, source
|
|
dwordreg treg, target
|
|
db 0x8B
|
|
modrm 0, treg, sreg
|
|
end match
|
|
end macro
|
|
|
|
|
|
macro mov.qreg.indexed.qreg target, source, index, scale
|
|
match =rbp, source
|
|
assert 0
|
|
; This is divided into some subcases we don't wish to deal with yet.
|
|
else match =rsp, index
|
|
assert 0
|
|
; This is the case where it's not actually indexed after all.
|
|
else
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
qwordreg ireg, index
|
|
scalefield sfield, scale
|
|
rex.w
|
|
db 0x8B
|
|
modrm 0, treg, 4
|
|
sib sfield, ireg, sreg
|
|
end match
|
|
end macro
|
|
|
|
|
|
macro mov.indexed.qreg.qreg target, index, scale, source
|
|
match =rbp, source
|
|
assert 0
|
|
; This is divided into some subcases we don't wish to deal with yet.
|
|
else match =rsp, index
|
|
assert 0
|
|
; This is the case where it's not actually indexed after all.
|
|
else
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
qwordreg ireg, index
|
|
scalefield sfield, scale
|
|
rex.w
|
|
db 0x89
|
|
modrm 0, sreg, 4
|
|
sib sfield, ireg, treg
|
|
end match
|
|
end macro
|
|
|
|
|
|
; Take a 64-bit source register, store its value into a high 64-bit target
|
|
; register (r8-r15).
|
|
;
|
|
; Notice that there are two ways to add another bit to the register encoding.
|
|
; Table 3-1 is about REX.B, but does not apply here, it's for instructions
|
|
; that use opcode bits to specify a register, and none of the
|
|
; register-to-register MOV variants do that (it's for immediate mode).
|
|
;
|
|
; Instead, we want the mechanism that uses REX.R as the extra bit, and it
|
|
; combines with the reg field of ModRM, as per 2.2.1.2.
|
|
;
|
|
; Therefore, we want the variant of MOV which puts the target in the reg
|
|
; field. That's Op/En "RM", opcode 0x8B with REX.WR.
|
|
;
|
|
; Mode 3 is direct addressing.
|
|
macro mov.oreg.qreg target, source
|
|
owordreg treg, target
|
|
qwordreg sreg, source
|
|
rex.wr
|
|
db 0x8B
|
|
modrm 3, treg, sreg
|
|
end macro
|
|
|
|
|
|
; Take a high 64-bit source register (r8-r15), store its value into a 64-bit
|
|
; target register.
|
|
;
|
|
; Notice that there are two ways to add another bit to the register encoding.
|
|
; Table 3-1 is about REX.B, but does not apply here, it's for instructions
|
|
; that use opcode bits to specify a register, and none of the
|
|
; register-to-register MOV variants do that (it's for immediate mode).
|
|
;
|
|
; Instead, we want the mechanism that uses REX.R as the extra bit, and it
|
|
; combines with the reg field of ModRM, as per 2.2.1.2.
|
|
;
|
|
; Therefore, we want the variant of MOV which puts the source in the reg
|
|
; field. That's Op/En "MR", opcode 0x89 with REX.WR.
|
|
;
|
|
; Mode 3 is direct addressing.
|
|
macro mov.qreg.oreg target, source
|
|
qwordreg treg, target
|
|
owordreg sreg, source
|
|
rex.wr
|
|
db 0x89
|
|
modrm 3, sreg, treg
|
|
end macro
|
|
|
|
|
|
; This increments a 64-bit register by 1, in place;
|
|
macro inc.qreg target
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0xFF
|
|
modrm 3, 0, treg
|
|
; The 0 is part of the opcode.
|
|
end macro
|
|
|
|
; This decrements a 64-bit register by 1, in place;
|
|
macro dec.qreg target
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0xFF
|
|
modrm 3, 1, treg
|
|
; The 1 is part of the opcode.
|
|
end macro
|
|
|
|
; This adds a 64-bit register to another 64-bit register, in place.
|
|
macro add.qreg.qreg target, source
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
rex.w
|
|
db 0x01
|
|
modrm 3, sreg, treg
|
|
end macro
|
|
|
|
|
|
macro add.indirect.qreg.qreg target, source
|
|
match =rsp, target
|
|
assert 0
|
|
; The SIB case.
|
|
else match =rbp, target
|
|
assert 0
|
|
; An unrelated addressing mode.
|
|
else
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
rex.w
|
|
db 0x01
|
|
modrm 0, sreg, treg
|
|
end match
|
|
end macro
|
|
|
|
|
|
macro add.qreg.indirect.qreg target, source
|
|
match =rsp, source
|
|
assert 0
|
|
; The SIB case.
|
|
else match =rbp, source
|
|
assert 0
|
|
; An unrelated addressing mode
|
|
else
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
rex.w
|
|
db 0x03
|
|
modrm 0, treg, sreg
|
|
end match
|
|
end macro
|
|
|
|
|
|
; This adds a signed 8-bit immediate value to a 64-bit register, in place.
|
|
;
|
|
; Notice the use of 3 as the addressing mode. This says to use the register
|
|
; itself. The 0 in the reg field is part of the opcode.
|
|
macro add.qreg.bimm target, source
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0x83
|
|
modrm 3, 0, treg
|
|
db source
|
|
end macro
|
|
|
|
|
|
; This adds a signed 32-bit immediate value to a 64-bit register, in place.
|
|
;
|
|
; Notice the use of 3 as the addressing mode. This says to use the register
|
|
; itself. The 0 in the reg field is part of the opcode.
|
|
macro add.qreg.dimm target, source
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0x81
|
|
modrm 3, 0, treg
|
|
dd source
|
|
end macro
|
|
|
|
; This subtracts a 64-bit register from another 64-bit register, in place.
|
|
macro sub.qreg.qreg target, source
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
rex.w
|
|
db 0x2B
|
|
modrm 3, treg, sreg
|
|
end macro
|
|
|
|
|
|
macro sub.indirect.qreg.qreg target, source
|
|
match =rsp, target
|
|
; The SIB case.
|
|
assert 0
|
|
else
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
rex.w
|
|
db 0x2B
|
|
modrm 0, sreg, treg
|
|
end match
|
|
end macro
|
|
|
|
|
|
; This subtracts a signed 8-bit immediate value from a 64-bit register, in
|
|
; place.
|
|
;
|
|
; Notice the use of 3 as the addressing mode. This says to use the register
|
|
; itself. The 5 in the reg field is part of the opcode.
|
|
macro sub.qreg.bimm target, source
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0x83
|
|
modrm 3, 5, treg
|
|
db source
|
|
end macro
|
|
|
|
; This subtracts a signed 32-bit immediate value from a 64-bit register, in
|
|
; place.
|
|
;
|
|
; Notice the use of 3 as the addressing mode. This says to use the register
|
|
; itself. The 5 in the reg field is part of the opcode.
|
|
macro sub.qreg.dimm target, source
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0x81
|
|
modrm 3, 5, treg
|
|
dd source
|
|
end macro
|
|
|
|
; Add with carry.
|
|
macro adc.qreg.bimm target, source
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0x83
|
|
modrm 3, 2, treg
|
|
db source
|
|
end macro
|
|
|
|
; Subtract with borrow.
|
|
macro sbb.qreg.bimm target, source
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0x83
|
|
modrm 3, 3, treg
|
|
db source
|
|
end macro
|
|
|
|
; This multiplies rax, as 64-bits, with another 64-bit register, in place.
|
|
;
|
|
; The 4 in the reg field is part of the opcode.
|
|
macro mul.rax.qreg source
|
|
qwordreg sreg, source
|
|
rex.w
|
|
db 0xF7
|
|
modrm 3, 4, sreg
|
|
end macro
|
|
|
|
; The official mnemonic for this is "div", but it's divmod: It takes a 128-bit
|
|
; dividend formed from concatenating rdx as the high half with rax as the low
|
|
; half, and divides it by a 64-bit divisor from a specified register. It
|
|
; stores the quotient, truncated towards zero, in rax, and it stores the
|
|
; remainder in rdx. This entire process is unsigned.
|
|
;
|
|
; The 6 in the reg field is part of the opcode.
|
|
macro div.rdxrax.qreg source
|
|
qwordreg sreg, source
|
|
rex.w
|
|
db 0xF7
|
|
modrm 3, 6, sreg
|
|
end macro
|
|
|
|
; Same as div, but signed.
|
|
;
|
|
; The 7 in the reg field is part of the opcode.
|
|
macro idiv.rdxrax.qreg source
|
|
qwordreg sreg, source
|
|
rex.w
|
|
db 0xF7
|
|
modrm 3, 7, sreg
|
|
end macro
|
|
|
|
|
|
macro and.qreg.qreg target, source
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
rex.w
|
|
db 0x23
|
|
modrm 3, treg, sreg
|
|
end macro
|
|
|
|
macro and.qreg.bimm target, source
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0x83
|
|
modrm 3, 4, treg
|
|
; The 4 is part of the opcode.
|
|
db source
|
|
end macro
|
|
|
|
macro or.qreg.qreg target, source
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
rex.w
|
|
db 0x0B
|
|
modrm 3, treg, sreg
|
|
end macro
|
|
|
|
macro or.qreg.bimm target, source
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0x83
|
|
modrm 3, 1, treg
|
|
; The 4 is part of the opcode.
|
|
db source
|
|
end macro
|
|
|
|
macro xor.qreg.qreg target, source
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
rex.w
|
|
db 0x33
|
|
modrm 3, treg, sreg
|
|
end macro
|
|
|
|
macro not.qreg target
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0xF7
|
|
modrm 3, 2, treg
|
|
; The 2 is part of the opcode.
|
|
end macro
|
|
|
|
|
|
; This sets the flags to the same things they'd be set to if subtracting
|
|
; right from left.
|
|
macro cmp.qreg.qreg left, right
|
|
qwordreg lreg, left
|
|
qwordreg rreg, right
|
|
rex.w
|
|
db 0x3B
|
|
modrm 3, lreg, rreg
|
|
end macro
|
|
|
|
; This sets the flags to the same things they'd be set to if and'ing right
|
|
; with left.
|
|
macro test.qreg.qreg left, right
|
|
qwordreg lreg, left
|
|
qwordreg rreg, right
|
|
rex.w
|
|
db 0x85
|
|
modrm 3, rreg, lreg
|
|
end macro
|
|
|
|
macro set.breg.cc target, condition
|
|
bytereg treg, target
|
|
conditioncode cc, condition
|
|
db 0x0F
|
|
opcodecc 0x90, cc
|
|
modrm 3, 0, treg
|
|
end macro
|
|
|
|
|
|
; Move from an 8-bit immediate value, to a location relative to a 64-bit
|
|
; register, with an 8-bit displacement and no indexing.
|
|
;
|
|
; This uses opcode 0xC6, which has w = 0. Since we run in 64-bit mode, that
|
|
; makes the operand size 8 bits, regardless of the current operand-size
|
|
; attribute. [Intel] volume 2D, appendix B, section B-1.4.3, table B-6.
|
|
macro mov.qreg.disp8.bimm target, offset, source
|
|
qwordreg treg, target
|
|
db 0xC6
|
|
modrm 1, 0, treg
|
|
; the 0 is part of the opcode
|
|
; 4 is rsp, but it's a special case
|
|
match =rsp, target
|
|
; R/M = rsp is the SIB case
|
|
sib 0, 4, treg
|
|
; no scaling, no indexing, target as base
|
|
end match
|
|
db offset
|
|
db source
|
|
end macro
|
|
|
|
; Move from a 16-bit immediate value, to a location relative to a 64-bit
|
|
; register, with an 8-bit displacement and no indexing.
|
|
;
|
|
; This uses opcode 0xC7, which has w = 1. We run in 64-bit mode, so that gives
|
|
; us an operand size of 32 bits by default. [Intel] volume 1, chapter 3,
|
|
; section 3-6.1, table 3-4. We want a 16-bit operand, so we use the
|
|
; operand-size prefix, 0x66, and we leave REX.W unset.
|
|
;
|
|
; We need to treat rsp specially because it's the SIB case, per table 2-2.
|
|
macro mov.qreg.disp8.wimm target, offset, source
|
|
qwordreg treg, target
|
|
db 0x66
|
|
db 0xC7
|
|
modrm 1, 0, treg
|
|
; the 0 is part of the opcode
|
|
match =rsp, target
|
|
; R/M = rsp is the SIB case
|
|
sib 0, 4, treg
|
|
; no scaling, no indexing, target as base
|
|
end match
|
|
db offset
|
|
dw source
|
|
end macro
|
|
|
|
; Move from a 32-bit immediate value, to a location relative to a 64-bit
|
|
; register, with an 8-bit displacement and no indexing.
|
|
;
|
|
; This uses opcode 0x67, which has w = 1. We run in 64-bit mode, so that gives
|
|
; us an operand size of 32 by default. [Intel] volume 2D, section B.1.43,
|
|
; table B-6. This is what we want, so we leave it.
|
|
macro mov.qreg.disp8.dimm target, offset, source
|
|
qwordreg treg, target
|
|
db 0xC7
|
|
modrm 1, 0, treg
|
|
; the 0 is part of the opcode
|
|
match =rsp, target
|
|
; R/M = rsp is the SIB case
|
|
sib 0, 4, treg
|
|
; no scaling, no indexing, target as base
|
|
end match
|
|
db offset
|
|
dd source
|
|
end macro
|
|
|
|
; Move from a 64-bit register, to a 64-bit location relative to a 64-bit
|
|
; register, with an 8-bit displacement and no indexing.
|
|
;
|
|
; This uses opcode 0x89 with REX.W, so that gives us the reg field as the
|
|
; 64-bit source and the R/M field as the 64-bit destination.
|
|
;
|
|
; We need to treat a target of rsp specially because it's the SIB case per
|
|
; table 2-2.
|
|
macro mov.disp8.qreg.qreg offset, target, source
|
|
qwordreg sreg, source
|
|
qwordreg treg, target
|
|
rex.w
|
|
db 0x89
|
|
modrm 1, sreg, treg
|
|
match =rsp, source
|
|
; R/M = rsp is the SIB case
|
|
sib 0, 4, 4
|
|
; no scaling, no indexing, rsp as base
|
|
end match
|
|
db offset
|
|
end macro
|
|
|
|
; Move from a 64-bit register, to a 64-bit location relative to a 64-bit
|
|
; register, with a 32-bit displacement and no indexing.
|
|
;
|
|
; This uses opcode 0x89 with REX.W, so that gives us the reg field as the
|
|
; 64-bit source and the R/M field as the 64-bit destination.
|
|
;
|
|
; We need to treat a target of rsp specially because it's the SIB case per
|
|
; table 2-2.
|
|
macro mov.qreg.disp32.qreg target, offset, source
|
|
qwordreg sreg, source
|
|
qwordreg treg, target
|
|
match =rsp, target
|
|
rex.w
|
|
db 0x89
|
|
modrm 2, sreg, treg
|
|
; treg is rsp by assumption, and R/M = rsp is the SIB case
|
|
sib 0, 4, 4
|
|
; no scaling, no indexing, rsp as base
|
|
dd offset
|
|
else
|
|
rex.w
|
|
db 0x89
|
|
modrm 2, sreg, treg
|
|
dd offset
|
|
end match
|
|
end macro
|
|
|
|
; Move from a 32-bit immediate value, to a 64-bit location relative to a
|
|
; 64-bit register, with an 8-bit displacement and no indexing.
|
|
;
|
|
; Note that there is no instruction to move a 64-bit immediate to memory.
|
|
;
|
|
; This uses opcode 0xC7, which has w = 1. We run in 64-bit mode, so that
|
|
; gives us an operand size of 32 by default. [Intel] volume 2D,
|
|
; section B.1.43, table B-6. We want a 64-bit operand, so we use the REX.W
|
|
; prefix, 0x48.
|
|
macro mov.qreg.disp8.dimm target, offset, source
|
|
qwordreg treg, target
|
|
match =rsp, target
|
|
rex.w
|
|
db 0xC7
|
|
modrm 1, 0, treg
|
|
; the 0 is part of the opcode
|
|
; 4 is rsp, but it's a special case
|
|
sib 0, 4, treg
|
|
; no scaling, no indexing, rsp as base
|
|
db offset
|
|
dd source
|
|
else
|
|
rex.w
|
|
db 0xC7
|
|
modrm 1, 0, treg
|
|
; the 0 is part of the opcode
|
|
db offset
|
|
dd source
|
|
end match
|
|
end macro
|
|
|
|
; "Load effective address". Compute a 64-bit address as you would for
|
|
; indexed addressing, with an 8-bit displacement and no indexing, but instead
|
|
; of doing anything with the memory, just store the address itself into a
|
|
; register.
|
|
macro lea.qreg.disp8.qreg target, offset, source
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
rex.w
|
|
db 0x8D
|
|
modrm 1, treg, sreg
|
|
match =rsp, source
|
|
; R/M = rsp is the SIB case
|
|
sib 0, 4, sreg
|
|
; no scaling, no indexing, rsp as base
|
|
end match
|
|
db offset
|
|
end macro
|
|
|
|
macro lea.qreg.disp32.qreg target, offset, source
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
rex.w
|
|
db 0x8D
|
|
modrm 2, treg, sreg
|
|
match =rsp, source
|
|
; R/M = rsp is the SIB case
|
|
sib 0, 4, sreg
|
|
; no scaling, no indexing, rsp as base
|
|
end match
|
|
dd offset
|
|
end macro
|
|
|
|
macro lea.qreg.indexed.qreg target, source, index, scale
|
|
match =rbp, source
|
|
assert 0
|
|
; This is divided into some subcases we don't wish to deal with yet.
|
|
else match =rsp, index
|
|
assert 0
|
|
; This is the case where it's not actually indexed after all.
|
|
else
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
qwordreg ireg, index
|
|
scalefield sfield, scale
|
|
rex.w
|
|
db 0x8D
|
|
modrm 0, treg, 4
|
|
sib sfield, ireg, sreg
|
|
end match
|
|
end macro
|
|
|
|
; Wow, we use ALL the instruction suffixes for this, huh. See [Intel] volume
|
|
; 2A, chapter 2, section 2-1, with particular attention to figure 2-1.
|
|
macro lea.qreg.disp8.indexed.qreg target, offset, source, index, scale
|
|
match =rbp, source
|
|
assert 0
|
|
; This is divided into some subcases we don't wish to deal with yet.
|
|
else match =rsp, index
|
|
assert 0
|
|
; This is the case where it's not actually indexed after all.
|
|
else
|
|
qwordreg treg, target
|
|
qwordreg sreg, source
|
|
qwordreg ireg, index
|
|
scalefield sfield, scale
|
|
rex.w
|
|
db 0x8D
|
|
modrm 1, treg, 4
|
|
; 1 in the mode field says we want a disp8.
|
|
; 4 in the R/M field says we want an SIB byte.
|
|
sib sfield, ireg, sreg
|
|
db offset
|
|
end match
|
|
end macro
|
|
|
|
macro mov.breg.breg target, source
|
|
bytereg treg, target
|
|
bytereg sreg, source
|
|
db 0x88
|
|
modrm 3, sreg, treg
|
|
end macro
|
|
|
|
macro mov.breg.bimm target, source
|
|
bytereg treg, target
|
|
db 0xC6
|
|
modrm 3, 0, treg
|
|
; the 0 is part of the opcode
|
|
db source
|
|
end macro
|
|
|
|
; Clear the DF flag. This makes string instructions increment RSI.
|
|
macro cld
|
|
db 0xFC
|
|
end macro
|
|
|
|
; Set the DF flag. This makes string instructions decrement RSI.
|
|
macro std
|
|
db 0xFD
|
|
end macro
|
|
|
|
; Load 64 bits from the address in RSI into RAX. Then, increment or decrement
|
|
; RSI by 8 bytes, depending on the value of the DF flag.
|
|
macro lodsq
|
|
rex.w
|
|
db 0xAD
|
|
end macro
|
|
|
|
macro cmps8
|
|
db 0xA6
|
|
end macro
|
|
|
|
; [Intel] describes two different styles of mnemonic for the repeated string
|
|
; operations. See, their parameters are always rsi and rdi, or the smaller
|
|
; versions of those same specific registers. Intel thinks we might want to
|
|
; write out "rsi" explicitly, even though the only information it conveys is
|
|
; the size. The position we take is that it's better to let that be conveyed
|
|
; by the instruction name; otherwise it'd be a point of confusion for new
|
|
; readers, who might mistakenly think it's possible to pass it different
|
|
; registers.
|
|
;
|
|
; With the string instructions, the reader SHOULD be thinking, "Wait...
|
|
; where does this get its parameters from?" Writing them in a way that makes
|
|
; them appear simpler than they are would be confusing.
|
|
macro rep operation
|
|
match =movsb, operation
|
|
db 0xF3 ; rep prefix
|
|
db 0xA4 ; opcode
|
|
else match =movsw, operation
|
|
db 0xF3 ; rep prefix
|
|
db 0x66 ; operand-size prefix
|
|
db 0xA5 ; opcode
|
|
else match =movsd, operation
|
|
db 0xF3 ; rep prefix
|
|
db 0xA5 ; opcode
|
|
else match =movsq, operation
|
|
; The "rep" instruction can also be thought of as a prefix to other
|
|
; instructions, though only a few specific ones are allowed. Anyway, it
|
|
; comes before the REX byte.
|
|
db 0xF3
|
|
; The rest of this is the same as the encoding of normal, non-repeated
|
|
; movsq.
|
|
rex.w
|
|
db 0xA5
|
|
; There's no explicit parameters. String operations are magic.
|
|
else
|
|
assert 0
|
|
end match
|
|
end macro
|
|
|
|
macro repz operation
|
|
match =scasb, operation
|
|
db 0xF3 ; rep prefix
|
|
db 0xAe ; opcode
|
|
else
|
|
assert 0
|
|
end match
|
|
end macro
|
|
|
|
macro repnz operation
|
|
match =scasb, operation
|
|
db 0xF2 ; rep prefix
|
|
db 0xAE ; opcode
|
|
else
|
|
assert 0
|
|
end match
|
|
end macro
|
|
|
|
; Push a 64-bit value from a register onto the stack (the one pointed to by
|
|
; rsp). Decrement rsp, then write the value at the new location.
|
|
;
|
|
; In the corner case where rsp is also the value being pushed, the old value
|
|
; is the one used.
|
|
;
|
|
; There's an alternate encoding of this that uses a ModRM byte, but doing it
|
|
; without is more compact, so we do without.
|
|
macro push.qreg source
|
|
qwordreg sreg, source
|
|
opcodereg 0x50, sreg
|
|
end macro
|
|
|
|
macro push.bimm source
|
|
db 0x6A
|
|
db source
|
|
end macro
|
|
|
|
; Operand-size prefix makes it 16-bit.
|
|
;
|
|
; If you're trying to fake pushing a larger size by doing several 16-bit
|
|
; pushes, remember to start by pushing the low end and proceed upwards.
|
|
; [Intel] volume 1, chapter 9, section 9-2.4, "Memory Data Formats".
|
|
macro push.wimm source
|
|
db 0x66
|
|
db 0x68
|
|
dw source
|
|
end macro
|
|
|
|
; There is no 64-bit immediate push. So, can we have a push instruction that
|
|
; pushes a 32-bit immediate value? Sort-of, but it's sign-extended to 64 bits,
|
|
; so rsp is decremented by 8, not by 4. This is that instruction.
|
|
;
|
|
; You need to do a really close read of a number of things to understand why.
|
|
; The opcode tables in [Intel] in volume 2D, appendix A, section A-3 give it
|
|
; the d64 annotation, which per table A-1 in section A-2.5 indicates that the
|
|
; operand size is always 64 bits and that there is no corresponding 32-bit
|
|
; version. Yet, the actual immediate value is still only 32 bits! Direct your
|
|
; attention to the instruction's details page, volume 2B, chapter 4, section
|
|
; 4-3, "PUSH". The description section clearly details that the immediate may
|
|
; be less than the operand size, which makes sense once you know it, but it
|
|
; doesn't explictly call out that the operand size is still 64 bits here.
|
|
;
|
|
; In general, the size of an immediate doesn't determine operand size, as you
|
|
; can read about in detail in [Intel] volume 1, chapter 3, section 3-6.1, with
|
|
; particular attention to table 3-4.
|
|
;
|
|
; Why is this surprising, given that it's consistent with the behavior of
|
|
; other instructions? Well, most instructions don't have such obvious
|
|
; side-effects. It's easy to not notice the operand size disagreeing with the
|
|
; immediate size when you'e only writing to a register, but changing the stack
|
|
; in an unexpected way breaks things much more obviously.
|
|
;
|
|
; Anyway, if you really want to decrement the stack pointer by 32 bits after
|
|
; a push, consider pushing a register.
|
|
macro push.dimm source
|
|
db 0x68
|
|
dd source
|
|
end macro
|
|
|
|
; Pop a 64-bit value into a register from the stack (the one pointed to by
|
|
; rsp). Read the value from the old location, then increment rsp.
|
|
;
|
|
; In the corner case where rsp is also the destination being written to, the
|
|
; read happens from the old location, then the write causes the increment to
|
|
; be irrelevant.
|
|
;
|
|
; There's an alternate encoding of this that uses a ModRM byte, but doing it
|
|
; without is more compact, so we do without.
|
|
macro pop.qreg target
|
|
qwordreg treg, target
|
|
opcodereg 0x58, treg
|
|
end macro
|
|
|
|
|
|
; Do an absolute indirect jump with a 64-bit register operand. That is: given
|
|
; a register which holds a pointer, read another address from the pointed-to
|
|
; memory and jump to it.
|
|
;
|
|
; Technically this is a "near" jump in x86 terms, but we just pretend far
|
|
; jumps and segments don't exist. They are still a thing in 64-bit mode, we
|
|
; just don't use them.
|
|
macro jmp.abs.indirect.qreg location
|
|
qwordreg lreg, location
|
|
db 0xFF
|
|
modrm 0, 4, lreg
|
|
end macro
|
|
|
|
; The location is relative to the start of the instruction immediately
|
|
; following the jmp.
|
|
macro jmp.rel.bimm location
|
|
db 0xEB
|
|
db location
|
|
end macro
|
|
|
|
; There in no 64-bit immediate "near" jump, so we use 32-bit. It's relatve,
|
|
; so that's honestly plenty.
|
|
;
|
|
; The location is relative to the start of the instruction immediately
|
|
; following the jmp.
|
|
macro jmp.rel.dimm location
|
|
db 0xE9
|
|
dd location
|
|
end macro
|
|
|
|
; The location is relative to the start of the instruction immediately
|
|
; following the jmp.
|
|
macro jmp.cc.rel.bimm condition, location
|
|
conditioncode cc, condition
|
|
opcodecc 0x70, cc
|
|
db location
|
|
end macro
|
|
|
|
; The location is relative to the start of the instruction immediately
|
|
; following the jmp.
|
|
macro jmp.cc.rel.dimm condition, location
|
|
conditioncode cc, condition
|
|
db 0x0F
|
|
opcodecc 0x70, cc
|
|
dd location
|
|
end macro
|
|
|
|
; Invoke a system call provided by the kernel. On Linux, the System V ABI
|
|
; describes the semantics of such calls (at least, on x86).
|
|
macro syscall
|
|
db 0x0F, 0x05
|
|
end macro
|
|
|
|
|
|
; Halts the CPU. We can't actually run this in userspace, but the kernel will
|
|
; kill our process or the debugger will break, and those are the outcomes we
|
|
; actually want.
|
|
macro hlt
|
|
db 0xf4
|
|
end macro
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;; Executable file format ;;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; Before we get into the body of the program, we do a lot of ELF-specific
|
|
;;; stuff to ensure that our output is in a format Linux knows how to run.
|
|
;;;
|
|
;;; First, we set the origin to load at. This is arbitrary, but it can't be
|
|
;;; zero. We tell flatassembler about it because it's used in label
|
|
;;; calculations; we can reference it as $$ any time we need it in future.
|
|
org 0x08000000
|
|
|
|
;;;
|
|
;;; Second, we output ELF's top-level file header. The only interesting
|
|
;;; thing here is the entry pointer.
|
|
;;;
|
|
elf_header:
|
|
; * denotes mandatory fields according to breadbox
|
|
db 0x7F, "ELF" ; *magic number
|
|
db 2 ; 64-bit
|
|
db 1 ; little-endian
|
|
db 1 ; ELF header format version 1
|
|
db 0 ; System-V ABI
|
|
db 8 DUP 0 ; (padding)
|
|
|
|
dw 2 ; *executable
|
|
dw 0x3E ; *Intel x86-64
|
|
dd 1 ; ELF format version
|
|
|
|
dq _start ; *entry point
|
|
dq program_header - $$ ; *program header offset
|
|
dq 0 ; section header offset
|
|
dd 0 ; processor flags
|
|
dw elf_header_size
|
|
dw program_header_entry_size ; *
|
|
dw 1 ; *number of program header entries
|
|
dw 0 ; section header entry size
|
|
dw 0 ; number of section header entries
|
|
dw 0 ; section name string table index
|
|
; Save a copy of the size of this chunk for our future reference, by comparing
|
|
; the current posiion to the label above.
|
|
elf_header_size = $ - elf_header
|
|
|
|
;;;
|
|
;;; Third, immediately after the ELF file header, we output ELF's program
|
|
;;; header, which lists the memory regions ("segments") we want to have and
|
|
;;; where we want them to come from. We list just a single region, which is
|
|
;;; the entire contents of the ELF file from disk.
|
|
;;;
|
|
;;; It would be more typical to use this header to ask the loader to give us
|
|
;;; separate code and data segments, and perhaps a stack or heap, but this
|
|
;;; keeps things simple, and we can create those things for ourselves later.
|
|
;;;
|
|
;;; We do have a little stack space available, though we don't explicitily
|
|
;;; request any; the kernel allocates it for us as part of exec() so that it
|
|
;;; can pass us argc and argv (which we ignore). That stack space will be at a
|
|
;;; random address, different every time, because of ASLR; that's a neat
|
|
;;; security feature, so we leave it as-is.
|
|
;;;
|
|
program_header:
|
|
dd 1 ; *"loadable" segment type
|
|
dd 0x05 ; *read+execute permission
|
|
dq 0 ; *offset in file
|
|
dq $$ ; *virtual address
|
|
; required, but can be anything, subject to alignment
|
|
dq 0 ; physical address (ignored)
|
|
dq file_size ; *size in file
|
|
dq file_size ; *size in memory
|
|
dq 0 ; segment alignment
|
|
; for relocation - will we be ASLR'd?
|
|
; Save the size of this chunk, as well.
|
|
program_header_entry_size = $ - program_header
|
|
|
|
; Everything after this point is code or data, not headers, so save the start
|
|
; of it for use in size calculations later.
|
|
code_start:
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;; Execution model ;;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; We use Forth-style dual stacks, one for values and one for control. We
|
|
;;; use rsp for values, just like C does. We use rbp for the control stack,
|
|
;;; which is a special Forth-y stack: These are pointers into the bodies of
|
|
;;; Forth words, not return addresses.
|
|
;;;
|
|
;;; The choice of rsp and rbp for the stack pointers imitates Jonesforth;
|
|
;;; I'm hopeful that it gives us convenient addressing modes, and will report
|
|
;;; back about that when I feel that I understand the implications.
|
|
;;;
|
|
;;; In Forth, everything is a "word", including mutable variables.
|
|
;;; Conceptually, a word is a unit of execution, which may be implemented
|
|
;;; either in machine code or as an array of pointer to other words.
|
|
;;;
|
|
;;; This polymorphism is implemented by having each word's contents begin
|
|
;;; with a "codeword", which is a pointer to machine code that "interprets"
|
|
;;; the rest of the contents. In the case of words implemented in machine
|
|
;;; code, the codeword points directly to that code, which is normally right
|
|
;;; next to it.
|
|
;;;
|
|
;;; Variables, to Forth, are simply one more thing that can be executed; the
|
|
;;; effect of executing a variable is to push its address onto the value
|
|
;;; stack.
|
|
;;;
|
|
;;; We adopt this model of words, codewords, and variables-as-words. It's
|
|
;;; really nice how it doesn't force anything else on us, not even a heap,
|
|
;;; though we do end up using a heap.
|
|
;;;
|
|
;;; We specifically implement a version of calling and returning that Forth
|
|
;;; calls indirect threaded code: The control stack is a stack of pointers
|
|
;;; into the middle of interpreted words. The interpreter snippet, called
|
|
;;; docol, implements calling. Each word is responsible for making sure
|
|
;;; returning works properly. Interpreted words accomplish this by ending with
|
|
;;; the word "exit", while machine-code words accomplish it by ending with a
|
|
;;; verbatim snippet called "next".
|
|
;;;
|
|
;;; Conceptually, "next" returns, but more specifically it accomplishes this
|
|
;;; by doing the caller's next dispatch for it; thus control never actually
|
|
;;; goes back to the caller's interpreter after initial setup. For performance
|
|
;;; reasons, "next" is always inlined, so we define it as a macro.
|
|
;;;
|
|
;;; The docol routine is just ordinary code, not a macro. It's defined later
|
|
;;; in this file, as a label.
|
|
;;;
|
|
;;; Notionally, we could consider not having a dictionary, and not giving
|
|
;;; our words names. However, it feels silly to stop when we're so close to
|
|
;;; being a full Forth, and using names for things solves a bootstrapping
|
|
;;; problem related to heap management - see the write-up of _start about how
|
|
;;; the heap is created, below. So, we add an additional header before the
|
|
;;; codeword for this purpose.
|
|
;;;
|
|
;;; The Forth dictionary is usually a linked list of every word that has
|
|
;;; ever been defined, with the newest at the head; the names of words are
|
|
;;; stored in string fields, often right next to the link pointer. We adopt
|
|
;;; this model, with the field sizes and order shown in the quick reference
|
|
;;; below. We break with Forth tradition in one way: Rather than having a
|
|
;;; length field, we use a null-terminated string. Thus, there's no length
|
|
;;; limit on names. This necessitates breaking out the flags (to be explained
|
|
;;; later) into their own byte, rather than taking bits from the length field
|
|
;;; for them.
|
|
;;;
|
|
;;; There's an important performance consideration: Executable words
|
|
;;; reference each other by pointers to their respective codewords. However,
|
|
;;; dictionary entries reference each other by pointers to their respective
|
|
;;; link fields. Traversing from the link field to the codeword is easy,
|
|
;;; though it's a non-constant-time operation: Just walk the string. In order
|
|
;;; to make Forth words easy to "decompile", it would be nice to also have a
|
|
;;; way to traverse backwards. We solve this by making the name field be
|
|
;;; null-terminated at both ends. Fun, yeah?
|
|
;;;
|
|
;;;
|
|
;;;
|
|
;;;
|
|
;;; --------------------------------------------------------------------------
|
|
;;; Quick Reference
|
|
;;; --------------------------------------------------------------------------
|
|
;;;
|
|
;;; The layout of an interpreted word:
|
|
;;;
|
|
;;; (overall start)
|
|
;;; 0x00 - 0x08 Link (to next-oldest word)
|
|
;;; 0x09 - 0x09 HM00000I Flags
|
|
;;; H - hidden
|
|
;;; M - metadata
|
|
;;; I - immediate
|
|
;;; all other bits reserved
|
|
;;; (name start)
|
|
;;; 0x0a - 0x0a Null byte (terminates name)
|
|
;;; 0x0b - name-end - 1 Name, as UTF-8
|
|
;;; name-end - name-end Null byte (terminates name)
|
|
;;; (padding start)
|
|
;;; name-end + 1 - codeword-start - 1 Zero-pad to 8-byte boundary
|
|
;;; (it's possible this will be zero bytes long)
|
|
;;; (codeword start)
|
|
;;; ... + 0x00 - ... + 0x08 Codeword (ie. address of docol)
|
|
;;; (8-byte chunks) Addresses of other words
|
|
;;; - ... (end) Address of "exit" word
|
|
;;;
|
|
;;; The layout of a machine-code word is different only from the codeword on:
|
|
;;;
|
|
;;; ... + 0x00 - ... + 0x08 Addresss of next byte
|
|
;;; ... + 0x08 - ???? Arbitrary machine code
|
|
;;; - ... (end) Inlined implementation of next
|
|
;;;
|
|
;;; Also, words always start at 8-byte boundaries.
|
|
;;;
|
|
;;;
|
|
;;; REGISTER usage conventions:
|
|
;;;
|
|
;;; * rsi is the "instruction pointer" for the "interpreter".
|
|
;;; That is, it points to some word-pointer inside an array of
|
|
;;; word-pointers inside the content of the word they're part of. It always
|
|
;;; points to the next word that should be executed, whose execution hasn't
|
|
;;; begun yet.
|
|
;;;
|
|
;;; * rbp points to the top of the control stack
|
|
;;; These are former values of rsi, to eventually be returned to, from
|
|
;;; successively older callers as you look further up the stack. The stack
|
|
;;; grows downwards in memory. Since values are kept separately, the only
|
|
;;; thing on the control stack is return addresses, one per layer of call.
|
|
;;;
|
|
;;; * rsp points to the top of the value stack
|
|
;;; The value stack has no specific format, but it grows downwards in
|
|
;;; memory. In particular there's no concept of stack frames, because items
|
|
;;; on the stack don't belong to any particular word; the value stack in
|
|
;;; Forth is in part a mechanism for passing values between words.
|
|
;;;
|
|
;;; Additionally, immediately after beginning execution of a word:
|
|
;;;
|
|
;;; * rax points to the address of the codeword being executed
|
|
;;; The value of rax is purely for the callee's benefit, and does not need
|
|
;;; to be preserved.
|
|
;;;
|
|
;;; Other registers are purely discretionary, and are not preserved across
|
|
;;; calls.
|
|
;;;
|
|
;;;
|
|
;;; FLAG usage:
|
|
;;;
|
|
;;; * DF should be 0
|
|
;;; We use lodsq extensively and that makes it increment rsi after using it.
|
|
;;;
|
|
;;; --------------------------------------------------------------------------
|
|
|
|
;;;
|
|
;;; Macro next
|
|
;;; ----------
|
|
;;;
|
|
;;; Include this inline at the end of a word implemented in machine-code.
|
|
;;; Conceptually, it returns. What it actually does is do the next thing the
|
|
;;; caller would do, which is call the next word from the caller's array of
|
|
;;; word pointers.
|
|
;;;
|
|
;;; Registers in:
|
|
;;;
|
|
;;; * rsi points to the address of the word to execute
|
|
;;;
|
|
;;; Registers out:
|
|
;;;
|
|
;;; * rax points to the codeword in the contents of the word that was executed
|
|
;;; * rsi points to the next word-address after this one
|
|
;;;
|
|
;;; Flags
|
|
;;; * DF = 0 is required
|
|
;;;
|
|
macro next
|
|
; Copy the next word's address from *rsi into rax. Increment rsi (as per the
|
|
; DF flag).
|
|
lodsq
|
|
|
|
; Load the codeword from the word's contents, and jump to the interpreter it
|
|
; points to.
|
|
jmp.abs.indirect.qreg rax
|
|
end macro
|
|
|
|
;;;
|
|
;;; Macro beforenext
|
|
;;; ----------------
|
|
;;;
|
|
;;; Sometimes we want to transfer control from a word implemented in
|
|
;;; machine-code to another word, without coming back after, as if we were
|
|
;;; simply jumping to it. This is an innovation of ours; Jonesforth doesn't do
|
|
;;; it.
|
|
;;;
|
|
;;; This implementation will work regardless of how the receiving word is
|
|
;;; implemented. It impersonates the "next" snippet, setting up rax to point
|
|
;;; to the codeword then jumping to the interpreter. Since it doesn't change
|
|
;;; the control stack or rsi, when the receiving word eventually invokes
|
|
;;; "next"; it will pick up in the same place as if this sending word had done
|
|
;;; it.
|
|
;;;
|
|
;;; Thus, notionally we are doing just this one transfer of control before
|
|
;;; eventually getting around to inlining "next". Hence the name.
|
|
;;;
|
|
macro beforenext target
|
|
; 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.
|
|
mov.qreg.qimm rax, target
|
|
jmp.abs.indirect.qreg rax
|
|
end macro
|
|
|
|
;;;
|
|
;;; Macros pushcontrol
|
|
;;; popcontrol
|
|
;;; ------------------
|
|
;;;
|
|
;;; Include these inline to push an address onto the control stack, or pop
|
|
;;; one off of it. You will recall the control stack is kept in rbp. The
|
|
;;; parameter is given in a user-specified register.
|
|
;;;
|
|
;;; Jonesforth's analogous macros are called PUSHRSP and POPRSP but I think
|
|
;;; that's super confusing, since rsp is also the name of a register, but a
|
|
;;; different one. I guess it was less confusing in 32-bit, since esp doesn't
|
|
;;; start with an "r". Anyway, this has to be named something that
|
|
;;; distinguishes it from Intel's PUSH and POP opcodes, so...
|
|
;;;
|
|
;;; "Load effective address" is just a cute way to do arithmetic on a
|
|
;;; register, here. To push or pop we decrement or increment rbp by 8. To
|
|
;;; actually interact with the space in the stack, we indirect through rbp.
|
|
;;;
|
|
;;; Registers in and out:
|
|
;;;
|
|
;;; * rbp points to the top of the control stack.
|
|
;;;
|
|
macro pushcontrol source
|
|
lea.qreg.disp8.qreg rbp, -8, rbp
|
|
mov.disp8.qreg.qreg 0, rbp, source
|
|
end macro
|
|
|
|
macro popcontrol target
|
|
mov.qreg.disp8.qreg target, 0, rbp
|
|
lea.qreg.disp8.qreg rbp, 8, rbp
|
|
end macro
|
|
|
|
;;;
|
|
;;; Routine _start
|
|
;;; --------------
|
|
;;;
|
|
;;; This is the entry point of the whole program, the very first code we
|
|
;;; actually execute. Linkers traditionally call this _start, and on balance
|
|
;;; I think it's probably best to keep that name, though I've honestly never
|
|
;;; liked it... Anyway, the ELF header points to it and exec() jumps to it.
|
|
;;; Also, though it could be anywhere in the code part of the output, in order
|
|
;;; to make the hexdump pretty we put it at the start.
|
|
;;;
|
|
;;; The kernel gives us most registers zeroed, and rsp pointing to the
|
|
;;; command-line stuff (argc, argv, envp), which is at an ASLR'd address with
|
|
;;; some stack space allocated for us, despite the fact we didn't request any.
|
|
;;; It also gives us all the flags clear except IF, but we don't rely on that.
|
|
;;; Lastly, of course, it loads our code segment and sets the instruction
|
|
;;; pointer where we asked; we don't need to check what those addresses are,
|
|
;;; because they're not randomized.
|
|
;;;
|
|
;;; This routine is really only responsible for one-time initialization.
|
|
;;;
|
|
;;; Registers in:
|
|
;;;
|
|
;;; * rsp points to the logical top of the value stack
|
|
;;; The kernel sets this up for us, and we need to save it somewhere so
|
|
;;; Forth can use it.
|
|
;;;
|
|
;;; Registers out:
|
|
;;;
|
|
;;; * rsi points within "quit"
|
|
;;; Quit is the word that's Forth's closest equivalent to main().
|
|
;;; * rsp points to the top of the value stack
|
|
;;;
|
|
;;; Notably, rbp is still uninitialialized after _start.
|
|
;;;
|
|
;;; Stack in:
|
|
;;;
|
|
;;; * argc, argv, envp in the usual Unix way
|
|
;;; We ignore them, though.
|
|
;;;
|
|
;;; Stack out:
|
|
;;;
|
|
;;; * The value of "heap", as a pointer
|
|
;;; The meaning of this will be explained below.
|
|
;;;
|
|
;;; Registers within:
|
|
;;;
|
|
;;; * rdi points to the base the heap was allocated at, once it exists
|
|
;;; This is the same value that "heap" will hold, once we reach a point
|
|
;;; where we have variables. Of course, variables are stored on the heap,
|
|
;;; hence this temporary measure.
|
|
;;;
|
|
;;; We also take this opportunity to define soeme memory layout parameters
|
|
;;; that this routine will be responsible for doing something with:
|
|
;;;
|
|
heap_requested_address = 0x0000001000000000 ; (very arbitrary)
|
|
heap_size = 0x0000000001000000 ; 16 MiB
|
|
control_stack_size = 0x10000 ; 64 KiB
|
|
|
|
_start:
|
|
cld ; clear the DF flag
|
|
|
|
;;;
|
|
;;; Prepare the heap.
|
|
;;;
|
|
;;; We could ask for a data segment in the program header, but where's the
|
|
;;; fun in that? Instead, we call mmap().
|
|
;;;
|
|
;;; If we wanted the kernel to do ASLR for us, passing address zero would
|
|
;;; cause it to pick somewhere at random, but instead we choose our own
|
|
;;; location. It's still not guaranteed to be where we ask for, so we still
|
|
;;; do the work to record where it wound up. We could pass the "fixed" flag
|
|
;;; and the kernel would trust us, but this gives us more options for
|
|
;;; interoperating with other runtimes.
|
|
;;;
|
|
mov.qreg.qimm rax, 9 ; mmap()
|
|
mov.qreg.qimm rdi, heap_requested_address ; address (very arbitrary)
|
|
mov.qreg.qimm rsi, heap_size ; size (one meg)
|
|
mov.qreg.qimm rdx, 0x07 ; protection (read+write+execute)
|
|
mov.oreg.qimm r10, 0x22 ; flags (private+anonymous)
|
|
mov.oreg.qimm r8, 0 ; file descriptor (ignored)
|
|
mov.oreg.qimm r9, 0 ; offset (ignored)
|
|
syscall
|
|
|
|
;;;
|
|
;;; The return value of the system call is in rax, we'll use it in a sec.
|
|
;;; We need to save this somewhere in case we ever want to munmap() it;
|
|
;;; there's no widely-used name for it so we have to make one up. S0 and r0
|
|
;;; are widely-used names for the physical tops (logical bottoms) of the
|
|
;;; value and control stacks, respectively, and we will eventually set those
|
|
;;; up as well, so we should keep those names in mind. The control stack
|
|
;;; lives within the heap, while the value stack is its own segment. This
|
|
;;; value, though, is the physical bottom of the segment, meaning that it
|
|
;;; stays the same even as we allocate and deallocate things within it. This
|
|
;;; is unlike the two stack pointers, so we give it a name that doesn't
|
|
;;; suggest similarity: "heap".
|
|
;;;
|
|
;;; Once Forth is fully set up, its internal variables will be accessed
|
|
;;; through variable-words like any other Forth data, including "heap". To
|
|
;;; get to that point, though, we need to be able to hold onto variable data
|
|
;;; between now and then. In fact, if we don't have at least one of "heap"
|
|
;;; and "here" (its counterpart which points to the logical top end), all
|
|
;;; our efforts to hold onto anything seem a bit doomed.
|
|
;;;
|
|
;;; So, we temporarily dedicate rdi to "heap" - only within this routine -
|
|
;;; and store everything else in ways that let us find things by reference
|
|
;;; to it. We choose rdi because it works with the indexing modes we care
|
|
;;; about, and its name suggests its function.
|
|
;;;
|
|
;;; The strategy Jonesforth uses is not applicable to us; Jonesforth
|
|
;;; takes advantage of the linker to let its code segment refer to specific,
|
|
;;; pre-allocated objects in the data segment. We are our own linker.
|
|
;;; Hence, this approach.
|
|
;;;
|
|
;;; Keying things off "heap" is the fundamental decision, but to make sure
|
|
;;; our variables are accessible both during early bootstrapping, and later,
|
|
;;; we also have to be thoughtful about data structures. More on that in a
|
|
;;; moment.
|
|
;;;
|
|
mov.qreg.qreg rdi, rax
|
|
|
|
;;;
|
|
;;; We also initialize rbp. We could hold off and let "quit" do this, but
|
|
;;; doing it now is the easiest way to initialize the r0 variable, since
|
|
;;; there's no instruction that moves a 64-bit immediate to memory.
|
|
;;;
|
|
;;; This is the moment at which we decide where the control stack starts!
|
|
;;; Fun, right? "Allocation" is just a fancy word for picking where we want
|
|
;;; something, then being consistent about it - like placing furniture in
|
|
;;; your home. See below for a little more thought about why here in
|
|
;;; particular.
|
|
;;;
|
|
lea.qreg.disp32.qreg rbp, control_stack_size, rdi
|
|
|
|
;;;
|
|
;;; Now we save some stuff onto the heap. These are the locations that
|
|
;;; will eventually be the backing stores of the Forth variables, but we
|
|
;;; don't create the word headers yet, since there's no requirement that
|
|
;;; they be next to the backing stores. We'll do that later, once we have
|
|
;;; word-writing infrastructure in place. For now, we just use their offsets
|
|
;;; relative to the physical bottom of the heap, which are fixed.
|
|
;;;
|
|
;;; These will be the permanent homes of these values, though we have
|
|
;;; copies of them elsewhere while we're still in this routine.
|
|
;;;
|
|
mov.qreg.disp32.qreg rdi, control_stack_size + 0x00, rdi ; log
|
|
mov.qreg.disp32.qreg rdi, control_stack_size + 0x08, rsp ; s0
|
|
mov.qreg.disp32.qreg rdi, control_stack_size + 0x10, rbp ; r0
|
|
mov.qreg.qimm rax, final_word_name
|
|
mov.qreg.disp32.qreg rdi, control_stack_size + 0x18, rax ; latest
|
|
lea.qreg.disp32.qreg rax, control_stack_size + 0x28, rdi
|
|
mov.qreg.disp32.qreg rdi, control_stack_size + 0x20, rax ; here
|
|
;;;
|
|
;;; * "log" is the physical bottom of the log
|
|
;;; The log grows upwards in memory, so this is also the logical
|
|
;;; bottom. This comes from the address mmap() just returned to us.
|
|
;;; The rest of quine.asm refers to the log as the heap. It's not a
|
|
;;; heap, but it used to be called that. The self-hosted version of
|
|
;;; Evocation has the fully revised and reconciled copy of all these
|
|
;;; comments, it just felt like unnecessary tedium to do that here as
|
|
;;; well.
|
|
;;; * "s0" is the logical bottom of the value stack
|
|
;;; The value stack grows downwards in memory, so this is the physical
|
|
;;; top of it. This comes from the stack pointer the kernel initialized us
|
|
;;; with.
|
|
;;; * "r0" is the logical bottom of the control stack
|
|
;;; The control stack also grows downwards, so this is its pysical top
|
|
;;; as well. We allocate this dedicated space within the heap right here,
|
|
;;; in this routine, through our choice of where to put things.
|
|
;;; * "here" is the physical start of the unallocated space in the heap
|
|
;;; We allocate heap space from bottom to top, by incrementing this
|
|
;;; value. So, it would also be accurate to say that it points immediately
|
|
;;; after the physical top of the allocated space. At any rate, the
|
|
;;; address it points to is the first one that hasn't been used yet.
|
|
;;; * "latest" is the address of the most-recently-defined word's header
|
|
;;; Defining new words changes this value.
|
|
;;;
|
|
;;; s0 and r0 are mostly used when we want to initialize or reinitialize
|
|
;;; their respective stacks - that is, discard all their contents at once.
|
|
;;;
|
|
;;; The value of r0 is the same address these variables start at, so
|
|
;;; you'll want to do a close read of the implementation of pushcontrol
|
|
;;; and convince yourself that it only ever writes things just below the rbp
|
|
;;; address it receives, never right on top of it.
|
|
;;;
|
|
;;; As an aside, by the way, please notice that strictly speaking, r0
|
|
;;; could be a constant... but it isn't known until runtime, so we might as
|
|
;;; well make it a variable. That will play nicely with any astonishing
|
|
;;; memory shenanigans someone might wish to do in the future.
|
|
;;;
|
|
;;; Notice also that "here" points immediately after itself. This is just
|
|
;;; a convenience, making it the last one like that so that the concern is
|
|
;;; dealt with in a single place and is easy to keep up-to-date with code
|
|
;;; changes.
|
|
;;;
|
|
;;; A little more detail about why we offset everything by
|
|
;;; control_stack_size: We're carving out some space at the bottom of the
|
|
;;; heap - which grows low-to-high - to be the control stack - which grows
|
|
;;; high-to-low. So the control stack is allocated out of the heap as a
|
|
;;; fixed-size, one-time thing, and then the variables come immediately
|
|
;;; after that. We do need to use 32-bit displacement indexing to access
|
|
;;; them this way, but that's no big deal.
|
|
;;;
|
|
;;; This is perhaps questionable, they should maybe be separate segments
|
|
;;; created with separate calls to mmap(), but for now we're not worried
|
|
;;; about overflow so we use the same allocation for both.
|
|
;;;
|
|
;;; We'll come back to these variables a bit later and generate the word
|
|
;;; headers that point at them, but now we're almost ready to switch to
|
|
;;; proper threaded-execution, so we finish that setup first...
|
|
;;;
|
|
|
|
;;;
|
|
;;; Push the value of "heap" onto the value stack so that it can be the
|
|
;;; breadcrumb the threaded code needs to find... the backing store of
|
|
;;; "heap". Yes, self-reference can be weird like that sometimes. There's
|
|
;;; nothing stopping "quit" from reading rdi, it just violates the
|
|
;;; abstraction...
|
|
;;;
|
|
push.qreg rdi
|
|
|
|
;;;
|
|
;;; 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!
|
|
;;;
|
|
mov.qreg.qimm rsi, cold_start
|
|
next
|
|
|
|
;;;
|
|
;;; This isn't really a routine so much as it's an array of words (exactly
|
|
;;; one of them), which is what "next" wants rsi to point to. It's only ever
|
|
;;; used this one time, so we just put it right here.
|
|
;;;
|
|
|
|
align 8
|
|
cold_start:
|
|
;;; Before handing off to us, _start pushed a single value onto the stack,
|
|
;;; a pointer to the beginning of the heap. Now, we load our entire Forth
|
|
;;; implementation onto that heap, beginning with the minimal set of words
|
|
;;; needed to define more words. We do this because we need variables as
|
|
;;; infrastructure so we can eventually have dynamic definitions.
|
|
;;;
|
|
;;; There's something non-obvious here: words implemented statically as
|
|
;;; part of the executable image can't contain things that vary at runtime.
|
|
;;; That means that even if these words tried to implement some sort of
|
|
;;; dynamic lookup, they would have no way to find the root of whatever
|
|
;;; dynamic data structure they use. Dynamism needs to be bootstrapped.
|
|
;;;
|
|
;;; In a more traditional C-style program, static code could look up
|
|
;;; variables based on fixed addresses that are the same on every run.
|
|
;;; Failing that, we could dedicate a register to it, though that's a
|
|
;;; considerable expense. We chose not to do either of those things, because
|
|
;;; we want the versatility that comes with not being picky about our
|
|
;;; address space: It allows us to contemplate future improvements such as
|
|
;;; ASLR, or embedding into other processes that impose their own addressing
|
|
;;; constraints, or even coexisting with multiple versions of ourselves.
|
|
;;; That choice does mean we have the hard version of this bootstrapping
|
|
;;; problem, and copying ourselves to the heap is how we solve it.
|
|
;;;
|
|
;;; We do have the heap address right now, though that won't last. In case
|
|
;;; it's unclear why not: keeping it on the stack would require all future
|
|
;;; references to walk the stack, and somehow know when they've reached the
|
|
;;; bottom. The stack is a good place to keep things with clearly delimited
|
|
;;; lifetimes and visibility, but when we want something to live for our
|
|
;;; entire program and be easy to find from any code within it, we need to
|
|
;;; do something else. Anyway, since we have the address, we can use it for
|
|
;;; the next little bit of setup.
|
|
;;;
|
|
;;; The first few words we define are our variables, which hardcode the
|
|
;;; addresses they will return - but since we're doing this at runtime,
|
|
;;; "hardcoding" can reflect where our heap is. This is the fundamental
|
|
;;; trick that makes the heap usable.
|
|
;;;
|
|
;;; One more thing to notice: We already allocated the backing stores of
|
|
;;; these variables, and populated their initial values, in _start. The
|
|
;;; words we're defining return those same addresses for the same backing
|
|
;;; stores. So, we have continuity: Stuff defined in terms of the
|
|
;;; variable-words we're defining now will interoperate with the stuff that
|
|
;;; we define in the "early" way, which includes those very words. Both the
|
|
;;; early code and the later code are dealing with the same data structures,
|
|
;;; they're just using a different technique to find them.
|
|
;;;
|
|
;;; This is the only hardcoding we need to do; by building on top of it,
|
|
;;; we will soon reach a point where the rest of the system can be defined
|
|
;;; within itself.
|
|
dq early_heap, litstring, "log", early_variable
|
|
dq early_s0, litstring, "s0", early_variable
|
|
dq early_r0, litstring, "r0", early_variable
|
|
dq early_latest, litstring, "latest", early_variable
|
|
dq early_here, litstring, "here", early_variable
|
|
|
|
;;; Now we define a heap version of docol. Strictly speaking it doesn't
|
|
;;; need to be among the first words, it only needs to come before the first
|
|
;;; words implemented in Forth. However, it's conceptually tidy to have it
|
|
;;; that way, so that's what we do.
|
|
;;;
|
|
;;; Docol also presents a unique challenge, in that it's two snippets of
|
|
;;; code and one of them needs to refer to the other. When we use docol as
|
|
;;; the codeword of a word we're defining, we point to a snippet which acts
|
|
;;; as an interpreter for the word's body. However, when we look up "docol"
|
|
;;; in the dictionary, what we get is a word that returns the address of the
|
|
;;; interpreter snippet, effectively acting as a constant.
|
|
;;;
|
|
;;; One way to make this work would be to use a forward-referencing
|
|
;;; address using the labels system. However, it turns out that only docol
|
|
;;; and zbranch would benefit from this, and we drastically simplify our
|
|
;;; code by reworking things so that no forward reference is needed.
|
|
;;;
|
|
;;; What we do is define the interpreter snippet first, allocating space
|
|
;;; for the machine code directly out of "here", with no word header nor any
|
|
;;; dictionary entry pointing to it. We keep track of the address we put
|
|
;;; that at, then we define the constant to point to it.
|
|
;;;
|
|
;;; While it may seem weird to use space that's "outside" of any word,
|
|
;;; keep in mind that using the heap in creative ways is part of the spirit
|
|
;;; of Forth. Jonesforth doesn't have this bootstapping problem, but its
|
|
;;; variables use this same technique of putting the value before the word
|
|
;;; header to avoid a forward reference. Also, words don't have end
|
|
;;; delimiters, so who's to say what's inside or outside them?
|
|
dq early_here, fetch, dup
|
|
dq rsi, pack_pushcontrol
|
|
dq lit, 8, rax, add_reg64_imm8
|
|
dq rax, rsi, mov_reg64_reg64
|
|
dq pack_next
|
|
dq lit, 8, packalign
|
|
dq roll3, swap, early_here_store, swap
|
|
; Now the interpreter snippet is in-place and "here" points after it, so
|
|
; that future allocation won't step on it. We also still have a copy of its
|
|
; start address, which we will now pass to early_variable.
|
|
dq litstring, "docol", early_variable
|
|
; (While it might be tidy to have a separate "early_constant", it would do
|
|
; the same thing. Late variables and constants will be different because the
|
|
; real "variable" word will also be responsible for allocating the backing
|
|
; 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
|
|
dq lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "swap", early_create, early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64, rbx, pop_reg64, rax, push_reg64, rbx, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "drop", early_create, early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "drop2".
|
|
dq litstring, "2drop", early_create, early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64, rax, pop_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "roll", early_create, early_self_codeword, early_here, fetch
|
|
dq rcx, pop_reg64
|
|
dq rcx, dec_reg64
|
|
dq rsp, rcx, lit, 8, rbx, mov_reg64_indexed_reg64
|
|
dq rsi, push_reg64
|
|
dq rsp, rcx, lit, 8, rsi, lea_reg64_indexed_reg64
|
|
dq rsp, rcx, lit, 8, lit, 8, rdi, lea_reg64_disp8_indexed_reg64
|
|
dq std
|
|
dq rep_movs64
|
|
dq cld
|
|
dq rsi, pop_reg64
|
|
dq rbx, rsp, mov_indirect_reg64_reg64
|
|
dq pack_next, 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
|
|
dq rcx, pop_reg64
|
|
dq rcx, dec_reg64
|
|
dq rcx, rdx, mov_reg64_reg64
|
|
dq rsp, rbx, mov_reg64_indirect_reg64
|
|
dq rsi, push_reg64
|
|
dq rsp, lit, 16, rsi, lea_reg64_disp8_reg64
|
|
dq rsp, lit, 8, rdi, lea_reg64_disp8_reg64
|
|
dq rep_movs64
|
|
dq rsi, pop_reg64
|
|
dq rbx, rsp, rdx, lit, 8, mov_indexed_reg64_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "roll3".
|
|
dq litstring, "3roll", early_create, early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rbx, pop_reg64
|
|
dq rcx, pop_reg64
|
|
dq rbx, push_reg64
|
|
dq rax, push_reg64
|
|
dq rcx, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "unroll3".
|
|
dq litstring, "3unroll", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rbx, pop_reg64
|
|
dq rcx, pop_reg64
|
|
dq rax, push_reg64
|
|
dq rcx, push_reg64
|
|
dq rbx, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "dup", early_create, early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rax, push_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "dup2".
|
|
dq litstring, "2dup", early_create, early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rbx, pop_reg64
|
|
dq rbx, push_reg64
|
|
dq rax, push_reg64
|
|
dq rbx, push_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "add".
|
|
dq litstring, "+", early_create, early_self_codeword, early_here, fetch
|
|
dq rbx, pop_reg64
|
|
dq rax, pop_reg64
|
|
dq rbx, rax, add_reg64_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "sub".
|
|
dq litstring, "-", early_create, early_self_codeword, early_here, fetch
|
|
dq rbx, pop_reg64
|
|
dq rax, pop_reg64
|
|
dq rbx, rax, sub_reg64_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mul".
|
|
dq litstring, "*", early_create, early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rbx, pop_reg64
|
|
dq rbx, mul_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, 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
|
|
dq rdx, rdx, xor_reg64_reg64
|
|
dq rbx, pop_reg64
|
|
dq rax, pop_reg64
|
|
dq rbx, divmod_reg64
|
|
dq rdx, push_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, 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
|
|
dq rax, pop_reg64
|
|
dq rbx, pop_reg64
|
|
dq rbx, rax, cmp_reg64_reg64
|
|
dq cc_equal, al, set_reg8_cc
|
|
dq lit, 0x01, rax, and_reg64_imm8
|
|
dq rax, push_reg64
|
|
dq pack_next, 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
|
|
dq rax, pop_reg64
|
|
dq rbx, pop_reg64
|
|
dq rbx, rax, cmp_reg64_reg64
|
|
dq cc_not_equal, al, set_reg8_cc
|
|
dq lit, 0x01, rax, and_reg64_imm8
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "gt".
|
|
dq litstring, ">", early_create, early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rbx, pop_reg64
|
|
dq rbx, rax, cmp_reg64_reg64
|
|
dq cc_greater, al, set_reg8_cc
|
|
dq lit, 0x01, rax, and_reg64_imm8
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "lt".
|
|
dq litstring, "<", early_create, early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rbx, pop_reg64
|
|
dq rbx, rax, cmp_reg64_reg64
|
|
dq cc_less, al, set_reg8_cc
|
|
dq lit, 0x01, rax, and_reg64_imm8
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "ge".
|
|
dq litstring, ">=", early_create, early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rbx, pop_reg64
|
|
dq rbx, rax, cmp_reg64_reg64
|
|
dq cc_greater_equal, al, set_reg8_cc
|
|
dq lit, 0x01, rax, and_reg64_imm8
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "le".
|
|
dq litstring, "<=", early_create, early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rbx, pop_reg64
|
|
dq rbx, rax, cmp_reg64_reg64
|
|
dq cc_less_equal, al, set_reg8_cc
|
|
dq lit, 0x01, rax, and_reg64_imm8
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "gt_unsigned".
|
|
dq litstring, ">unsigned", early_create
|
|
dq early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rbx, pop_reg64
|
|
dq rbx, rax, cmp_reg64_reg64
|
|
dq cc_above, al, set_reg8_cc
|
|
dq lit, 0x01, rax, and_reg64_imm8
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "lt_unsigned".
|
|
dq litstring, "<unsigned", early_create
|
|
dq early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rbx, pop_reg64
|
|
dq rbx, rax, cmp_reg64_reg64
|
|
dq cc_below, al, set_reg8_cc
|
|
dq lit, 0x01, rax, and_reg64_imm8
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "ge_unsigned".
|
|
dq litstring, ">=unsigned", early_create
|
|
dq early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rbx, pop_reg64
|
|
dq rbx, rax, cmp_reg64_reg64
|
|
dq cc_above_equal, al, set_reg8_cc
|
|
dq lit, 0x01, rax, and_reg64_imm8
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "le_unsigned".
|
|
dq litstring, "<=unsigned", early_create
|
|
dq early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rbx, pop_reg64
|
|
dq rbx, rax, cmp_reg64_reg64
|
|
dq cc_below_equal, al, set_reg8_cc
|
|
dq lit, 0x01, rax, and_reg64_imm8
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "&", early_create, early_self_codeword, early_here, fetch
|
|
dq rbx, pop_reg64
|
|
dq rax, pop_reg64
|
|
dq rbx, rax, and_reg64_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "|", early_create, early_self_codeword, early_here, fetch
|
|
dq rbx, pop_reg64
|
|
dq rax, pop_reg64
|
|
dq rbx, rax, or_reg64_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "xor", early_create, early_self_codeword, early_here, fetch
|
|
dq rbx, pop_reg64
|
|
dq rax, pop_reg64
|
|
dq rbx, rax, xor_reg64_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "invert", early_create, early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rax, not_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "lit", early_create, early_self_codeword, early_here, fetch
|
|
dq lods64
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "litstring", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rsi, push_reg64
|
|
dq rsi, rdi, mov_reg64_reg64
|
|
dq rax, rax, xor_reg64_reg64
|
|
dq rcx, rcx, xor_reg64_reg64
|
|
dq rcx, not_reg64
|
|
dq repnz_scas8
|
|
dq rdi, rsi, mov_reg64_reg64
|
|
dq lit, 7, rsi, add_reg64_imm8
|
|
dq lit, 0xF8, rsi, and_reg64_imm8
|
|
dq pack_next, 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
|
|
dq rbx, pop_reg64
|
|
dq rax, pop_reg64
|
|
dq rax, rbx, mov_indirect_reg64_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This is "fetch".
|
|
dq litstring, "@", early_create, early_self_codeword, early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rax, rax, mov_reg64_indirect_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This is "addstore".
|
|
dq litstring, "+!", early_create, early_self_codeword, early_here, fetch
|
|
dq rbx, pop_reg64
|
|
dq rax, pop_reg64
|
|
dq rax, rbx, add_indirect_reg64_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This is "substore".
|
|
dq litstring, "-!", early_create, early_self_codeword, early_here, fetch
|
|
dq rbx, pop_reg64
|
|
dq rax, pop_reg64
|
|
dq rax, rbx, sub_indirect_reg64_reg64
|
|
dq pack_next, 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
|
|
dq rbx, pop_reg64
|
|
dq rax, pop_reg64
|
|
dq al, rbx, mov_indirect_reg64_reg8
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "fetch8".
|
|
dq litstring, "8@", early_create, early_self_codeword, early_here, fetch
|
|
dq rbx, pop_reg64
|
|
dq rax, rax, xor_reg64_reg64
|
|
dq rbx, al, mov_reg8_indirect_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "store16".
|
|
dq litstring, "16!", early_create, early_self_codeword, early_here, fetch
|
|
dq rbx, pop_reg64
|
|
dq rax, pop_reg64
|
|
dq ax, rbx, mov_indirect_reg64_reg16
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "fetch16".
|
|
dq litstring, "16@", early_create, early_self_codeword, early_here, fetch
|
|
dq rbx, pop_reg64
|
|
dq rax, rax, xor_reg64_reg64
|
|
dq rbx, ax, mov_reg16_indirect_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "store32".
|
|
dq litstring, "32!", early_create, early_self_codeword, early_here, fetch
|
|
dq rbx, pop_reg64
|
|
dq rax, pop_reg64
|
|
dq eax, rbx, mov_indirect_reg64_reg32
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "fetch32".
|
|
dq litstring, "32@", early_create, early_self_codeword, early_here, fetch
|
|
dq rbx, pop_reg64
|
|
dq rax, rax, xor_reg64_reg64
|
|
dq rbx, eax, mov_reg32_indirect_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "store_control_stack". Jonesforth calls it RSP!, which looks as
|
|
; if it's meant to be an Intel register name but is actually short for
|
|
; return stack pointer. There is no register by that name, it's a
|
|
; Forth-provided abstraction. That's super confusing, plus as discussed
|
|
; above we call it the control stack not the return stack, so we call it...
|
|
dq litstring, "control!", 0, early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rbp, pop_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
; This was "fetch_control_stack".
|
|
dq litstring, "control@", 0, early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rbp, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
; This was "store_value_stack". Jonesforth calls it DSP!, for data stack
|
|
; pointer. Again, there's no Intel register by that name, and we call it the
|
|
; value stack, so...
|
|
dq litstring, "value!", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rsp, pop_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
; This was "fetch_value_stack".
|
|
dq litstring, "value@", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rsp, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "memcopy", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rsi, rdx, mov_reg64_reg64
|
|
dq rcx, pop_reg64
|
|
dq rdi, pop_reg64
|
|
dq rsi, pop_reg64
|
|
dq rep_movs8
|
|
dq rdx, rsi, mov_reg64_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "memmove", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rsi, rdx, mov_reg64_reg64
|
|
dq rcx, pop_reg64
|
|
dq rdi, pop_reg64
|
|
dq rsi, pop_reg64
|
|
dq rsi, rax, mov_reg64_reg64
|
|
dq rdi, rax, cmp_reg64_reg64
|
|
dq lit, 4, cc_below, jmp_cc_rel_imm8
|
|
dq rep_movs8
|
|
dq lit, 16, jmp_rel_imm8
|
|
dq rcx, rsi, add_reg64_reg64
|
|
dq rsi, dec_reg64
|
|
dq rcx, rdi, add_reg64_reg64
|
|
dq rdi, dec_reg64
|
|
dq std
|
|
dq rep_movs8
|
|
dq cld
|
|
dq rdx, rsi, mov_reg64_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "stringlen", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rdi, pop_reg64
|
|
dq rdi, rbx, mov_reg64_reg64
|
|
dq rax, rax, xor_reg64_reg64
|
|
dq rcx, rcx, xor_reg64_reg64
|
|
dq rcx, not_reg64
|
|
dq repnz_scas8
|
|
dq rbx, rdi, sub_reg64_reg64
|
|
dq lit, 1, rdi, sub_reg64_imm8
|
|
dq rdi, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "reverse_stringlen".
|
|
dq litstring, "reverse-stringlen", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rdi, pop_reg64
|
|
dq rdi, rbx, mov_reg64_reg64
|
|
dq rax, rax, xor_reg64_reg64
|
|
dq rcx, rcx, xor_reg64_reg64
|
|
dq rcx, not_reg64
|
|
dq std
|
|
dq repnz_scas8
|
|
dq cld
|
|
dq rdi, rbx, sub_reg64_reg64
|
|
dq lit, 1, rbx, sub_reg64_imm8
|
|
dq rbx, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "reverse_padding_len".
|
|
dq litstring, "reverse-padding-len", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rdi, pop_reg64
|
|
dq rdi, rbx, mov_reg64_reg64
|
|
dq rax, rax, xor_reg64_reg64
|
|
dq lit, 9, rcx, mov_reg64_imm32
|
|
dq std
|
|
dq repz_scas8
|
|
dq cld
|
|
dq rdi, rbx, sub_reg64_reg64
|
|
dq lit, 1, rbx, sub_reg64_imm8
|
|
dq rbx, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "stringcmp", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rsi, rdx, mov_reg64_reg64
|
|
dq rsi, pop_reg64
|
|
dq rdi, pop_reg64
|
|
dq rbx, rbx, xor_reg64_reg64
|
|
dq rax, rax, xor_reg64_reg64
|
|
dq rsi, rcx, mov_reg64_indirect_reg64
|
|
dq cl, al, mov_reg8_reg8
|
|
dq cmps8
|
|
dq lit, 15, cc_equal, jmp_cc_rel_imm8
|
|
dq cc_above, bl, set_reg8_cc
|
|
dq lit, 0, rbx, sbb_reg64_imm8
|
|
dq rbx, push_reg64
|
|
dq rdx, rsi, mov_reg64_reg64
|
|
dq pack_next
|
|
dq rax, rax, test_reg64_reg64
|
|
dq lit, -28, cc_not_equal, jmp_cc_rel_imm8
|
|
dq lit, 0, push_imm32_extended64
|
|
dq rdx, rsi, mov_reg64_reg64
|
|
dq pack_next
|
|
dq lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "branch", early_create, early_self_codeword, early_here, fetch
|
|
; Save the address we're packing to; it will be the label we jump to from
|
|
; zbranch.
|
|
dq dup, unroll3
|
|
dq rsi, rsi, add_reg64_indirect_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "zbranch".
|
|
dq litstring, "0branch", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rax, rax, test_reg64_reg64
|
|
; Retrieve the saved address for the start of "branch". Compute the
|
|
; relative offset from the current address to it. This will be a negative
|
|
; number. Subtract an additional two bytes, to allow for the length of the
|
|
; jmp instruction.
|
|
dq dup, lit, 4, roll, swap, sub, lit, 2, sub
|
|
; It's slightly counterintuitive that the condition is called cc_equal;
|
|
; that's a result of the condition names favoring cmp over test. While cmp
|
|
; simulates subtraction, test simulates bitwise AND. What we're testing is
|
|
; that the result is zero.
|
|
dq cc_equal, jmp_cc_rel_imm8
|
|
dq lods64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "execute", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rax, pop_reg64
|
|
dq rax, jmp_abs_indirect_reg64
|
|
dq lit, 8, packalign, early_here_store
|
|
|
|
; This was "sys_exit".
|
|
;
|
|
; This name is exactly eight bytes long. Don't even ask (go read litstring's
|
|
; code if you really need to know).
|
|
dq litstring, "sys-exit", 0, early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq lit, 60, rax, mov_reg64_imm64
|
|
dq rdi, pop_reg64
|
|
dq syscall
|
|
dq hlt
|
|
; This one, uniquely, doesn't need to be followed by the "next" macro. It
|
|
; still needs alignment padding though.
|
|
dq lit, 8, packalign, early_here_store
|
|
|
|
; This was "sys_write".
|
|
dq litstring, "sys-write", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rcx, pop_reg64
|
|
dq rdx, pop_reg64
|
|
dq rsi, push_reg64
|
|
dq lit, 1, rax, mov_reg64_imm64
|
|
dq lit, 1, rdi, mov_reg64_imm64
|
|
dq rcx, rsi, mov_reg64_reg64
|
|
dq syscall
|
|
dq rsi, pop_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This was "sys_read".
|
|
dq litstring, "sys-read", 0, early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq rcx, pop_reg64
|
|
dq rdx, pop_reg64
|
|
dq rsi, push_reg64
|
|
dq lit, 0, rax, mov_reg64_imm64
|
|
dq lit, 0, rdi, mov_reg64_imm64
|
|
dq rcx, rsi, mov_reg64_reg64
|
|
dq syscall
|
|
dq rsi, pop_reg64
|
|
dq rax, push_reg64
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
|
|
; This one has the honor of being the first word written in Forth. To do
|
|
; that, it needs to be able to look up the words we've defined so far, to
|
|
; reference them. We have a valid dictionary data structure, and early_find
|
|
; is able to search it, so we can do that.
|
|
;
|
|
; One thing to be cautious of is that if we inadvertently reference a word
|
|
; by the wrong name, we'll get the copy that's statically included in the
|
|
; ELF, rather than the copy on the heap. Watch carefully for that, with all
|
|
; the lookups from here on.
|
|
dq litstring, "emitstring", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "stringlen", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "sys-write", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "pow", early_create, early_docol_codeword
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -22*8, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "logfloor", 0, early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ">unsigned", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "<", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8*8, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -45*8, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "logceil", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ">=unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "<", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8*8, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -45*8, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "dotbase_unsigned"
|
|
dq litstring, ".base-unsigned", early_create, early_docol_codeword
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "logfloor", 0, early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ">", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pow", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "/%", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "/%", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10, early_comma
|
|
dq litstring, ">", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "0", early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6*8, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10, early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "a", early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "value@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3*8, early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -51*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "dotbase".
|
|
dq litstring, ".base", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, ">", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 7*8, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -1, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "-", early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, ".base-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "dot".
|
|
dq litstring, ".", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10, early_comma
|
|
dq litstring, ".base", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "dothex".
|
|
dq litstring, ".hex", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 16, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, ".base-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "dothex8".
|
|
dq litstring, ".hex8", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 16, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2, early_comma
|
|
dq litstring, ".base-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "dothex16".
|
|
dq litstring, ".hex16", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 16, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, ".base-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "dothex32".
|
|
dq litstring, ".hex32", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 16, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, ".base-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "dothex64".
|
|
dq litstring, ".hex64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 16, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 16, early_comma
|
|
dq litstring, ".base-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "crash", early_create, early_self_codeword, early_here, fetch
|
|
dq hlt
|
|
dq lit, 8, packalign, early_here_store
|
|
|
|
; This was "align_size".
|
|
dq litstring, "align-size", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "/%", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, 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_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "pack32", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "32!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "pack16", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "16!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "pack8", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "8!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "packstring", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "stringlen", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "memcopy", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "pack_raw_string".
|
|
dq litstring, "pack-raw-string", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "stringlen", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "memcopy", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "packalign", early_create, early_docol_codeword
|
|
dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "/%", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8*8, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -11*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "litpack64", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq lods64
|
|
dq rax, push_reg64
|
|
; ("heap", modified "here")
|
|
dq swap, litstring, "pack64", early_find, entry_to_execution_token
|
|
; (modified "here", "heap", execution token)
|
|
dq swap, unroll3, pack_beforenext
|
|
dq lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "litpack32", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq lods64
|
|
dq rax, push_reg64
|
|
; ("heap", modified "here")
|
|
dq swap, litstring, "pack32", early_find, entry_to_execution_token
|
|
; (modified "here", "heap", execution token)
|
|
dq swap, unroll3, pack_beforenext
|
|
dq lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "litpack16", early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq lods64
|
|
dq rax, push_reg64
|
|
; ("heap", modified "here")
|
|
dq swap, litstring, "pack16", early_find, entry_to_execution_token
|
|
; (modified "here", "heap", execution token)
|
|
dq swap, unroll3, pack_beforenext
|
|
dq lit, 8, packalign, early_here_store
|
|
|
|
; This name is exactly eight bytes long. Don't even ask (go read litstring's
|
|
; code if you really need to know).
|
|
dq litstring, "litpack8", 0, early_create, early_self_codeword
|
|
dq early_here, fetch
|
|
dq lods64
|
|
dq rax, push_reg64
|
|
; ("heap", modified "here")
|
|
dq swap, litstring, "pack8", early_find, entry_to_execution_token
|
|
; (modified "here", "heap", execution token)
|
|
dq swap, unroll3, pack_beforenext
|
|
dq lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "unpack64", 0, early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "unpack32", 0, early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "32@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "unpack16", 0, early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "16@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "unpack8", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "8@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "unpackalign", early_create, early_docol_codeword
|
|
dq litstring, "align-size", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; The flatassembler names of all these were the same, but without the
|
|
; colons, and with underscores instead of hyphens.
|
|
dq litstring, ":rax", early_keyword
|
|
dq litstring, ":rcx", early_keyword
|
|
dq litstring, ":rdx", early_keyword
|
|
dq litstring, ":rbx", early_keyword
|
|
dq litstring, ":rsp", early_keyword
|
|
dq litstring, ":rbp", early_keyword
|
|
dq litstring, ":rsi", early_keyword
|
|
dq litstring, ":rdi", early_keyword
|
|
dq litstring, ":r8", early_keyword
|
|
dq litstring, ":r9", early_keyword
|
|
dq litstring, ":r10", early_keyword
|
|
dq litstring, ":r11", early_keyword
|
|
dq litstring, ":r12", early_keyword
|
|
dq litstring, ":r13", early_keyword
|
|
dq litstring, ":r14", early_keyword
|
|
dq litstring, ":r15", early_keyword
|
|
dq litstring, ":eax", early_keyword
|
|
dq litstring, ":ecx", early_keyword
|
|
dq litstring, ":edx", early_keyword
|
|
dq litstring, ":ebx", early_keyword
|
|
dq litstring, ":esp", early_keyword
|
|
dq litstring, ":ebp", early_keyword
|
|
dq litstring, ":esi", early_keyword
|
|
dq litstring, ":edi", early_keyword
|
|
dq litstring, ":ax", early_keyword
|
|
dq litstring, ":cx", early_keyword
|
|
dq litstring, ":dx", early_keyword
|
|
dq litstring, ":bx", early_keyword
|
|
dq litstring, ":sp", early_keyword
|
|
dq litstring, ":bp", early_keyword
|
|
dq litstring, ":si", early_keyword
|
|
dq litstring, ":di", early_keyword
|
|
dq litstring, ":al", early_keyword
|
|
dq litstring, ":cl", early_keyword
|
|
dq litstring, ":dl", early_keyword
|
|
dq litstring, ":bl", early_keyword
|
|
dq litstring, ":ah", early_keyword
|
|
dq litstring, ":ch", early_keyword
|
|
dq litstring, ":dh", early_keyword
|
|
dq litstring, ":bh", early_keyword
|
|
dq litstring, ":cc-overflow", early_keyword
|
|
dq litstring, ":cc-no-overflow", early_keyword
|
|
dq litstring, ":cc-below", early_keyword
|
|
dq litstring, ":cc-above-equal", early_keyword
|
|
dq litstring, ":cc-equal", early_keyword
|
|
dq litstring, ":cc-not-equal", early_keyword
|
|
dq litstring, ":cc-below-equal", early_keyword
|
|
dq litstring, ":cc-above", early_keyword
|
|
dq litstring, ":cc-sign", 0, early_keyword
|
|
dq litstring, ":cc-not-sign", early_keyword
|
|
dq litstring, ":cc-even", 0, early_keyword
|
|
dq litstring, ":cc-odd", early_keyword
|
|
dq litstring, ":cc-less", 0, early_keyword
|
|
dq litstring, ":cc-greater-equal", early_keyword
|
|
dq litstring, ":cc-less-equal", early_keyword
|
|
dq litstring, ":cc-greater", early_keyword
|
|
|
|
dq litstring, "reg64", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rax", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rcx", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rdx", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rbx", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rsp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rbp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rsi", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rdi", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 7, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "Paramete", early_comma, lit, "r to reg", early_comma
|
|
dq lit, "64 is no", early_comma, lit, "t a reg6", early_comma
|
|
dq lit, "4.", early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "sys-exit", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "extrareg64", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":r8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":r9", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":r10", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":r11", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":r12", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":r13", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":r14", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":r15", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 7, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "Paramete", early_comma, lit, "r to ext", early_comma
|
|
dq lit, "rareg64 ", early_comma, lit, "is not a", early_comma
|
|
dq lit, "n extrar", early_comma, lit, "eg64.", early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "sys-exit", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "reg32", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":eax", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":ecx", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":edx", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":ebx", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":esp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":ebp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":esi", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":edi", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 7, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "Paramete", early_comma, lit, "r to reg", early_comma
|
|
dq lit, "32 is no", early_comma, lit, "t a reg3", early_comma
|
|
dq lit, "2.", early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "sys-exit", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "reg16", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":ax", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cx", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":dx", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":bx", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":sp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":bp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":si", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":di", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 7, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "Paramete", early_comma, lit, "r to reg", early_comma
|
|
dq lit, "16 is no", early_comma, lit, "t a reg1", early_comma
|
|
dq lit, "6.", early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "sys-exit", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "reg8", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":al", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cl", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":dl", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":bl", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":ah", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":ch", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":dh", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":bh", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 7, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "Paramete", early_comma, lit, "r to reg", early_comma
|
|
dq lit, "8 is not", early_comma, lit, " a reg8.", early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "sys-exit", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "scalefield", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "Paramete", early_comma, lit, "r to sca", early_comma
|
|
dq lit, "lefield ", early_comma, lit, "is not 1", early_comma
|
|
dq lit, ", 2, 4, ", early_comma, lit, "or 8.", early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "sys-exit", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "conditioncode", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-overflow", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-no-overflow", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-below", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-above-equal", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-equal", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-not-equal", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-below-equal", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-above", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 7, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-sign", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-not-sign", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 9, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-even", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-odd", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 11, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-less", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 12, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-greater-equal", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 13, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-less-equal", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 14, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":cc-greater", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 15, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "Paramete", early_comma, lit, "r to con", early_comma
|
|
dq lit, "ditionco", early_comma, lit, "de is no", early_comma
|
|
dq lit, "t a cond", early_comma, lit, "ition co", early_comma
|
|
dq lit, "de.", early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "sys-exit", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rex_w".
|
|
dq litstring, "rex-w", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x48, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rex_b".
|
|
dq litstring, "rex-b", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x41, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rex_wb".
|
|
dq litstring, "rex-wb", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x49, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "opcodereg", early_create, early_docol_codeword
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "opcodecc", 0, early_create, early_docol_codeword
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "modrm", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 64, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "sib", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 64, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "addressing_reg64".
|
|
dq litstring, "addressing-reg64", 0, early_create, early_docol_codeword
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "modrm", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "addressing_indirect_reg64".
|
|
dq litstring, "addressing-indirect-reg64", early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rbp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 23*8, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rsp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "modrm", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8*8, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, ":rsp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "sib", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "R/M para", early_comma, lit, "meter to", early_comma
|
|
dq lit, " address", early_comma, lit, "ing-indi", early_comma
|
|
dq lit, "rect-reg", early_comma, lit, "64 is :r", early_comma
|
|
dq lit, "bp.", early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "sys-exit", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "addressing_disp8_reg64".
|
|
dq litstring, "addressing-disp8-reg64", early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rsp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "modrm", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8*8, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, ":rsp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "sib", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "addressing_disp32_reg64".
|
|
dq litstring, "addressing-disp32-reg64", early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rsp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "modrm", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8*8, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, ":rsp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "sib", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack32", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "addressing_indexed_reg64".
|
|
dq litstring, "addressing-indexed-reg64", 0, early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rbp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 23*8, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "modrm", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "scalefield", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "sib", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "Base par", early_comma, lit, "ameter t", early_comma
|
|
dq lit, "o addres", early_comma, lit, "sing-ind", early_comma
|
|
dq lit, "exed-reg", early_comma, lit, "64 is :r", early_comma
|
|
dq lit, "bp.", early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "sys-exit", 0, early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "addressing_disp8_indexed_reg64".
|
|
dq litstring, "addressing-disp8-indexed-reg64", early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 7, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "modrm", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "scalefield", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "sib", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "addressing_reg8".
|
|
dq litstring, "addressing-reg8", early_create, early_docol_codeword
|
|
dq litstring, "reg8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "modrm", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "cld", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xFC, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "std", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xFD, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_reg64_imm32".
|
|
dq litstring, "mov-reg64-imm32", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xC7, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack32", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_reg64_imm64".
|
|
dq litstring, "mov-reg64-imm64", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xB8, early_comma
|
|
dq litstring, "opcodereg", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_extrareg64_imm64".
|
|
dq litstring, "mov-extrareg64-imm64", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-wb", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "extrareg64", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xB8, early_comma
|
|
dq litstring, "opcodereg", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_reg64_reg64".
|
|
dq litstring, "mov-reg64-reg64", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x89, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_indirect_reg64_reg64".
|
|
dq litstring, "mov-indirect-reg64-reg64", 0, early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x89, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indirect-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_disp8_reg64_reg64".
|
|
dq litstring, "mov-disp8-reg64-reg64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x89, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-disp8-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_reg64_indirect_reg64".
|
|
dq litstring, "mov-reg64-indirect-reg64", 0, early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x8B, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indirect-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_reg64_disp8_reg64".
|
|
dq litstring, "mov-reg64-disp8-reg64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x8B, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-disp8-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_reg64_disp32_reg64".
|
|
dq litstring, "mov-reg64-disp32-reg64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x89, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-disp32-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_reg64_indexed_reg64".
|
|
dq litstring, "mov-reg64-indexed-reg64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x8B, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indexed-reg64", 0, early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_indexed_reg64_reg64".
|
|
dq litstring, "mov-indexed-reg64-reg64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x89, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indexed-reg64", 0, early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_indirect_reg64_reg32".
|
|
dq litstring, "mov-indirect-reg64-reg32", 0, early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x89, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg32", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indirect-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_indirect_reg64_reg32".
|
|
dq litstring, "mov-disp8-reg64-reg32", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x89, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg32", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-disp8-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
;; This was "mov_reg32_indirect_reg64".
|
|
dq litstring, "mov-reg32-indirect-reg64", 0, early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x8B, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg32", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indirect-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_reg32_disp8_reg64".
|
|
dq litstring, "mov-reg32-disp8-reg64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x8B, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg32", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-disp8-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_indirect_reg64_reg16".
|
|
dq litstring, "mov-indirect-reg64-reg16", 0, early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x89, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg16", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indirect-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_disp8_reg64_reg16".
|
|
dq litstring, "mov-disp8-reg64-reg16", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x89, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg16", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-disp8-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_reg16_indirect_reg64".
|
|
dq litstring, "mov-reg16-indirect-reg64", 0, early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x8B, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg16", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indirect-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_reg16_disp8_reg64".
|
|
dq litstring, "mov-reg16-disp8-reg64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x8B, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg16", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-disp8-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_indirect_reg64_reg8".
|
|
dq litstring, "mov-indirect-reg64-reg8", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x88, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indirect-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_disp8_reg64_reg8".
|
|
dq litstring, "mov-disp8-reg64-reg8", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x88, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-disp8-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_reg8_indirect_reg64".
|
|
dq litstring, "mov-reg8-indirect-reg64", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x8A, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indirect-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_reg8_disp8_reg64".
|
|
dq litstring, "mov-reg8-disp8-reg64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x8A, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-disp8-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mov_reg8_reg8".
|
|
dq litstring, "mov-reg8-reg8", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x88, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg8", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "lea_reg64_disp8_reg64".
|
|
dq litstring, "lea-reg64-disp8-reg64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x8D, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-disp8-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "lea_reg64_disp32_reg64".
|
|
dq litstring, "lea-reg64-disp32-reg64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x8D, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-disp32-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "lea_reg64_indexed_reg64".
|
|
dq litstring, "lea-reg64-indexed-reg64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x8D, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indexed-reg64", 0, early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "lea_reg64_disp8_indexed_reg64".
|
|
dq litstring, "lea-reg64-disp8-indexed-reg64", early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x8D, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-disp8-indexed-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "push_reg64".
|
|
dq litstring, "push-reg64", early_create, early_docol_codeword
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x50, early_comma
|
|
dq litstring, "opcodereg", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "push_extrareg64".
|
|
dq litstring, "push-extrareg64", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-b", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "extrareg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x50, early_comma
|
|
dq litstring, "opcodereg", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "pop_reg64".
|
|
dq litstring, "pop-reg64", early_create, early_docol_codeword
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x58, early_comma
|
|
dq litstring, "opcodereg", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "pop_extrareg64".
|
|
dq litstring, "pop-extrareg64", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-b", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "extrareg64", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x58, early_comma
|
|
dq litstring, "opcodereg", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was push_imm32_extended64".
|
|
dq litstring, "push-imm32-extended64", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x68, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack32", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "movs8", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA4, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "movs16", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA5, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "movs32", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA5, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "movs64", early_create, early_docol_codeword
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA5, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rep_movs8".
|
|
dq litstring, "rep-movs8", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA4, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rep_movs16".
|
|
dq litstring, "rep-movs16", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA5, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rep_movs32".
|
|
dq litstring, "rep-movs32", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA5, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rep_movs64".
|
|
dq litstring, "rep-movs64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA5, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "lods8", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAC, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "lods16", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAD, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "lods32", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAD, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "lods64", early_create, early_docol_codeword
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAD, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rep_lods8".
|
|
dq litstring, "rep-lods8", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAC, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rep_lods16".
|
|
dq litstring, "rep-lods16", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAD, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rep_lods32".
|
|
dq litstring, "rep-lods32", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAD, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rep_lods64".
|
|
dq litstring, "rep-lods64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAD, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "stos8", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAA, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "stos16", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAB, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "stos32", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAB, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "stos64", early_create, early_docol_codeword
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAB, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rep_stos8".
|
|
dq litstring, "rep-stos8", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAA, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rep_stos16".
|
|
dq litstring, "rep-stos16", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAB, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rep_stos32".
|
|
dq litstring, "rep-stos32", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAB, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "rep_stos64".
|
|
dq litstring, "rep-stos64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAB, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "cmps8", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA6, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "cmps16", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA7, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "cmps32", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA7, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "cmps64", early_create, early_docol_codeword
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA7, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repz_cmps8".
|
|
dq litstring, "repz-cmps8", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA6, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repz_cmps16".
|
|
dq litstring, "repz-cmps16", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA7, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repz_cmps32".
|
|
dq litstring, "repz-cmps32", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA7, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repz_cmps64".
|
|
dq litstring, "repz-cmps64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA7, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repnz_cmps8".
|
|
dq litstring, "repnz-cmps8", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF2, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA6, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repnz_cmps16".
|
|
dq litstring, "repnz-cmps16", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF2, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA7, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repnz_cmps32".
|
|
dq litstring, "repnz-cmps32", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF2, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA7, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repnz_cmps64".
|
|
dq litstring, "repnz-cmps64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF2, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xA7, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "scas8", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAE, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "scas16", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAF, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "scas32", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAF, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "scas64", early_create, early_docol_codeword
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAF, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repz_scas8".
|
|
dq litstring, "repz-scas8", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAE, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repz_scas16".
|
|
dq litstring, "repz-scas16", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAF, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repz_scas32".
|
|
dq litstring, "repz-scas32", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAF, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repz_scas64".
|
|
dq litstring, "repz-scas64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF3, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAF, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repnz_scas8".
|
|
dq litstring, "repnz-scas8", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF2, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAE, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repnz_scas16".
|
|
dq litstring, "repnz-scas16", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF2, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x66, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAF, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repnz_scas32".
|
|
dq litstring, "repnz-scas32", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF2, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAF, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "repnz_scas64".
|
|
dq litstring, "repnz-scas64", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF2, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xAF, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "add_reg64_reg64".
|
|
dq litstring, "add-reg64-reg64", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x01, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "add_indirect_reg64_reg64".
|
|
dq litstring, "add-indirect-reg64-reg64", 0, early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x01, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indirect-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "add_reg64_indirect_reg64".
|
|
dq litstring, "add-reg64-indirect-reg64", 0, early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x03, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indirect-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "add_reg64_imm8".
|
|
dq litstring, "add-reg64-imm8", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x83, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "sub_reg64_reg64".
|
|
dq litstring, "sub-reg64-reg64", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x2B, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "sub_indirect_reg64_reg64".
|
|
dq litstring, "sub-indirect-reg64-reg64", 0, early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x2B, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indirect-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "sub_reg64_imm8".
|
|
dq litstring, "sub-reg64-imm8", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x83, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "sbb_reg64_imm8".
|
|
dq litstring, "sbb-reg64-imm8", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x83, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "mul_reg64".
|
|
dq litstring, "mul-reg64", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF7, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "divmod_reg64".
|
|
dq litstring, "divmod-reg64", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF7, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "idivmod_reg64".
|
|
dq litstring, "idivmod-reg64", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF7, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 7, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "inc_reg64".
|
|
dq litstring, "inc-reg64", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xFF, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "dec_reg64".
|
|
dq litstring, "dec-reg64", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xFF, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "and_reg64_reg64".
|
|
dq litstring, "and-reg64-reg64", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x23, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "and_reg64_imm8".
|
|
dq litstring, "and-reg64-imm8", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x83, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "or_reg64_reg64".
|
|
dq litstring, "or-reg64-reg64", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0B, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "or_reg64_imm8".
|
|
dq litstring, "or-reg64-imm8", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x83, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "xor_reg64_reg64".
|
|
dq litstring, "xor-reg64-reg64", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x33, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "not_reg64".
|
|
dq litstring, "not-reg64", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF7, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "cmp_reg64_reg64".
|
|
dq litstring, "cmp-reg64-reg64", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x3B, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "test_reg64_reg64".
|
|
dq litstring, "test-reg64-reg64", 0, early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "rex-w", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x85, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-reg64", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "set_reg8_cc".
|
|
dq litstring, "set-reg8-cc", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0F, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "conditioncode", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x90, early_comma
|
|
dq litstring, "opcodecc", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reg8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "modrm", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "jmp_cc_rel_imm8".
|
|
dq litstring, "jmp-cc-rel-imm8", early_create, early_docol_codeword
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "conditioncode", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x70, early_comma
|
|
dq litstring, "opcodecc", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "jmp_cc_rel_imm32".
|
|
dq litstring, "jmp-cc-rel-imm32", 0, early_create, early_docol_codeword
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0F, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "conditioncode", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x70, early_comma
|
|
dq litstring, "opcodecc", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack32", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "jmp_abs_indirect_reg64".
|
|
dq litstring, "jmp-abs-indirect-reg64", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xFF, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "addressing-indirect-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "jmp_rel_imm8".
|
|
dq litstring, "jmp-rel-imm8", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xEB, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "jmp_rel_imm32".
|
|
dq litstring, "jmp-rel-imm32", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xE9, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack32", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "syscall", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0F, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x05, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "hlt", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xF4, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "pack_next".
|
|
dq litstring, "pack-next", early_create, early_docol_codeword
|
|
dq litstring, "lods64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rax", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "jmp-abs-indirect-reg64", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "pack_beforenext".
|
|
dq litstring, "pack-beforenext", early_create, early_docol_codeword
|
|
dq litstring, ":rax", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "mov-reg64-imm64", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, ":rax", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "jmp-abs-indirect-reg64", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "pack_pushcontrol".
|
|
dq litstring, "pack-pushcontrol", 0, early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rbp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -8, early_comma
|
|
dq litstring, ":rbp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lea-reg64-disp8-reg64", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rbp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "mov-disp8-reg64-reg64", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "pack_popcontrol".
|
|
dq litstring, "pack-popcontrol", early_create, early_docol_codeword
|
|
dq litstring, ":rbp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "mov-reg64-disp8-reg64", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, ":rbp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, ":rbp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lea-reg64-disp8-reg64", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "entry_to_execution_token".
|
|
dq litstring, "entry-to-execution-token", 0, early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "stringlen", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 7, early_comma
|
|
dq litstring, "invert", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "execution_token_to_entry".
|
|
dq litstring, "execution-token-to-entry", 0, early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reverse-padding-len", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "reverse-stringlen", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 9, early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "fetch_entry_flags".
|
|
dq litstring, "entry-flags@", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xFF, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "store_entry_flags".
|
|
dq litstring, "entry-flags!", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xFF, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0xFFFFFFFFFFFFFF00, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "entry_to_name".
|
|
dq litstring, "entry-to-name", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "find_in".
|
|
dq litstring, "find-in", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4*8, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "entry-flags@", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x80, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x80, early_comma
|
|
dq litstring, "!=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8*8, early_comma
|
|
dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "stringcmp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4*8, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -28*8, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "next_newer_entry_in".
|
|
dq litstring, "next-newer-entry-in", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4*8, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4*8, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -16*8, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "guess_entry_end_in".
|
|
dq litstring, "guess-entry-end-in", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "entry-flags@", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x01, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x01, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6*8, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "next-newer-entry-in", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "show_hex_between".
|
|
dq litstring, "show-hex-between", 0, early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "entry-to-execution-token", 0, early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ">=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, " ", early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ".hex64", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -17*8, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "show_source_between".
|
|
dq litstring, "show-source-between", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "entry-to-execution-token", 0, early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ">=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "execution-token-to-entry", 0, early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "entry-to-name", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, " ", early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "lit", early_comma
|
|
dq litstring, "stringcmp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 57*8, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "litpack8", early_comma, lit, 0, early_comma
|
|
dq litstring, "stringcmp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 50*8, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "litpack1", early_comma, lit, "6", early_comma
|
|
dq litstring, "stringcmp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 43*8, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "litpack3", early_comma, lit, "2", early_comma
|
|
dq litstring, "stringcmp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 36*8, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "litpack6", early_comma, lit, "4", early_comma
|
|
dq litstring, "stringcmp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 29*8, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "branch", early_comma
|
|
dq litstring, "stringcmp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 23*8, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "zbranch", early_comma
|
|
dq litstring, "stringcmp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 17*8, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "0branch", early_comma
|
|
dq litstring, "stringcmp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 11*8, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "litstrin", early_comma, lit, "g", early_comma
|
|
dq litstring, "stringcmp", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 16*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -82*8, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, " ", early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ".", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -94*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, " ", early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x22, early_comma
|
|
dq litstring, "value@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x22, early_comma
|
|
dq litstring, "value@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "stringlen", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "/%", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -126*8, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; This was "show_source_or_hex_between".
|
|
dq litstring, "show-source-or-hex-between", early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2*8, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "entry-to-execution-token", 0, early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3*8, early_comma
|
|
dq litstring, "show-hex-between", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "show-source-between", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
;;; Now here we have some "original" words that rely on the heap and don't
|
|
;;; have flatassembler-based equivalents.
|
|
|
|
; This has the distinction of having been written in Evocation, in
|
|
; interpret.e, and then back-ported to flatassembler. This is the version
|
|
; that makes clever use of memmove, if we do say so ourselves, to handle
|
|
; immediate-mode string literals as input.
|
|
;
|
|
; In:
|
|
; name string
|
|
dq litstring, "create", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "stringlen", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "here", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "memmove", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "here", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "latest", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "pack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "packalign", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "here", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "latest", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "here", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; In:
|
|
; value to append to current word-in-progress
|
|
dq litstring, ",", early_create, early_docol_codeword
|
|
dq litstring, "here", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack64", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "here", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "self-codeword", early_create, early_docol_codeword
|
|
dq litstring, "here", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ",", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; In:
|
|
; address for new variable word to return
|
|
; name string
|
|
dq litstring, "variable", 0, early_create, early_docol_codeword
|
|
dq litstring, "create", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "self-codeword", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "here", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ":rax", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "mov-reg64-imm64", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, ":rax", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "push-reg64", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "pack-next", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "packalign", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "here", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; Allocates bytes on the heap by incrementing the global "here" pointer.
|
|
; The "here" pointer is kept aligned to an 8-byte boundary, regardless of
|
|
; the size requested.
|
|
;
|
|
; This does not create dictionary entries, it's just a raw memory
|
|
; interface. It's suitable for allocating data or scratch space.
|
|
;
|
|
; In:
|
|
; size in bytes
|
|
; Out:
|
|
; pointer to start
|
|
dq litstring, "allocate", 0, early_create, early_docol_codeword
|
|
dq litstring, "here", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
; (size, here value, here value)
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "packalign", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "here", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; Takes a string pointer which must be equal to the current value of
|
|
; "here", ; indicating it is in the temporary allocation space, and
|
|
; allocates it permanently by advancing "here" to the next aligned address
|
|
; after it.
|
|
;
|
|
; In:
|
|
; string pointer
|
|
; Out:
|
|
; string pointer
|
|
dq litstring, "allocate-string", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "stringlen", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "packalign", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "here", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; In:
|
|
; pointer to buffer metadata
|
|
; Out:
|
|
; pointer to buffer "physical-start" field
|
|
dq litstring, "buffer-physical-start", early_create, early_docol_codeword
|
|
; The physical-start field happens to be the first thing in the metadata, so
|
|
; this is an nop, but it still exists as a word because having it reduces
|
|
; confusion.
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; In:
|
|
; pointer to buffer metadata
|
|
; Out:
|
|
; pointer to buffer "physical-length" field
|
|
dq litstring, "buffer-physical-length", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; In:
|
|
; pointer to buffer metadata
|
|
; Out:
|
|
; pointer to buffer "logical-start" field
|
|
dq litstring, "buffer-logical-start", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2*8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; In:
|
|
; pointer to buffer metadata
|
|
; Out:
|
|
; pointer to buffer "logical-length" field
|
|
dq litstring, "buffer-logical-length", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3*8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; In:
|
|
; pointer to input buffer metadata
|
|
; Out:
|
|
; pointer to input buffer "refill" field
|
|
dq litstring, "input-buffer-refill", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4*8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; In:
|
|
; pointer to input buffer metadata
|
|
; Out:
|
|
; pointer to input buffer "next-source" field
|
|
dq litstring, "input-buffer-next-source", 0, early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; Given an initialized buffer (input or otherwise), sets its logical-start
|
|
; and logical-length fields to indicate the buffer is empty. This relies on
|
|
; the buffer having a backing store attached, but does not alter the backing
|
|
; store or its contents.
|
|
;
|
|
; In:
|
|
; pointer to buffer metadata
|
|
dq litstring, "clear-buffer", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-physical-start", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
; (address of backing store, metadata pointer)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
; (metadata pointer, address of backing store, metadata pointer)
|
|
dq litstring, "buffer-logical-start", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-logical-length", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; Sets all fields in an input buffer metadata structure to zero,
|
|
; effectively detaching and leaking any backing store that had been attached
|
|
; to it. Suitable for use during initialization.
|
|
;
|
|
; In:
|
|
; pointer to input buffer metadata
|
|
dq litstring, "zero-input-buffer-metadata", early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-physical-start", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-physical-length", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-logical-start", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-logical-length", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "input-buffer-refill", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
; Notice the absence of a dup this time.
|
|
dq litstring, "input-buffer-next-source", 0, early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; Allocates buffer metadata, with no backing store attached. Initializes
|
|
; the metadata to all zeroes.
|
|
;
|
|
; Out:
|
|
; pointer to buffer metadata
|
|
dq litstring, "allocate-input-buffer-metadata", early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6*8, early_comma
|
|
dq litstring, "allocate", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "zero-input-buffer-metadata", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; Allocates input buffer metadata and a backing store, in one operation.
|
|
; Points the metadata to the backing store.
|
|
;
|
|
; In:
|
|
; buffer capacity in bytes
|
|
; Out:
|
|
; pointer to buffer metadata
|
|
dq litstring, "allocate-input-buffer", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6*8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "allocate", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "zero-input-buffer-metadata", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
; (capacity in bytes, metadata pointer)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6*8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
; (capacity in bytes, metadata pointer, metadata pointer, physical start)
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-physical-start", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
; (capacity in bytes, metadata pointer)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-physical-length", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
; (metadata pointer)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "clear-buffer", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; Sets the backing store of an input buffer to point at a null-teriminated
|
|
; string and read from it.
|
|
;
|
|
; In:
|
|
; pointer to buffer metadata
|
|
; pointer to string
|
|
dq litstring, "attach-string-to-input-buffer", early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
; (string pointer, metadata pointer)
|
|
dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-physical-start", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
; (string pointer, metadata pointer)
|
|
dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-logical-start", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
; (string pointer, metadata pointer)
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "stringlen", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
; (string length, metadata pointer)
|
|
dq litstring, "2dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-physical-length", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
; (string length, metadata pointer)
|
|
dq litstring, "buffer-logical-length", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
;;; Here we have some imperative code that runs immediately, to initialize
|
|
;;; some runtime data structures.
|
|
|
|
; First, we insert a metadata word header to delimit the space. Otherwise
|
|
; "describe" would crash when attempting to describe
|
|
; "attach-string-to-input-buffer".
|
|
; (heap pointer)
|
|
dq litstring, "main-input-buffer-metadata", early_create
|
|
dq litstring, "main-input-buffer-metadata", early_find
|
|
dq lit, 1, store_entry_flags
|
|
|
|
; Having done that, now we do the runtime allocation.
|
|
; (heap pointer)
|
|
dq litstring, "allocate-input-buffer-metadata", early_find
|
|
dq entry_to_execution_token, execute
|
|
|
|
; We also initialize the metadata here, pointing it to the boot source as
|
|
; its backing store. We could do that later, but it's convenient to do it
|
|
; here.
|
|
; (heap pointer, metadata pointer)
|
|
dq swap, litstring, "attach-string-to-input-buffer", early_find
|
|
; (metadata pointer, heap pointer, entry pointer)
|
|
dq entry_to_execution_token, swap, unroll3
|
|
; (heap pointer, metadata pointer, execution token)
|
|
dq swap, dup, unroll3
|
|
; (heap pointer, metadata pointer, execution token, metadata pointer)
|
|
dq lit, boot_source, roll3
|
|
; (heap pointer, metadata pointer, metadata pointer, string pointer,
|
|
; execution token)
|
|
dq execute
|
|
|
|
; Finally, we define the named variable "main-input-buffer" so we can find
|
|
; it again.
|
|
; (heap pointer, metadata pointer)
|
|
dq swap, litstring, "variable", 0, early_find, entry_to_execution_token
|
|
; (metadata pointer, heap pointer, execution token)
|
|
dq swap, unroll3
|
|
; (heap pointer, metadata pointer, execution token)
|
|
dq litstring, "main-input-buffer", swap
|
|
; (heap pointer, metadata pointer, string pointer, execution token)
|
|
dq execute
|
|
|
|
|
|
; (metadata pointer)
|
|
dq litstring, "consume-from", early_create, early_docol_codeword
|
|
|
|
; If the length is zero, exit without doing anything.
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-logical-length", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2*8, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; Decrement the logical length. We do this now to get it over with, since
|
|
; adjusting the start pointer is more complex.
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-logical-length", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
; (metadata pointer)
|
|
|
|
; We compute the physical end. We'll need it in adjusting the logical start,
|
|
; and doing it now means less stack juggling later.
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-physical-start", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-physical-length", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
; (physical end, metadata pointer)
|
|
|
|
; Compute the incremented logical start.
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-logical-start", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
; (physical end, metadata pointer, updated start pointer)
|
|
|
|
; Check whether the updated start is equal to the physical end.
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
; (metadata pointer, updated start, updated start, physical end)
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
|
|
; If the logical start pointer is now equal to the physical end pointer,
|
|
; we want to wrap to the physical start. That's what makes it a circular
|
|
; buffer.
|
|
; (metadata pointer, updated start)
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-physical-start", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
|
|
; However we got here, save the updated logical start pointer.
|
|
; (metadata pointer, updated start)
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-logical-start", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
; (metadata pointer)
|
|
dq litstring, "peek-from", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-logical-length", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 28*8, early_comma
|
|
|
|
; If the length is zero, there is no input, but we can still try calling
|
|
; the "refill" word.
|
|
; (metadata pointer)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "input-buffer-refill", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 17*8, early_comma
|
|
|
|
; If the refill word is nonzero, call it. It expects a copy of the metadata
|
|
; pointer as its parameter, so set that up.
|
|
; (metadata pointer, refill word)
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "execute", early_find, entry_to_execution_token, early_comma
|
|
; (metadata pointer)
|
|
; Now we check if the length is still zero.
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "buffer-logical-length", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10*8, early_comma
|
|
|
|
; The length is zero even after calling the refill word, so return null.
|
|
; (metadata pointer)
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; If the refill word is zero, we can't help, just return null.
|
|
; (metadata pointer, refill word)
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; The buffer is non-empty, so read a byte from it. We might have reached
|
|
; this point either from the original check, or from the second check after
|
|
; calling the refill word.
|
|
;
|
|
; While it might be more extensible to call an "unpack" word here, such as
|
|
; unpack8, we actually just want to get the value, and delegate the pointer
|
|
; adjustments to "consume".
|
|
;
|
|
; (metadata pointer)
|
|
dq litstring, "buffer-logical-start", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "8@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
; (metadata pointer)
|
|
dq litstring, "key-from", 0, early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "peek-from", early_find, entry_to_execution_token, early_comma
|
|
; (metadata pointer, result byte)
|
|
; We unconditionally consume, because we have no way to distinguish between
|
|
; reading a zero byte and having nothing left to read.
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "consume-from", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
dq litstring, "is-space", 0, early_create, early_docol_codeword
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x20, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x09, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0a, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0b, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0c, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0d, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
dq litstring, "peek", early_create, early_docol_codeword
|
|
dq litstring, "main-input-buffer", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "peek-from", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "consume", early_create, early_docol_codeword
|
|
dq litstring, "main-input-buffer", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "consume-from", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "key", early_create, early_docol_codeword
|
|
dq litstring, "main-input-buffer", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "key-from", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
;;; As a convenience for "word", we have some facilities for working with
|
|
;;; stack-allocated strings. Yeah, trippy concept. Also, it would be a
|
|
;;; buffer overrun hazard if we were worried about that, which is why this
|
|
;;; is no longer common practice in C.
|
|
;;;
|
|
;;; The most important of these is accumulate-string, but we need some
|
|
;;; smaller pieces first.
|
|
|
|
; In:
|
|
; (multiple words) string
|
|
; (multiple words) items to be left alone
|
|
; item to be unrolled
|
|
; number of items above string that participate in the unroll
|
|
; Out:
|
|
; item that was unrolled
|
|
; (multiple words) string
|
|
; (multiple words) items left alone
|
|
dq litstring, "unroll-past-string", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
; (string, other items, top item, byte offset to string start)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "value@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
; We have two copies of the offset present, in addition to the stuff we want
|
|
; to rotate. So, the actual string starts two words on... We could have
|
|
; adjusted the offset instead, but we'll want the unmodified offset again
|
|
; later.
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 16, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
; (string, other items, top item, offset to start, string pointer)
|
|
dq litstring, "stringlen", early_find, entry_to_execution_token, early_comma
|
|
; Same reasoning as in accumulate-string (see below).
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "align-size", early_find, entry_to_execution_token, early_comma
|
|
; (string, other items, top item, offset to start, string length w/ padding)
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "/%", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
; (string, other items, top item, number of words to unroll)
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; In:
|
|
; (multiple words) string
|
|
; item to be swapped
|
|
; Out:
|
|
; item that was swapped
|
|
; (multiple words) string
|
|
dq litstring, "swap-past-string", 0, early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "unroll-past-string", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; In:
|
|
; (multiple words) string
|
|
dq litstring, "dropstring", early_create, early_docol_codeword
|
|
dq litstring, "value@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "stringlen", early_find, entry_to_execution_token, early_comma
|
|
; Same reasoning as in accumulate-string (see below).
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "align-size", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "value@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
; At the time we fetched the stack pointer, there was an extra value atop
|
|
; it, so we have to add one more word.
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "value!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; In:
|
|
; (multiple words) string
|
|
; item to be kept
|
|
; Out:
|
|
; item that was kept
|
|
dq litstring, "dropstring-with-result", early_create, early_docol_codeword
|
|
dq litstring, "swap-past-string", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "dropstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; In:
|
|
; (multiple words) string-so-far
|
|
; new character byte
|
|
; Out:
|
|
; (multiple words) updated string-so-far
|
|
dq litstring, "accumulate-string", early_create
|
|
dq early_docol_codeword
|
|
|
|
; Compute the address of the final word of the string.
|
|
;
|
|
; It's a little bit difficult to get the start pointer right, since all
|
|
; our intermediate products affect what we get from value@, so we compute
|
|
; that just once, here at the beginning.
|
|
dq litstring, "value@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
; (string so far, new character byte, pointer to start of string)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "stringlen", early_find, entry_to_execution_token, early_comma
|
|
; There are two concerns here that overlap: First, we always want at least
|
|
; one word. Recall that a length of zero bytes won't receive any alignment
|
|
; padding because it's already divisible by 8. Second, the result of
|
|
; stringlen doesn't include the null byte, which might be in a word by
|
|
; itself that needs to be counted. We can address both of them by
|
|
; unconditionally adding 1 to the length before applying alignment.
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
; Pad the length for alignment.
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "align-size", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
; We want an offset from the first word of the string to the last word of
|
|
; the string, so we subtract one word from the length.
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
; (string so far, new character byte, address of final word)
|
|
|
|
; Examine the final word of the string, leaving other stuff undisturbed.
|
|
; Work low-to-high to figure out where to store the new byte, taking the
|
|
; first one that's available.
|
|
; (string so far, new character byte, address of final word)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x00000000000000FF, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6*8, early_comma
|
|
; (string so far, new character byte, address of final word, old value)
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
; (string so far, new character byte, address of final word, old value)
|
|
|
|
; This next part is repeated several times, changing only the offsets, for
|
|
; bytes 1 through 6; bytes 0 (above) and 7 (way below) are different.
|
|
; (string so far, new character byte, address of final word, old value)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x000000000000FF00, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 9*8, early_comma
|
|
; (string so far, new character byte, address of final word, old value)
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0000000000000100, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; Highly repetitive code, see above.
|
|
; (string so far, new character byte, address of final word, old value)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0000000000FF0000, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 9*8, early_comma
|
|
; (string so far, new character byte, address of final word, old value)
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0000000000010000, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; Highly repetitive code, see above.
|
|
; (string so far, new character byte, address of final word, old value)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x00000000FF000000, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 9*8, early_comma
|
|
; (string so far, new character byte, address of final word, old value)
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0000000001000000, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; Highly repetitive code, see above.
|
|
; (string so far, new character byte, address of final word, old value)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x000000FF00000000, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 9*8, early_comma
|
|
; (string so far, new character byte, address of final word, old value)
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0000000100000000, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; Highly repetitive code, see above.
|
|
; (string so far, new character byte, address of final word, old value)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0000FF0000000000, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 9*8, early_comma
|
|
; (string so far, new character byte, address of final word, old value)
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0000010000000000, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; Highly repetitive code, see above.
|
|
; (string so far, new character byte, address of final word, old value)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x00FF000000000000, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 9*8, early_comma
|
|
; (string so far, new character byte, address of final word, old value)
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0001000000000000, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; The top byte of the final word is always zero (or else stringlen
|
|
; wouldn't have called it the final word), so we don't need to check it, we
|
|
; can just use it.
|
|
;
|
|
; We need to put the new value in the top byte, which will mean we have no
|
|
; null terminator, so we also need to start a new word.
|
|
;
|
|
; There is a fiddly order-dependency here: unroll-past-string relies on
|
|
; being able to find the null terminator, which won't work if we've gotten
|
|
; rid of it. Also, calling it will move all the earlier words, including
|
|
; the one we intend to write to, which will invalidate any pointer we're
|
|
; keeping at that point. There's a few ways to resolve this; what we do is
|
|
; put the new terminator in place first, manually nudge the pointer, and
|
|
; then write the new value.
|
|
; (string so far, new character byte, address of final word, old value)
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x0100000000000000, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
; (string so far, new value, address of final word)
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3, early_comma
|
|
dq litstring, "unroll-past-string", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
; (new null terminator, string so far, new value, invalid address)
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
; (new null terminator, string so far, new value, updated address)
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
; (updated string)
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
; Okay, this is the big one, the lexer! Wow.
|
|
;
|
|
; Out:
|
|
; (multiple words) string
|
|
dq litstring, "word", early_create, early_docol_codeword
|
|
|
|
; We allocate an empty string first, so that the result of "key" will
|
|
; conveniently be on the easy-to-find end of it.
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
|
|
; Skip whitespace.
|
|
dq litstring, "key", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "is-space", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -7*8, early_comma
|
|
|
|
; Early exit if it's a zero byte.
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dropstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "accumulate-string", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
|
|
dq litstring, "peek", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "is-space", 0, early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8*8, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
dq litstring, "consume", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "accumulate-string", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -14*8, early_comma
|
|
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
dq litstring, "find", early_create, early_docol_codeword
|
|
dq litstring, "latest", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "find-in", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
; In:
|
|
; character
|
|
; Out:
|
|
; 1 for true, 0 for false
|
|
dq litstring, "is-alphanumeric", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "0", early_comma
|
|
dq litstring, ">", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
|
|
; Less than "0".
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "9", early_comma
|
|
dq litstring, ">=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
|
|
; Less than or equal to "9".
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "A", early_comma
|
|
dq litstring, ">", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
|
|
; Less than "A".
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "Z", early_comma
|
|
dq litstring, ">=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
|
|
; Less than or equal to "Z".
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "a", early_comma
|
|
dq litstring, ">", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
|
|
; Less than "a".
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "z", early_comma
|
|
dq litstring, ">=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5*8, early_comma
|
|
|
|
; Less than or equal to "z".
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; Greater than "z".
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
; In:
|
|
; character
|
|
; Out:
|
|
; value
|
|
dq litstring, "generalized-digit-value", early_create, early_docol_codeword
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "a", early_comma
|
|
dq litstring, "<=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8*8, early_comma
|
|
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "a", early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "A", early_comma
|
|
dq litstring, "<=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8*8, early_comma
|
|
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "A", early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "0", early_comma
|
|
dq litstring, "-", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
; In:
|
|
; character
|
|
; base
|
|
; Out:
|
|
; value (if successful)
|
|
; error indicator (zero indicates success)
|
|
dq litstring, "decode-generalized-digit", 0, early_create
|
|
dq early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "is-alphanumeric", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 14*8, early_comma
|
|
|
|
; It's alphanumeric.
|
|
; (base, character)
|
|
dq litstring, "generalized-digit-value", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
; (base, value)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
; (value, value, base)
|
|
dq litstring, ">", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4*8, early_comma
|
|
|
|
; It's in range.
|
|
; (value)
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; It's out of range.
|
|
; (value)
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; It's not alphanumeric.
|
|
; (base, character)
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
; In:
|
|
; string pointer
|
|
; base
|
|
; Out:
|
|
; result (if successful)
|
|
; error indicator (zero indicates success)
|
|
dq litstring, "read-base-unsigned", early_create, early_docol_codeword
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
|
|
; If the first byte is null, this is an error
|
|
dq litstring, "unpack8", early_find, entry_to_execution_token, early_comma
|
|
; (numeric base, current point in string, character)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 7*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; Decode the first byte as a generalized digit in the base.
|
|
; (numeric base, current point in string, character)
|
|
; If the first byte is less than "0", this is an error.
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
; (numeric base, current point in string, character, numeric base)
|
|
dq litstring, "decode-generalized-digit", 0, early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6*8, early_comma
|
|
|
|
; (numeric base, current point in string)
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; The first byte is a valid generalized digit in the appropriate base, so
|
|
; let's get started.
|
|
; (numeric base, current point in string, initial value)
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
|
|
; Start of the loop.
|
|
; (numeric base, result so far, current point in string)
|
|
dq litstring, "unpack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8*8, early_comma
|
|
|
|
; A null after the first character is valid, and indicates we're done.
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; Decode the latest byte as a generalized digit in the base.
|
|
; (numeric base, result so far, current point in string, latest byte)
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
; (numeric base, result so far, current point in string, character
|
|
; numeric base)
|
|
dq litstring, "decode-generalized-digit", 0, early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 7*8, early_comma
|
|
|
|
; If the latest character is not a valid digit, that's an error.
|
|
; (numeric base, result so far, current point in string)
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; The latest character is valid, so incorporate it and loop.
|
|
; (numeric base, result so far, current point in string, latest value)
|
|
dq litstring, "3roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4, early_comma
|
|
dq litstring, "roll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 5, early_comma
|
|
dq litstring, "unroll", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -42*8, early_comma
|
|
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
; In:
|
|
; string pointer
|
|
; Out:
|
|
; result (if successful)
|
|
; error indicator (zero indicates success)
|
|
dq litstring, "read-integer-unsigned", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "unpack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "0", early_comma
|
|
dq litstring, "!=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6*8, early_comma
|
|
|
|
; This is the case where the leading digit is not a zero.
|
|
; (original string pointer, advanced string pointer)
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10, early_comma
|
|
dq litstring, "read-base-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; This is the case where the leading digit is a zero.
|
|
; (original string pointer, advanced string pointer)
|
|
dq litstring, "unpack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "x", early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8*8, early_comma
|
|
|
|
; This is the case where the second character is equal to "x".
|
|
; (original string pointer, doubly advanced string pointer, character)
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 16, early_comma
|
|
dq litstring, "read-base-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "o", early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8*8, early_comma
|
|
|
|
; This is the case where the second character is equal to "o".
|
|
; (original string pointer, doubly advanced string pointer, character)
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "read-base-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "b", early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8*8, early_comma
|
|
|
|
; This is the case where the second character is equal to "b".
|
|
; (original string pointer, doubly advanced string pointer, character)
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2, early_comma
|
|
dq litstring, "read-base-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; This is the case where the second character is something else.
|
|
; (original string pointer, doubly advanced string pointer, character)
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10, early_comma
|
|
dq litstring, "read-base-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
|
|
; In:
|
|
; string pointer
|
|
; Out:
|
|
; result (if successful)
|
|
; error indicator (zero indicates success)
|
|
dq litstring, "read-integer", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "unpack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "-", early_comma
|
|
dq litstring, "!=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4*8, early_comma
|
|
|
|
; This is the case where it's non-negative.
|
|
; (original string pointer, advanced string pointer)
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "read-integer-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; This is the case where it's negative.
|
|
; (original string pointer, advanced string pointer)
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "read-integer-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
; (result maybe, exit code)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2*8, early_comma
|
|
|
|
; Failure
|
|
; (non-zero exit code)
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; Success
|
|
; (result, zero exit code)
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -1, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
; In:
|
|
; string pointer
|
|
; Out:
|
|
; result (if successful)
|
|
; error indicator (zero indicates success)
|
|
dq litstring, "read-decimal", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "unpack8", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "-", early_comma
|
|
dq litstring, "!=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 6*8, early_comma
|
|
|
|
; This is the case where it's non-negative.
|
|
; (original string pointer, advanced string pointer)
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10, early_comma
|
|
dq litstring, "read-base-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; This is the case where it's negative.
|
|
; (original string pointer, advanced string pointer)
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 10, early_comma
|
|
dq litstring, "read-base-unsigned", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
; (result maybe, exit code)
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 2*8, early_comma
|
|
|
|
; Failure
|
|
; (non-zero exit code)
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; Success
|
|
; (result, zero exit code)
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, -1, early_comma
|
|
dq litstring, "*", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
dq litstring, "interpreter-flags-storage", early_create
|
|
dq litstring, "interpreter-flags-storage", early_find
|
|
dq dup, lit, 1, store_entry_flags
|
|
dq entry_to_execution_token
|
|
; (heap pointer, storage pointer)
|
|
dq swap, lit, 0, early_comma
|
|
dq litstring, "variable", 0, early_find, entry_to_execution_token
|
|
; (storage pointer, heap pointer, execution token)
|
|
dq swap, unroll3
|
|
; (heap pointer, storage pointer, execution token)
|
|
dq litstring, "interpreter-flags", swap
|
|
; (heap pointer, storage pointer, string pointer, execution token)
|
|
dq execute
|
|
|
|
|
|
dq litstring, "hide-entry", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "entry-flags@", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x80, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "entry-flags!", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
dq litstring, "unhide-entry", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "entry-flags@", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x80, early_comma
|
|
dq litstring, "invert", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "entry-flags!", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
dq litstring, "set-word-immediate", early_create, early_docol_codeword
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "entry-flags@", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x01, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "entry-flags!", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
dq litstring, "[", early_create, early_docol_codeword
|
|
dq litstring, "interpreter-flags", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x01, early_comma
|
|
dq litstring, "invert", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "interpreter-flags", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; Run some imperative code to fix the flags.
|
|
dq litstring, "set-word-immediate", early_find, entry_to_execution_token
|
|
dq swap, litstring, "[", early_find, roll3, execute
|
|
|
|
|
|
dq litstring, "]", early_create, early_docol_codeword
|
|
dq litstring, "interpreter-flags", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x01, early_comma
|
|
dq litstring, "|", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "interpreter-flags", early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
dq litstring, ":", early_create, early_docol_codeword
|
|
dq litstring, "word", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "value@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "create", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dropstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "docol", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ",", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "latest", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "hide-entry", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
; If this feels backwards, imagine to yourself that everything that ISN'T
|
|
; defining a word body is part of an implicit [ ... ] sequence. Doing so
|
|
; doesn't really change anything, but may make you happier.
|
|
dq litstring, "]", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
dq litstring, ";", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ",", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "latest", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "unhide-entry", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
; As above.
|
|
dq litstring, "[", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
; Run some imperative code to fix the flags.
|
|
dq litstring, "set-word-immediate", early_find, entry_to_execution_token
|
|
dq swap, litstring, ";", early_find, roll3, execute
|
|
|
|
|
|
dq litstring, ";asm", early_create, early_docol_codeword
|
|
dq litstring, "here", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "pack-next", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "packalign", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "here", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "latest", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "unhide-entry", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "entry-to-execution-token", 0, early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 8, early_comma
|
|
dq litstring, "+", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "swap", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "!", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "[", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
dq litstring, "set-word-immediate", early_find, entry_to_execution_token
|
|
dq swap, litstring, ";asm", early_find, roll3, execute
|
|
|
|
|
|
; Although we will eventually define the word "'" to give us the symbol of a
|
|
; word, it will rely on being able to compile a literal. Rather than do
|
|
; lots of string processing later, we choose to define this word now to
|
|
; avoid having to look up the word "lit" as part of that.
|
|
;
|
|
; In:
|
|
; value
|
|
dq litstring, "literal", early_create, early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ",", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ",", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
; Now the single most important word...
|
|
dq litstring, "interpret", early_create, early_docol_codeword
|
|
dq litstring, "word", early_find, entry_to_execution_token, early_comma
|
|
|
|
; If no word was returned, exit.
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 3*8, early_comma
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; The string is on the top of the stack, so to get a pointer to it we get
|
|
; the stack address.
|
|
; (string)
|
|
dq litstring, "value@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "find", early_find, entry_to_execution_token, early_comma
|
|
|
|
; Check whether the word was found in the dictionary.
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "!=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 25*8, early_comma
|
|
|
|
; If the word is in the dictionary, check what mode we're in, then...
|
|
dq litstring, "dropstring-with-result", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
; (entry pointer)
|
|
dq litstring, "interpreter-flags", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x01, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 14*8, early_comma
|
|
|
|
; ... if we're in compile mode, there's still a chance it's an immediate
|
|
; word, in which case we branch over to interpret mode...
|
|
dq litstring, "dup", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "entry-flags@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 1, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 4*8, early_comma
|
|
; ... but it's a regular word, so append it to the heap.
|
|
dq litstring, "entry-to-execution-token", 0, early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, ",", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; ... if we're in interpret mode, or the word is immediate, run it.
|
|
dq litstring, "entry-to-execution-token", 0, early_find
|
|
dq entry_to_execution_token, early_comma
|
|
dq litstring, "execute", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; If it's not in the dictionary, check whether it's a decimal number.
|
|
dq litstring, "drop", early_find, entry_to_execution_token, early_comma
|
|
; As before, we get the stack address and use it as a string pointer.
|
|
; (string)
|
|
dq litstring, "value@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "read-integer", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0, early_comma
|
|
dq litstring, "=", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 16*8, early_comma
|
|
|
|
; It's a number.
|
|
dq litstring, "interpreter-flags", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 0x01, early_comma
|
|
dq litstring, "&", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "0branch", early_find, entry_to_execution_token, early_comma
|
|
dq lit, 7*8, early_comma
|
|
|
|
; We're in compile mode; append first "lit", then the number, to the heap.
|
|
; The version of "lit" we use is the one that's current when we ourselves
|
|
; are compiled, hardcoded; doing a dynamic lookup would require dealing with
|
|
; what happens if it's not found.
|
|
dq litstring, "dropstring-with-result", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ",", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, ",", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; We're in interpret mode; push the number to the stack. Or at least, that's
|
|
; what the code we're interpreting will see. Really it's already on the
|
|
; stack, just clean everything else up and leave it there.
|
|
dq litstring, "dropstring-with-result", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
|
|
; If it's neither in the dictionary nor a number, just print an error.
|
|
dq litstring, "litstring", early_find, entry_to_execution_token, early_comma
|
|
dq lit, "No such ", early_comma, lit, "word: ", early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "value@", early_find, entry_to_execution_token, early_comma
|
|
dq litstring, "emitstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "dropstring", early_find, entry_to_execution_token
|
|
dq early_comma
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
|
|
|
|
; The next layer is built now, so let's move on to it.
|
|
;
|
|
; We've chosen to defer creating "quit" until we're in interpreted mode,
|
|
; so we can't call "quit" here, we need to call "interpret". Since
|
|
; "interpret" doesn't loop, we need to call it a few times in a row - just
|
|
; enough times for the code in boot_source, which it'll be interpreting, to
|
|
; create and invoke "quit".
|
|
;
|
|
; We could allocate a real word that does that, but then it would stick
|
|
; around after it's no longer needed. Instead, we create a trampoline, which
|
|
; has a "docol" codeword, some calls to "interpret", but nothing else, then
|
|
; we call it the same way we would call an ordinary word given its execution
|
|
; token.
|
|
;
|
|
; To avoid needing to explicitly clean up the trampoline, we never
|
|
; formally allocate it. Since we know exactly what code it'll be running, we
|
|
; also know how much heap space that code will use. We put the trampoline
|
|
; immediately after the end of where "quit" will be, so that the very next
|
|
; heap allocations after creating "quit" will overwrite the trampoline.
|
|
;
|
|
; For simplicity's sake, we use the flatassembler copies of docol, lit,
|
|
; and sys_exit. It would be possible to use the heap copies, but we have
|
|
; these ones for just a few moments longer, so we might as well use them.
|
|
dq litstring, "interpret", early_find, entry_to_execution_token
|
|
dq swap, early_here, fetch
|
|
; (interpret, heap pointer, here pointer)
|
|
|
|
; Consult the definition of "quit" in boot_source and count how many words
|
|
; the compiled implementation of it will take up.
|
|
;
|
|
; That will include one for the next-entry pointer; one for the name and
|
|
; flags (it's short enough to fit, even with the null terminators); one for
|
|
; the codeword pointer to docol; one for each word that's explicitly added
|
|
; as part of its body in the source; and one for a trailing "exit" that's
|
|
; added by ";" and never reached.
|
|
;
|
|
; Whatever total you get, that's how many words to add to "here", on this
|
|
; line, to obtain the trampoline's start location.
|
|
;
|
|
; Notionally, less might appear to work, but you'd be racing to execute a
|
|
; word before overwriting it, so it isn't a great idea.
|
|
dq lit, 10*8, add
|
|
; (interpret, heap pointer, start of trampoline)
|
|
|
|
dq dup, lit, 4, roll, swap
|
|
; (heap pointer, start of trampoline, interpret, current point in trampoline)
|
|
dq lit, docol, pack64
|
|
|
|
; In boot_source, count how many interpreted words there are from the
|
|
; initial ":" to the invocation of "quit", inclusive. Don't forget that
|
|
; ": quit" is only a single interpreted word, because ":" reads a word to
|
|
; use as a name, and that one is never seen by "interpret".
|
|
;
|
|
; Whatever total you get, adjust the number of repeated lines just below,
|
|
; to put that exact number of copies of the execution token for "interpret"
|
|
; into the trampoline.
|
|
;
|
|
; (heap pointer, start of trampoline, interpret, current point in trampoline)
|
|
dq swap, dup, unroll3, pack64
|
|
dq swap, dup, unroll3, pack64
|
|
dq swap, dup, unroll3, pack64
|
|
dq swap, dup, unroll3, pack64
|
|
dq swap, dup, unroll3, pack64
|
|
dq swap, dup, unroll3, pack64
|
|
dq swap, dup, unroll3, pack64
|
|
dq swap, dup, unroll3, pack64
|
|
dq swap, dup, unroll3, pack64
|
|
dq swap, dup, unroll3, pack64
|
|
dq swap, dup, unroll3, pack64
|
|
dq swap, dup, unroll3, pack64
|
|
dq swap, dup, unroll3, pack64
|
|
dq swap, dup, unroll3, pack64
|
|
|
|
dq swap, drop
|
|
; (heap pointer, start of trampoline, current point in trampoline)
|
|
|
|
; The trampoline will never get past the above calls to "interpret", but if
|
|
; it does, complain.
|
|
dq lit, lit, pack64, lit, 1, pack64, lit, sys_exit, pack64
|
|
dq drop
|
|
; (heap pointer, start of trampoline)
|
|
|
|
; Get rid of that heap pointer on the stack, we're finally done with it!
|
|
dq swap, drop
|
|
dq execute
|
|
|
|
; We won't be coming back, but if we do, complain about that, too.
|
|
dq lit, 1, sys_exit
|
|
|
|
|
|
;;; For triage's sake, here's an inventory of everything else in the file.
|
|
;;;
|
|
;;; Macros:
|
|
;;; next, beforenext, pushcontrol, popcontrol
|
|
;;; Assembly:
|
|
;;; docol (the constant, and the actual codeword implementation)
|
|
;;; needs a label
|
|
;;; pushcontrol, next
|
|
;;; exit
|
|
;;; popcontrol, next
|
|
;;; swap, drop, drop2, roll, unroll, roll3, unroll3, dup, dup2
|
|
;;; add, sub, mul, divmod
|
|
;;; eq, ne, gt, lt, ge, le
|
|
;;; gt_unsigned, lt_unsigned, ge_unsigned, le_unsigned
|
|
;;; and, or, xor, invert
|
|
;;; lit, litstring
|
|
;;; store, fetch
|
|
;;; store_control_stack,fetch_control_stack,
|
|
;;; store_value_stack, fetch_value_stack,
|
|
;;; addstore, substore, store8, fetch8, store16, fetch16, store32, fetch32
|
|
;;; memcopy, stringlen
|
|
;;; reverse_stringlen, reverse_padding_len
|
|
;;; stringcmp
|
|
;;; no dependencies except next for any of these
|
|
;;; branch, zbranch
|
|
;;; sorta needs a label but might be avoidable
|
|
;;; needs next
|
|
;;; execute
|
|
;;; sys_exit, sys_write
|
|
;;; nothing special
|
|
;;; Forth:
|
|
;;; emitstring
|
|
;;; stringlen, sys_write, basics
|
|
;;; pow logfloor logceil
|
|
;;; dotbase_unsigned, dotbase, dot
|
|
;;; dothex, dothex8, dothex16, dothex32, dothex64
|
|
;;; Assembly:
|
|
;;; crash
|
|
;;; nothing special
|
|
;;; Forth:
|
|
;;; pack64, pack32, pack16, pack8, packstring, packalign
|
|
;;; only the basics above
|
|
;;; Assembly:
|
|
;;; litpack64, litpack32, litpack16, litpack8
|
|
;;; beforenext, pack*
|
|
;;; Forth:
|
|
;;; rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi
|
|
;;; r8, r9, r10, r11, r12, r13, r14, r15
|
|
;;; eax, ecx, edx, ebx, esp, ebp, esi, edi
|
|
;;; ax, cx, dx, bx, sp, bp, si, di
|
|
;;; al, cl, dl, bl, ah, ch, dh, bh
|
|
;;; cc_overflow, cc_no_overflow, cc_below, cc_above_equal, cc_equal,
|
|
;;; cc_not_equal, cc_below_equal, cc_above, cc_sign, cc_not_sign, cc_even,
|
|
;;; cc_odd, cc_less, cc_greater_equal, cc_less_equal, cc_greater
|
|
;;; only the basics above
|
|
;;; reg64, extrareg64, reg32, reg16, reg8, scalefield, conditioncode
|
|
;;; only the basics plus optional emitstring and sys_exit
|
|
;;; (notice that these are forward references!)
|
|
;;; rex_w, rex_wb, opcodereg, opcodecc, modrm, sib
|
|
;;; only the basics above
|
|
;;; addressing_reg64, addressing_indirect_reg64, addressing_disp8_reg64,
|
|
;;; addressing_indexed_reg64, addressing_disp8_indexed_reg64,
|
|
;;; addressing_reg8
|
|
;;; basics plus earlier assembly stuff
|
|
;;; cld, std,
|
|
;;; mov_reg64_imm32,
|
|
;;; mov_reg64_imm64, mov_extrareg64_imm64,
|
|
;;; mov_reg64_reg64,
|
|
;;; mov_indirect_reg64_reg64, mov_disp8_reg64_reg64,
|
|
;;; mov_reg64_indirect_reg64, mov_reg64_disp8_reg64,
|
|
;;; mov_reg64_indexed_reg64, mov_indexed_reg64_reg64,
|
|
;;; mov_indirect_reg64_reg32, mov_disp8_reg64_reg32,
|
|
;;; mov_reg32_indirect_reg64, mov_reg32_disp8_reg64,
|
|
;;; mov_indirect_reg64_reg16, mov_disp8_reg64_reg16,
|
|
;;; mov_reg16_indirect_reg64, mov_reg16_disp8_reg64,
|
|
;;; mov_indirect_reg64_reg8, mov_disp8_reg64_reg8,
|
|
;;; mov_reg8_indirect_reg64, mov_reg8_disp8_reg64,
|
|
;;; mov_reg8_reg8,
|
|
;;; lea_reg64_disp8_reg64, lea_reg64_indexed_reg64,
|
|
;;; lea_reg64_disp8_indexed_reg64,
|
|
;;; push_reg64, pop_reg64, push_imm32_extended,
|
|
;;; movs8, movs16, movs32, movs64,
|
|
;;; rep_movs8, rep_movs16, rep_movs32, rep_movs64,
|
|
;;; lods8, lods16, lods32, lods64,
|
|
;;; rep_lods8, rep_lods16, rep_lods32, rep_lods64,
|
|
;;; stos8, stos16, stos32, stos64,
|
|
;;; rep_stos8, rep_stos16, rep_stos32, rep_stos64,
|
|
;;; cmps8, cmps16, cmps32, cmps64,
|
|
;;; repz_cmps8, repz_cmps16, repz_cmps32, repz_cmps64,
|
|
;;; repnz_cmps8, repnz_cmps16, repnz_cmps32, repnz_cmps64,
|
|
;;; scas8, scas16, scas32, scas64,
|
|
;;; repz_scas8, repz_scas16, repz_scas32, repz_scas64,
|
|
;;; repnz_scas8, repnz_scas16, repnz_scas32, repnz_scas64,
|
|
;;; add_reg64_reg64, add_indirect_reg64_reg64, add_reg64_indirect_reg64,
|
|
;;; add_reg64_imm8,
|
|
;;; sub_reg64_reg64, sub_indirect_reg64_reg64,
|
|
;;; sub_reg64_imm8, sbb_reg64_imm8
|
|
;;; mul_reg64, divmod_reg64, idivmod_reg64, inc_reg64, dec_reg64,
|
|
;;; and_reg64_reg64, and_reg64_imm8,
|
|
;;; or_reg64_reg64, or_reg64_imm8,
|
|
;;; xox_reg64_reg64,
|
|
;;; not_reg64,
|
|
;;; cmp_reg64_reg64, test_reg64_reg64,
|
|
;;; set_reg8_cc, jmp_cc_rel_imm8, jmp_cc_rel_im32,
|
|
;;; jmp_abs_indirect_reg64, jmp_rel_imm8, jmp_rel_imm32,
|
|
;;; syscall, hlt
|
|
;;; basics plus assembly helpers
|
|
;;; pack_next, pack_beforenext, pack_pushcontrol, pack_popcontrol,
|
|
;;; basics, assembly stuff
|
|
;;; entry_to_execution_token, execution_token_to_entry,
|
|
;;; fetch_entry_flags, store_entry_flags,
|
|
;;; entry_to_name,
|
|
;;; find_in, next_newer_entry_in, guess_entry_end_in,
|
|
;;; show_hex_between, show_source_between, show_source_or_hex_between,
|
|
;;; some interdependencies here but it's all topologically sorted
|
|
;;; Forth, not needed on heap:
|
|
;;; early_heap, early_s0, early_r0, early_latest, early_here
|
|
;;; early_find, early_next_newer_entry, early_guess_entry_end,
|
|
;;; early_show_hex, early_show_source, early_show_source_or_hex
|
|
;;; early_describe, early_describe_all,
|
|
;;; TODO there should really be non-early versions of these two
|
|
;;; early_create, early_comma, early_self_codeword, early_docol_codeword,
|
|
;;; early_here_store, early_variable
|
|
;;;
|
|
;;; It's likely that nothing past this point is required for the heap copy,
|
|
;;; but it's here for completeness.
|
|
;;;
|
|
;;; Forth, subject to reconsideration:
|
|
;;; quit
|
|
;;; quine (this is a forward reference)
|
|
;;; Forth:
|
|
;;; quine
|
|
;;; early_here (removable), all_contents (forward)
|
|
;;; sys_write, basics
|
|
;;; use_label, set_label
|
|
;;; only basics
|
|
;;; Forth:
|
|
;;; all_contents, elf_file_header, elf_program_header
|
|
;;; output_start_routine
|
|
;;; nothing special in any of these (they do want use/set_label)
|
|
;;; self_raw
|
|
;;; self-reference
|
|
;;; Not a real word:
|
|
;;; end_segment
|
|
;;;
|
|
dq quit
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;; Now we are in Forth ;;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; Everything we define from here on out is an actual Forth word, with a
|
|
;;; proper header and everything. So, you'll see some more preamble before the
|
|
;;; definitions.
|
|
;;;
|
|
;;; Keep in mind, though, that, although we have threaded execution, we
|
|
;;; don't yet have Forth-style variables. That's because the heap is at a
|
|
;;; dynamically-chosen location, so none of this read-only code that we're
|
|
;;; defining now can reference it. Before invoking cold_start, we thoughtfully
|
|
;;; put the value of "heap" on the stack for ourselves; our first task will be
|
|
;;; to dynamically allocate some words on the heap that know how to find the
|
|
;;; heap. We'll do that by defining bootstrapping versions of the
|
|
;;; word-defining words, which will eventually be replaced.
|
|
|
|
; Token pasting is possible in flatassembler, but kind of a pain.
|
|
calminstruction defword_label_helper name
|
|
local full_name, address
|
|
arrange full_name, name#=_name ; do the token-pasting
|
|
compute address, $ ; compute the current address
|
|
publish full_name:, address ; bind the label
|
|
end calminstruction
|
|
|
|
; The only time we actually use this variant is docol.
|
|
macro defword_unlabeled name, flags
|
|
align 8
|
|
defword_label_helper name
|
|
dq latest_word
|
|
latest_word = $ - 8
|
|
db flags, 0x00, `name, 0x00
|
|
align 8
|
|
end macro
|
|
|
|
; This is the variant we use to define ordinary words.
|
|
macro defword name, flags
|
|
defword_unlabeled name, flags
|
|
label name
|
|
end macro
|
|
|
|
latest_word = 0
|
|
|
|
;;;
|
|
;;; 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
|
|
defword_unlabeled docol, 0
|
|
docol_constant:
|
|
; Evaluated as a word, docol is a constant which returns a pointer.
|
|
dq $ + 8
|
|
mov.qreg.qimm rax, docol
|
|
push.qreg rax
|
|
next
|
|
align 8
|
|
docol:
|
|
; 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.
|
|
pushcontrol rsi
|
|
add.qreg.bimm rax, 8
|
|
mov.qreg.qreg rsi, rax
|
|
next
|
|
|
|
latest_word = docol_name
|
|
|
|
;;;
|
|
;;; 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".
|
|
;;;
|
|
defword exit, 0
|
|
dq $ + 8
|
|
popcontrol rsi
|
|
next
|
|
|
|
|
|
;;;
|
|
;;; Stack manipulation routines
|
|
;;; ---------------------------
|
|
;;;
|
|
;;; We start with the three traditional stack operations, swap drop and
|
|
;;; roll. Sorry to fans of the name "ROT"; we were an HP calculator kid. It'll
|
|
;;; always be roll to us. Anyway, we do a couple other operations too. Since
|
|
;;; our goal right now is just to bootstrap the heap, we keep this short and
|
|
;;; sweet.
|
|
;;;
|
|
;;; There is definitely plenty of optimization that could be done.
|
|
;;;
|
|
|
|
defword swap, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
push.qreg rax
|
|
push.qreg rbx
|
|
next
|
|
|
|
defword drop, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
next
|
|
|
|
defword drop2, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rax
|
|
next
|
|
|
|
; Rotates "up" (pops its parameter, n; nth item then becomes current item).
|
|
;
|
|
; We implement this the high-performance way, with rep movsq, aka the
|
|
; instruction that exists to optimize C's memcpy(). The details of setting
|
|
; that up are complex; see below.
|
|
defword roll, 0
|
|
dq $ + 8
|
|
|
|
; Pop our parameter. The rep instruction takes rcx as its count, so we
|
|
; reduce copying by using it to hold our count, as well.
|
|
pop.qreg rcx
|
|
|
|
; We have n - 1 items to slide, so decrement rcx. For the purpose of
|
|
; counting how many repetitions will happen, it's one-based. This is because
|
|
; the rep instruction performs a single movsq, then decrements rcx, then
|
|
; stops if rcx is zero.
|
|
dec.qreg rcx
|
|
|
|
; Retrieve the nth item, for later. For this purpose we're thinking in
|
|
; zero-based terms, so we do this after already having decremented rcx.
|
|
mov.qreg.indexed.qreg rbx, rsp, rcx, 8
|
|
|
|
; The source address for movsq is rsi and the destination is rdi; we can
|
|
; use rdi as we wish, but rsi is our Forth "instruction pointer", so we must
|
|
; save and restore it. Doing so alters rsp, so we have to adjust the address
|
|
; calculations by eight bytes as compared to the expressions above, but
|
|
; happily we can use the disp8 field to do that. We'd be using disp8 anyway
|
|
; because it's helpful.
|
|
push.qreg rsi
|
|
|
|
; Now we set up parameters for the memory-sliding operation. We have
|
|
; n - 1 items to copy, moving the range rsp through rsp + (n-2)*8 onto the
|
|
; range rsp + 8 through rsp + (n-1)*8. That's with the value of rsp as it
|
|
; exists at this moment (it's going to change soon).
|
|
;
|
|
; We're sliding them upwards in memory, so we start at the high end so
|
|
; that we're always moving into a location that doesn't have anything
|
|
; precious. We use lea as a convenient way to do the stack math.
|
|
;
|
|
; When rcx is 1, we want rsp + 8.
|
|
lea.qreg.indexed.qreg rsi, rsp, rcx, 8
|
|
; When rcx is 1, we want rsp + 16.
|
|
lea.qreg.disp8.indexed.qreg rdi, 8, rsp, rcx, 8
|
|
;
|
|
; Using rcx = 1 is the most convenient example to use for figuring out the
|
|
; arithmetic. It's a linear relationship, so as long as we get the 8-byte
|
|
; stride correct, we just need to pick a single point and verify that our
|
|
; math is right for that point, and it'll be right for any value of rcx.
|
|
|
|
; Another of our Forth conventions is that the DF flag should be kept at
|
|
; zero, which directs string instruction to increment rsi. Here, however,
|
|
; because our source and destination ranges overlap, we need to start at the
|
|
; high end, which means we need it to decrement. So we set DF to one, and
|
|
; we'll clear it after.
|
|
std
|
|
rep movsq
|
|
|
|
; Set everything back.
|
|
cld
|
|
pop.qreg rsi
|
|
|
|
; There is now an extra item at the low end of the stack (the top) that
|
|
; needs to go away, and coincidentally we have a value in rbx that needs to
|
|
; be in that spot. Rather than doing a drop and push, we overwrite it, to
|
|
; save a little work.
|
|
mov.indirect.qreg.qreg rsp, rbx
|
|
|
|
; All done, wow! What a mouthful.
|
|
next
|
|
|
|
; Rotates "down" (pops its parameter, n; current item then becomes nth item).
|
|
;
|
|
; We implement this the high-performance way, with rep movsq, aka the
|
|
; instruction that exists to optimize C's memcpy(). The details of setting
|
|
; that up are complex; see below.
|
|
defword unroll, 0
|
|
dq $ + 8
|
|
|
|
; Pop our parameter. The rep instruction takes rcx as its count, so we
|
|
; reduce copying by using it to hold our count, as well.
|
|
pop.qreg rcx
|
|
|
|
; We have n - 1 items to slide, so decrement rcx. Also, save a copy of it in
|
|
; rdx after doing that, for later.
|
|
dec.qreg rcx
|
|
mov.qreg.qreg rdx, rcx
|
|
|
|
; Retrieve the 0th item, for later.
|
|
mov.qreg.indirect.qreg rbx, rsp
|
|
|
|
; Now we set up parameters for the memory-sliding operation. We have
|
|
; n - 1 items to copy, moving the range rsp + 8 through rsp + (n-1)*8 onto
|
|
; the range rsp through rsp + (n-2)*8. That's with the value of rsp as it
|
|
; exists at this moment (it's going to change soon).
|
|
;
|
|
; We're sliding them downwards in memory, so we start at the low end so
|
|
; that we're always moving into a location that doesn't have anything
|
|
; precious. We use lea as a convenient way to do the stack math.
|
|
;
|
|
; As with roll, we need to save rsi and adjust those rsp calculations
|
|
; accordingly.
|
|
push.qreg rsi
|
|
|
|
; Regardless of rcx, we want rsp + 16.
|
|
lea.qreg.disp8.qreg rsi, 16, rsp
|
|
; Regardless of rcx, we want rsp + 8.
|
|
lea.qreg.disp8.qreg rdi, 8, rsp
|
|
|
|
; With roll, we were starting at the high end. Here, we start at the low
|
|
; end, which means we need rsi to increment after each repetition. That's
|
|
; what it does when the DF flag is clear, and another of our Forth
|
|
; conventions is to keep it clear normally. So, we don't have to touch DF!
|
|
; Yay!
|
|
rep movsq
|
|
|
|
; Restore our original rsi.
|
|
pop.qreg rsi
|
|
|
|
; There is now an extra item in the middle of the stack, at the high end of
|
|
; the sliding we did, that needs to be overwritten with our value in rbx.
|
|
; Since we destructively updated our count in rcx, we saved a copy of the
|
|
; count in rdx, and we use that to find the right address.
|
|
;
|
|
; When the original count was n, we want rsp + (n-1)*8, so we saved rdx
|
|
; after decrementing rcx, above.
|
|
mov.indexed.qreg.qreg rsp, rdx, 8, rbx
|
|
|
|
; All done, wow! What a mouthful.
|
|
next
|
|
|
|
; Rotates "up" (third item becomes current item)
|
|
defword roll3, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
pop.qreg rcx
|
|
push.qreg rbx
|
|
push.qreg rax
|
|
push.qreg rcx
|
|
next
|
|
|
|
; Rotates "down" (current item becomes third item)
|
|
defword unroll3, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
pop.qreg rcx
|
|
push.qreg rax
|
|
push.qreg rcx
|
|
push.qreg rbx
|
|
next
|
|
|
|
defword dup, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
push.qreg rax
|
|
push.qreg rax
|
|
next
|
|
|
|
defword dup2, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
push.qreg rbx
|
|
push.qreg rax
|
|
push.qreg rbx
|
|
push.qreg rax
|
|
next
|
|
|
|
;;;
|
|
;;; Arithmetic routines
|
|
;;; -------------------
|
|
;;;
|
|
;;; No surprises here. Again, since our goal is to bootstrap the heap, we
|
|
;;; keep it short. Also again, this is nowhere near optimal.
|
|
;;;
|
|
|
|
defword add, 0
|
|
dq $ + 8
|
|
pop.qreg rbx
|
|
pop.qreg rax
|
|
add.qreg.qreg rax, rbx
|
|
push.qreg rax
|
|
next
|
|
|
|
defword sub, 0
|
|
dq $ + 8
|
|
pop.qreg rbx
|
|
pop.qreg rax
|
|
sub.qreg.qreg rax, rbx
|
|
push.qreg rax
|
|
next
|
|
|
|
defword mul, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
mul.rax.qreg rbx
|
|
push.qreg rax
|
|
next
|
|
|
|
defword divmod, 0
|
|
dq $ + 8
|
|
xor.qreg.qreg rdx, rdx ; rdx is the high bits of the input; zero it
|
|
pop.qreg rbx
|
|
pop.qreg rax
|
|
div.rdxrax.qreg rbx
|
|
push.qreg rdx ; remainder
|
|
push.qreg rax ; quotient
|
|
next
|
|
|
|
;;;
|
|
;;; Comparison routines
|
|
;;; -------------------
|
|
;;;
|
|
|
|
; So. This is subtle. These comparison routines all have the same structure.
|
|
; Notice that eq and ne are commutative, whereas the others are not, so
|
|
; consider gt as the archetypical one when reasoning about correctness. To
|
|
; test if A > B, we do cmp A, B, which sets the flags the same way as
|
|
; subtracting B from A does. The mnemonic names of the condition codes are
|
|
; based on the assumption you do it in this order.
|
|
;
|
|
; We want to treat the top of the stack as the first operand, so we carefully
|
|
; pop in the appropriate order.
|
|
;
|
|
; There are both signed and unsigned variants of the condition codes. We use
|
|
; the signed ones.
|
|
|
|
defword eq, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
cmp.qreg.qreg rax, rbx
|
|
set.breg.cc al, equal
|
|
and.qreg.bimm rax, 0x01
|
|
push.qreg rax
|
|
next
|
|
|
|
defword ne, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
cmp.qreg.qreg rax, rbx
|
|
set.breg.cc al, not_equal
|
|
and.qreg.bimm rax, 0x01
|
|
push.qreg rax
|
|
next
|
|
|
|
defword gt, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
cmp.qreg.qreg rax, rbx
|
|
set.breg.cc al, greater
|
|
and.qreg.bimm rax, 0x01
|
|
push.qreg rax
|
|
next
|
|
|
|
; Is the top of the stack less than the second item in the stack?
|
|
defword lt, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
cmp.qreg.qreg rax, rbx
|
|
set.breg.cc al, less
|
|
and.qreg.bimm rax, 0x01
|
|
push.qreg rax
|
|
next
|
|
|
|
defword ge, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
cmp.qreg.qreg rax, rbx
|
|
set.breg.cc al, greater_equal
|
|
and.qreg.bimm rax, 0x01
|
|
push.qreg rax
|
|
next
|
|
|
|
defword le, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
cmp.qreg.qreg rax, rbx
|
|
set.breg.cc al, less_equal
|
|
and.qreg.bimm rax, 0x01
|
|
push.qreg rax
|
|
next
|
|
|
|
defword gt_unsigned, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
cmp.qreg.qreg rax, rbx
|
|
set.breg.cc al, above
|
|
and.qreg.bimm rax, 0x01
|
|
push.qreg rax
|
|
next
|
|
|
|
defword lt_unsigned, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
cmp.qreg.qreg rax, rbx
|
|
set.breg.cc al, below
|
|
and.qreg.bimm rax, 0x01
|
|
push.qreg rax
|
|
next
|
|
|
|
defword ge_unsigned, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
cmp.qreg.qreg rax, rbx
|
|
set.breg.cc al, above_equal
|
|
and.qreg.bimm rax, 0x01
|
|
push.qreg rax
|
|
next
|
|
|
|
defword le_unsigned, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
pop.qreg rbx
|
|
cmp.qreg.qreg rax, rbx
|
|
set.breg.cc al, below_equal
|
|
and.qreg.bimm rax, 0x01
|
|
push.qreg rax
|
|
next
|
|
|
|
;;;
|
|
;;; Bitwise routines
|
|
;;; ----------------
|
|
;;;
|
|
|
|
defword and, 0
|
|
dq $ + 8
|
|
pop.qreg rbx
|
|
pop.qreg rax
|
|
and.qreg.qreg rax, rbx
|
|
push.qreg rax
|
|
next
|
|
|
|
defword or, 0
|
|
dq $ + 8
|
|
pop.qreg rbx
|
|
pop.qreg rax
|
|
or.qreg.qreg rax, rbx
|
|
push.qreg rax
|
|
next
|
|
|
|
defword xor, 0
|
|
dq $ + 8
|
|
pop.qreg rbx
|
|
pop.qreg rax
|
|
xor.qreg.qreg rax, rbx
|
|
push.qreg rax
|
|
next
|
|
|
|
; The HP overloads the name "not", so we follow the Forth convention.
|
|
defword invert, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
not.qreg rax
|
|
push.qreg rax
|
|
next
|
|
|
|
;;;
|
|
;;; Routine lit
|
|
;;; ------------
|
|
;;;
|
|
|
|
defword lit, 0
|
|
dq $ + 8
|
|
lodsq
|
|
push.qreg rax
|
|
next
|
|
|
|
defword litstring, 0
|
|
dq $ + 8
|
|
; The string immediately follows the codeword in memory, so rsi is already
|
|
; pointing to it. That address will be our returned result, so we push it to
|
|
; the stack.
|
|
push.qreg rsi
|
|
|
|
; Now we need to skip over the string, so that rsi will be valid for the
|
|
; next Forth word. To do that, we're going to do a string operation with
|
|
; scasb, which takes rdi as the address to look at. This means scasb is
|
|
; treating its operand as analogous to the destination operand of movs*.
|
|
mov.qreg.qreg rdi, rsi
|
|
; We want to compare for equality with zero; scasb looks in al for the other
|
|
; half of the comparison, so we clear rax.
|
|
xor.qreg.qreg rax, rax
|
|
; Counterintuitively, we do need to pass a count. We pass -1, which will
|
|
; always work.
|
|
xor.qreg.qreg rcx, rcx
|
|
not.qreg rcx
|
|
; The DF flag is zero per our Forth execution-model convention, which means
|
|
; scasb increments rdi after each iteration. This is what we want, so
|
|
; there's no need to mess with it.
|
|
;
|
|
; We also need to worry about ZF, but fortunately that "not" will make sure
|
|
; it's clear.
|
|
;
|
|
; So, we're ready; do it!
|
|
repnz scasb
|
|
; The scasb completes, incrementing rdi, before the repnz checks its
|
|
; condition. So, rdi is now pointing immediately after the terminating null
|
|
; byte. Of course, we want this in rsi for Forth's purposes.
|
|
mov.qreg.qreg rsi, rdi
|
|
|
|
; Finally, we need to align rsi to the next word boundary.
|
|
add.qreg.bimm rsi, 7
|
|
and.qreg.bimm rsi, NOT 7
|
|
|
|
next
|
|
|
|
;;;
|
|
;;; Memory access routines
|
|
;;; ----------------------
|
|
;;;
|
|
;;; We go with Forth names for this stuff. The HP's names for memory and
|
|
;;; storage operations heavily leverage the fact they have an object system
|
|
;;; with type tags and so on; we want to stay close to the bytes.
|
|
;;;
|
|
|
|
; Address on the top of the stack, value in the second position
|
|
defword store, 0
|
|
dq $ + 8
|
|
pop.qreg rbx
|
|
pop.qreg rax
|
|
mov.indirect.qreg.qreg rbx, rax
|
|
next
|
|
|
|
defword fetch, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
mov.qreg.indirect.qreg rax, rax
|
|
push.qreg rax
|
|
next
|
|
|
|
; Address on top, value second
|
|
; I might have done it the other way, but this is what Jonesforth does and it
|
|
; seems reasonable enough.
|
|
defword addstore, 0
|
|
dq $ + 8
|
|
pop.qreg rbx
|
|
pop.qreg rax
|
|
add.indirect.qreg.qreg rbx, rax
|
|
next
|
|
|
|
defword substore, 0
|
|
dq $ + 8
|
|
pop.qreg rbx
|
|
pop.qreg rax
|
|
sub.indirect.qreg.qreg rbx, rax
|
|
next
|
|
|
|
defword store8, 0
|
|
dq $ + 8
|
|
pop.qreg rbx
|
|
pop.qreg rax
|
|
mov.indirect.qreg.breg rbx, al
|
|
next
|
|
|
|
defword fetch8, 0
|
|
dq $ + 8
|
|
pop.qreg rbx
|
|
xor.qreg.qreg rax, rax
|
|
mov.breg.indirect.qreg al, rbx
|
|
push.qreg rax
|
|
next
|
|
|
|
defword store16, 0
|
|
dq $ + 8
|
|
pop.qreg rbx
|
|
pop.qreg rax
|
|
mov.indirect.qreg.wreg rbx, ax
|
|
next
|
|
|
|
defword fetch16, 0
|
|
dq $ + 8
|
|
pop.qreg rbx
|
|
xor.qreg.qreg rax, rax
|
|
mov.wreg.indirect.qreg ax, rbx
|
|
push.qreg rax
|
|
next
|
|
|
|
defword store32, 0
|
|
dq $ + 8
|
|
pop.qreg rbx
|
|
pop.qreg rax
|
|
mov.indirect.qreg.dreg rbx, eax
|
|
next
|
|
|
|
defword fetch32, 0
|
|
dq $ + 8
|
|
pop.qreg rbx
|
|
xor.qreg.qreg rax, rax
|
|
mov.dreg.indirect.qreg eax, rbx
|
|
push.qreg rax
|
|
next
|
|
|
|
; Before we get too deep into it, we also define a few reflection routines
|
|
; that retrieve, or set, the address of either of the two stacks.
|
|
;
|
|
; The result, or the new value, is on the top of the data stack. That's the
|
|
; same as how it works for any other word, but given the metacircular nature
|
|
; of these ones it's easy to get confused about that...
|
|
defword store_control_stack, 0
|
|
dq $ + 8
|
|
pop.qreg rbp
|
|
next
|
|
defword fetch_control_stack, 0
|
|
dq $ + 8
|
|
push.qreg rbp
|
|
next
|
|
defword store_value_stack, 0
|
|
dq $ + 8
|
|
; Per Intel's description of POP this reads from the old location, and there
|
|
; is no increment applied to the resulting value. See, the description says
|
|
; it increments the register then overwrites it, in that order.
|
|
pop.qreg rsp
|
|
next
|
|
defword fetch_value_stack, 0
|
|
dq $ + 8
|
|
; Per Intel's description of PUSH this pushes the old value.
|
|
push.qreg rsp
|
|
next
|
|
|
|
; Copy one non-overlapping block of memory over another. For the overlapping
|
|
; 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,
|
|
; 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 the C programming tradition 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 memcopy, 0
|
|
dq $ + 8
|
|
; We need to save and restore rsi; the other registers we can trample.
|
|
mov.qreg.qreg rdx, rsi
|
|
pop.qreg rcx
|
|
pop.qreg rdi
|
|
pop.qreg rsi
|
|
; We start from the low end, since that's easier arithmetic. So, we get to
|
|
; leave the DF flag alone.
|
|
rep movsb
|
|
mov.qreg.qreg rsi, rdx
|
|
next
|
|
|
|
; (written much later)
|
|
;
|
|
; In:
|
|
; destination
|
|
; source
|
|
; length
|
|
defword memmove, 0
|
|
dq $ + 8
|
|
; We need to save and restore rsi; the other registers we can trample.
|
|
mov.qreg.qreg rdx, rsi
|
|
pop.qreg rcx
|
|
pop.qreg rdi
|
|
pop.qreg rsi
|
|
|
|
; We need to check source < destination to decide which end to start from.
|
|
mov.qreg.qreg rax, rsi
|
|
cmp.qreg.qreg rax, rdi
|
|
; Relative offsets are from the start of the instruction after the jmp.
|
|
jmp.cc.rel.bimm below, 4
|
|
|
|
; If source is greater, we are sliding downwards so we start from the low
|
|
; end. So, we get to leave the DF flag alone.
|
|
rep movsb ; 2 bytes
|
|
jmp.rel.bimm 16 ; 2 bytes
|
|
|
|
; If destination is greater, we are sliding upwards so we start from the
|
|
; high end. So, we have to save and restore DF. Also, we have to adjust the
|
|
; pointers.
|
|
add.qreg.qreg rsi, rcx ; 3 bytes
|
|
dec.qreg rsi ; 3 bytes
|
|
add.qreg.qreg rdi, rcx ; 3 bytes
|
|
dec.qreg rdi ; 3 bytes
|
|
std ; 1 byte
|
|
rep movsb ; 2 bytes
|
|
cld ; 1 byte
|
|
|
|
mov.qreg.qreg rsi, rdx
|
|
next
|
|
|
|
|
|
; Stack in:
|
|
; string address
|
|
; Stack out:
|
|
; string length not including null byte
|
|
defword stringlen, 0
|
|
dq $ + 8
|
|
pop.qreg rdi
|
|
mov.qreg.qreg rbx, rdi
|
|
xor.qreg.qreg rax, rax
|
|
xor.qreg.qreg rcx, rcx
|
|
not.qreg rcx
|
|
repnz scasb
|
|
sub.qreg.qreg rdi, rbx
|
|
sub.qreg.bimm rdi, 1
|
|
push.qreg rdi
|
|
next
|
|
|
|
; Stack in:
|
|
; address of final non-null byte at the end of a string
|
|
; Stack out:
|
|
; backwards string length not including null byte at start
|
|
defword reverse_stringlen, 0
|
|
dq $ + 8
|
|
pop.qreg rdi
|
|
|
|
mov.qreg.qreg rbx, rdi
|
|
xor.qreg.qreg rax, rax
|
|
xor.qreg.qreg rcx, rcx
|
|
not.qreg rcx
|
|
|
|
std
|
|
repnz scasb
|
|
cld
|
|
|
|
sub.qreg.qreg rbx, rdi
|
|
sub.qreg.bimm rbx, 1
|
|
|
|
push.qreg rbx
|
|
next
|
|
|
|
; If you have a variable-length string followed by alignment padding, and
|
|
; you want to traverse it in reverse, you also need to skip the alignment
|
|
; padding...
|
|
;
|
|
; Stack in:
|
|
; address of final null byte in alignment padding of total length up to 8
|
|
; Stack out:
|
|
; number of null bytes (from end) until nearest non-null byte, or 8
|
|
defword reverse_padding_len, 0
|
|
dq $ + 8
|
|
pop.qreg rdi
|
|
|
|
mov.qreg.qreg rbx, rdi
|
|
xor.qreg.qreg rax, rax
|
|
mov.qreg.dimm rcx, 9
|
|
|
|
std
|
|
repz scasb
|
|
cld
|
|
|
|
sub.qreg.qreg rbx, rdi
|
|
sub.qreg.bimm rbx, 1
|
|
|
|
push.qreg rbx
|
|
next
|
|
|
|
; We make this work using exactly two jump instructions, which is likely the
|
|
; minimum possible. To avoid relying on labels, we hand-compute the byte
|
|
; offsets, so every instruction within their ranges is annotated with its
|
|
; length in bytes. Good fun.
|
|
;
|
|
; Stack in:
|
|
; left string address
|
|
; right string address
|
|
; Stack out:
|
|
; comparison value (0 for equal, 1 for left > right, -1 for left < right)
|
|
defword stringcmp, 0
|
|
dq $ + 8
|
|
; Save the rsi register.
|
|
;
|
|
; Happily, we don't need a lot of registers for this code, so we can
|
|
; dedicate rdx to this and not have to deal with stack juggling..
|
|
mov.qreg.qreg rdx, rsi
|
|
|
|
; Get the parameters off the stack.
|
|
;
|
|
; For reasons that will be explained below, the left and right strings
|
|
; from our caller's perspective are swapped from the perspective of the
|
|
; comparisons we'll be doing. The rdi register points to the right-hand
|
|
; operand of the "cmps" instruction, while rsi points to the left-hand
|
|
; operand; [Intel] volume 2A, chapter 3, section 4-3.3, "CMPS"; note that
|
|
; the PDF mis-numbers the sections in the second half of chapter 3.
|
|
pop.qreg rsi
|
|
pop.qreg rdi
|
|
|
|
; For the comparison-unequal loop-exit code, we'll need rbx set to zero.
|
|
; The easy way to do that is by xor'ing it with itself, but doing it at the
|
|
; end of the loop would overwrite the comparison flags, which we need. So we
|
|
; do it in advance, and carefully don't touch it anywhere else.
|
|
;
|
|
; See the list of which instructions affect the flags in [Intel] volume 1,
|
|
; appendix A, section A-1, table A-2.
|
|
xor.qreg.qreg rbx, rbx
|
|
|
|
; We also clear rax; we'll be using al later, and it will be convenient to
|
|
; know the upper bits are always zero.
|
|
xor.qreg.qreg rax, rax
|
|
|
|
; Now we've initialized everything we need; everything after this point is
|
|
; part of the loop.
|
|
|
|
; At the start of each iteration, save a copy of the byte we're at now. We
|
|
; need to do this before cmps because the pointers will increment; we'll
|
|
; eventually use it to test whether we've reached the end delimiter.
|
|
;
|
|
; We do a 64-bit load into rcx, which is otherwise unused, then copy the
|
|
; low byte from cl to al. This avoids having to think about addressing modes
|
|
; that combine 64-bit addresses with smaller data sizes; those are very
|
|
; subtle.
|
|
mov.qreg.indirect.qreg rcx, rsi ; 3 bytes
|
|
mov.breg.breg al, cl ; 2 bytes
|
|
|
|
; Now do the cmps, which is the heart of the loop.
|
|
;
|
|
; Note that, in addition to relying on this comparison to test content
|
|
; bytes against each other, in the event that one string is a prefix of the
|
|
; other, this will also test content bytes against null delimiters. The
|
|
; longer string will compare as "greater", because zero is less than all
|
|
; other possible byte values. This is what we want.
|
|
;
|
|
; Since strings of different lengths are necessarily unequal, letting this
|
|
; test do the work of detecting that also means we don't have to deal with
|
|
; scenarios where we're past the end of one string but not the other.
|
|
cmps8 ; 1 byte
|
|
|
|
; The flags are now set based on the simulated subtraction of the next
|
|
; bytes from the two strings. If they were unequal, the loop will end. If
|
|
; they were equal, we have another test to do before we're finished with
|
|
; this iteration. So we put the loop-end code next, and conditionally jump
|
|
; forward past it.
|
|
;
|
|
; Recall that relative offsets are from the start of the instruction after
|
|
; the jmp.
|
|
jmp.cc.rel.bimm equal, 15 ; 2 bytes
|
|
|
|
; If we got here, the strings are unequal, so we need to turn the flags
|
|
; into a comparison value. We cleared rbx earlier; now we set its low bit to
|
|
; the "above" flag, then use sbb to subtract the "carry" flag (which it
|
|
; thinks of as the "borrow" flag).
|
|
;
|
|
; Recall that "carry" is based on whether the comparison would cause a
|
|
; change to the next bit "outside" the bits being compared; [Intel]
|
|
; volume 1, chapter 3, section 3-4.3.1. Since the comparison is a
|
|
; subtraction, "carry" is true when the right-hand byte is strictly greater
|
|
; than the left-hand byte.
|
|
;
|
|
; Also recall that "zero", also called "equal", is based on whether the
|
|
; comparison's result produces output that's all zero bits. Since the
|
|
; comparison is a subtraction, "zero" is true when the two bytes are
|
|
; identical.
|
|
;
|
|
; The "above" condition is not a flag, but a composite of flags. It's true
|
|
; when both "carry" and "zero" are false; [Intel] volume 1, chapter 7,
|
|
; section 7-3.1.1, table 7-2. For us, this is equivalent to saying the
|
|
; left-hand byte is strictly greater than the right-hand.
|
|
;
|
|
; So, after the "set" instruction, rbx is 1 if left > right, and 0 if
|
|
; left = right or left < right. The "sbb" instruction with an immediate
|
|
; value of zero subtracts the value of the carry flag from rbx; the flag is
|
|
; true in the case where left < right, and false otherwise. So, after the
|
|
; "sbb", rbx is 1 if left > right, 0 if left = right, and -1 if
|
|
; left < right.
|
|
;
|
|
; This sounds like the opposite of what we want, but recall that we
|
|
; exchanged the operands, so these are the values our caller is expecting.
|
|
; While it might be tempting to look for a way to not need that
|
|
; transposition, and indeed there exists an approach using "not above", it's
|
|
; fiddly in a way that's even harder to explain.
|
|
;
|
|
; Note that it's important that the "jmp" and "set" instructions don't
|
|
; change the flags (see table A-2 again), so the "cmps" is the most recent
|
|
; thing that did. The "sbb" instruction does change them, but we don't need
|
|
; them again after that point so it doesn't matter.
|
|
;
|
|
; Finally, we need to restore rsi before we return to Forth.
|
|
;
|
|
; The two-instruction set-sbb sequence is one of those classic assembly
|
|
; programming tricks that often goes unexplained, because most of its appeal
|
|
; is its brevity and a proper explanation is quite lengthy. Please enjoy
|
|
; this gift of knowledge, and thanks to our friends who showed it to us.
|
|
set.breg.cc bl, above ; 3 bytes
|
|
sbb.qreg.bimm rbx, 0 ; 4 bytes
|
|
push.qreg rbx ; 1 byte
|
|
mov.qreg.qreg rsi, rdx ; 3 bytes
|
|
next ; 4 bytes
|
|
|
|
; If we got here, the current bytes are equal to each other. We still need
|
|
; to test if they're null terminators; if so, we exit, and if not, we loop.
|
|
;
|
|
; At the beginning of this iteration, we saved a copy of the byte being
|
|
; inspected in rax. The "test" instruction simulates a xor and sets the
|
|
; flags accordingly. We check the "not equal" condition, also known as "not
|
|
; zero", and jump backwards to the start of the loop when that's the case.
|
|
;
|
|
; Recall that relative offsets are from the start of the instruction after
|
|
; the jmp.
|
|
test.qreg.qreg rax, rax ; 3 bytes
|
|
jmp.cc.rel.bimm not_equal, -28 ; 2 bytes
|
|
|
|
; If we got here, we got all the way to the end of both strings and found
|
|
; a null byte, so we return 0 to indicate they're equal.
|
|
;
|
|
; We can use push.dimm even though our stack holds 64-bit values, because
|
|
; it gets sign-extended.
|
|
;
|
|
; We need to restore rsi before we return to Forth.
|
|
push.dimm 0
|
|
mov.qreg.qreg rsi, rdx
|
|
next
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;
|
|
;;; Branching ;;;
|
|
;;;;;;;;;;;;;;;;;
|
|
|
|
; This takes a number of bytes, not machine words. That allows it to be used
|
|
; for putting weird things embedded in the code.
|
|
;
|
|
; The offset is relative to the start of the word the number of bytes is in,
|
|
; so, make sure to have it skip itself.
|
|
defword branch, 0
|
|
dq $ + 8
|
|
add.qreg.indirect.qreg rsi, rsi
|
|
next
|
|
|
|
; This should probably be 0branch, but right now the auto-label code is picky.
|
|
defword zbranch, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
test.qreg.qreg rax, rax
|
|
; Please notice the 8-bit branch to the nearby word.
|
|
jmp.cc.rel.bimm zero, branch + 8 - zbranch_after_jmp
|
|
zbranch_after_jmp:
|
|
lodsq ; just a convenient way to skip rsi forward
|
|
next
|
|
|
|
; This is like next, but instead of using rsi as the "instruction pointer", it
|
|
; takes a codeword address from the value stack.
|
|
;
|
|
; In the event that the codeword is docol, docol will handle any manipulation
|
|
; of the control stack that needs to happen. Yes, it really is that simple.
|
|
defword execute, 0
|
|
dq $ + 8
|
|
pop.qreg rax
|
|
jmp.abs.indirect.qreg rax
|
|
|
|
;;;;;;;;;;;;;;;;;;;;
|
|
;;; System calls ;;;
|
|
;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; The kernel preserves every register except rax, rcx, and r11. The system
|
|
;;; call number goes in rax, as does the return value. Parameters go in rdi,
|
|
;;; rsi, rdx, r10, r8, and r9, in that order. [SysV] A.2.1.
|
|
;;;
|
|
;;; Notice that rsi is our control stack, so we have to save it (for
|
|
;;; syscalls with at least two parameters). We can use the value stack to do
|
|
;;; that, since rsp is preserved. We don't save other registers because our
|
|
;;; caller should do that, if it cares.
|
|
;;;
|
|
|
|
;;;
|
|
;;; This does the Linux exit() system call, passing it an exit code taken
|
|
;;; from the stack.
|
|
;;;
|
|
defword sys_exit, 0
|
|
dq $ + 8
|
|
|
|
mov.qreg.qimm rax, 60 ; syscall number
|
|
pop.qreg rdi ; exit code
|
|
syscall
|
|
|
|
; In the event we're still here, let's minimize confusion.
|
|
hlt
|
|
|
|
|
|
;;;
|
|
;;; This does the Linux write() system call, passing it an address from the
|
|
;;; top of the stack and a length from the second position on the stack. It
|
|
;;; writes to file descriptor 1, which is stdout.
|
|
;;;
|
|
;;; For our length parameter, we can pop directly from the stack into rdx,
|
|
;;; which directly becomes the syscall parameter. For our address parameter,
|
|
;;; the syscall wants it in rsi, which we also care about, so we have to do a
|
|
;;; little juggling.
|
|
;;;
|
|
defword sys_write, 0
|
|
dq $ + 8
|
|
pop.qreg rcx ; address from stack
|
|
pop.qreg rdx ; length from stack, passed directly
|
|
push.qreg rsi ; save rsi
|
|
mov.qreg.qimm rax, 1 ; syscall number
|
|
mov.qreg.qimm rdi, 1 ; file descriptor
|
|
mov.qreg.qreg rsi, rcx ; pass address
|
|
syscall
|
|
pop.qreg rsi ; restore rsi
|
|
next
|
|
|
|
|
|
; In:
|
|
; length
|
|
; address
|
|
defword sys_read, 0
|
|
dq $ + 8
|
|
pop.qreg rcx ; address from stack
|
|
pop.qreg rdx ; length from stack, passed directly
|
|
push.qreg rsi ; save rsi
|
|
mov.qreg.qimm rax, 0 ; syscall number
|
|
mov.qreg.qimm rdi, 0 ; file descriptor
|
|
mov.qreg.qreg rsi, rcx ; pass address
|
|
syscall
|
|
pop.qreg rsi ; restore rsi
|
|
push.qreg rax ; return length
|
|
next
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;; I/O conveniences ;;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
|
defword emitstring, 0
|
|
dq docol, dup, stringlen, swap, sys_write, exit
|
|
|
|
|
|
; The main word for this next part is "dot"; the stuff preceding it is
|
|
; internals used to implement it.
|
|
;
|
|
; Although this could notionally be emitinteger for symmetry, it's
|
|
; well-known under the name dot and as a single period character, and that
|
|
; name participates in conventions for names of other things. So, we go with
|
|
; it.
|
|
;
|
|
; Unlike Jonesforth, we do not have a global "base" variable, and this word
|
|
; does not change its behavior depending on that value. It's always base ten.
|
|
;
|
|
; This is an extremely inefficient implementation, but on the plus side,
|
|
; doing that avoids having to think about any sort of memory management or
|
|
; recursion, and lets us stick entirely with the trivial control-flow
|
|
; constructs we already have.
|
|
|
|
; In:
|
|
; base
|
|
; exponent
|
|
; Out:
|
|
; base to the power of exponent
|
|
defword pow, 0
|
|
dq docol
|
|
dq lit, 1, swap
|
|
; If the count of remaining powers is NOT equal to zero, the comparison will
|
|
; return 0, which will cause the zbranch to skip the rest of the line.
|
|
dq dup, lit, 0, eq, zbranch, 5*8, drop, swap, drop, exit
|
|
; (base, result so far, count of remaining powers)
|
|
dq lit, 1, sub, unroll3
|
|
; (updated count of remaining powers, base, result so far)
|
|
dq swap, dup, lit, 4, unroll
|
|
; (base, updated count of remaining powers, result so far, base)
|
|
dq mul, swap
|
|
; (base, updated result so far, updated count of remaining powers)
|
|
dq branch, -22*8
|
|
|
|
; In:
|
|
; base
|
|
; value
|
|
; Out:
|
|
; floor of logarithm of value, in base base
|
|
defword logfloor, 0
|
|
dq docol
|
|
|
|
; Start with a product equal to the base, and a count of 0.
|
|
dq swap, dup, unroll3, lit, 0
|
|
|
|
; This is the start of the loop body.
|
|
; (base, value, product so far, count of powers included so far)
|
|
dq unroll3, dup2
|
|
; (base, count so far, value, product so far)
|
|
dq gt_unsigned, zbranch, 6*8
|
|
|
|
; If we get here, we're done.
|
|
; (base, count so far, value, product so far)
|
|
dq drop, drop, swap, drop, exit
|
|
|
|
; If we're here, we need to do another loop.
|
|
; (base, count so far, value, product so far)
|
|
dq lit, 4, roll, dup, lit, 5, unroll, mul, roll3, lit, 1, add
|
|
; (base, value, updated product so far, updated count so far)
|
|
|
|
; If the product is less than the base, we overflowed. In that case, the
|
|
; product-so-far is the maximum, so just return it.
|
|
dq lit, 4, roll, dup, lit, 5, unroll, roll3, dup, lit, 4, unroll
|
|
dq lt, zbranch, 8*8
|
|
dq lit, 4, unroll, drop, drop, drop, exit
|
|
|
|
; Nothing else weird going on, so loop.
|
|
dq branch, -45*8
|
|
|
|
; In:
|
|
; base
|
|
; value
|
|
; Out:
|
|
; celing of logarithm of value, in base base
|
|
defword logceil, 0
|
|
dq docol
|
|
|
|
; Start with a product of 1 and a count of 0.
|
|
dq lit, 1, lit, 0
|
|
|
|
; This is the start of the loop body.
|
|
; (base, value, product so far, count of powers included so far)
|
|
dq unroll3, dup2
|
|
; (base, count so far, value, product so far)
|
|
dq ge_unsigned, zbranch, 6*8
|
|
|
|
; If we get here, we're done.
|
|
; (base, count so far, value, product so far)
|
|
dq drop, drop, swap, drop, exit
|
|
|
|
; If we're here, we need to do another loop.
|
|
; (base, count so far, value, product so far)
|
|
dq lit, 4, roll, dup, lit, 5, unroll, mul, roll3, lit, 1, add
|
|
; (base, value, updated product so far, updated count so far)
|
|
|
|
; If the product is less than the base, we overflowed. In that case, the
|
|
; product-so-far is the maximum, so just return it.
|
|
dq lit, 4, roll, dup, lit, 5, unroll, roll3, dup, lit, 4, unroll
|
|
dq lt, zbranch, 8*8
|
|
dq lit, 4, unroll, drop, drop, drop, exit
|
|
|
|
; Nothing else weird going on, so loop.
|
|
dq branch, -45*8
|
|
|
|
; In:
|
|
; integer to print
|
|
; base to print in
|
|
; width to zero-pad to
|
|
defword dotbase_unsigned, 0
|
|
dq docol
|
|
|
|
; (input, base, width)
|
|
; Compute how many digits we need to display. Because we use logfloor, the
|
|
; logic of always printing at least one digit is already handled for us.
|
|
dq unroll3, swap, dup2, logfloor, lit, 1, add
|
|
; (width, base, input, number of digits if no padding)
|
|
dq lit, 4, roll, dup2, gt, zbranch, 5*8
|
|
; (base, input, number of digits if no padding, width)
|
|
; If we're here, we should use the padded width
|
|
dq swap, drop, branch, 2*8
|
|
; (base, input, number of digits if no padding, width)
|
|
; If we're here, we should use the unpadded width
|
|
dq drop
|
|
|
|
; (base, input, number of digits remaining)
|
|
; This is the start of the loop.
|
|
dq dup2, lit, 1, sub
|
|
; (base, input, number of digits remaining, input, intermediate value)
|
|
dq lit, 5, roll, dup, lit, 6, unroll, swap
|
|
; (base, input, number of digits remaining, input, base, intermediate value)
|
|
dq pow, divmod, swap, drop
|
|
; (base, input, number of digits remaining,
|
|
; input divided by base^x appropriately)
|
|
dq lit, 4, roll, dup, lit, 5, unroll
|
|
; (base, input, number of digits remaining,
|
|
; input divided by base^x appropriately, base)
|
|
dq divmod, drop
|
|
|
|
; (base, input, number of digits remaining, current digit)
|
|
; We construct a one-character string on the stack, then use a pointer to
|
|
; it. It will always contain its own null-termination without us having to
|
|
; do anything special to that end.
|
|
dq dup, lit, 10, gt, zbranch, 5*8
|
|
dq lit, "0", branch, 6*8
|
|
dq lit, 10, sub, lit, "a"
|
|
dq add
|
|
dq fetch_value_stack, emitstring
|
|
|
|
; We deallocate the string by dropping it.
|
|
;
|
|
; Saying it like that makes it sound obvious; contemplate it until it feels
|
|
; surprising.
|
|
dq drop
|
|
|
|
dq lit, 1, sub
|
|
dq dup, zbranch, 3*8, branch, -51*8
|
|
dq drop, drop, drop, exit
|
|
|
|
; In:
|
|
; integer to print
|
|
; base to print in
|
|
defword dotbase, 0
|
|
dq docol
|
|
|
|
dq swap
|
|
; (base, input)
|
|
|
|
; Deal with negative numbers.
|
|
dq dup, lit, 0, gt, zbranch, 7*8
|
|
dq lit, -1, mul
|
|
dq litstring, "-", emitstring
|
|
|
|
dq swap, lit, 0, dotbase_unsigned, exit
|
|
|
|
; In:
|
|
; integer to print
|
|
defword dot, 0
|
|
dq docol, lit, 10, dotbase, exit
|
|
defword dothex, 0
|
|
dq docol, lit, 16, lit, 0, dotbase_unsigned, exit
|
|
defword dothex8, 0
|
|
dq docol, lit, 16, lit, 2, dotbase_unsigned, exit
|
|
defword dothex16, 0
|
|
dq docol, lit, 16, lit, 4, dotbase_unsigned, exit
|
|
defword dothex32, 0
|
|
dq docol, lit, 16, lit, 8, dotbase_unsigned, exit
|
|
defword dothex64, 0
|
|
dq docol, lit, 16, lit, 16, dotbase_unsigned, exit
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;; Development utilities ;;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
; This peforms the "hlt" instruction (Intel's mnemomic, short for "halt"),
|
|
; which will cause the program to exit with a segmentation fault. If you're
|
|
; running under a debugger, this is a convenient way to get execution to stop
|
|
; at a certain point.
|
|
;
|
|
; It's called "crash" rather than "hlt" to distinguish it from the word
|
|
; which outputs the instruction as machine code.
|
|
defword crash, 0
|
|
dq $ + 8
|
|
hlt
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;
|
|
;;; Output 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, lit, 1, add, dup
|
|
; base/destination, source, length, length
|
|
dq lit, 4, roll, dup, lit, 4, unroll
|
|
; source, destination, length, length, base/destination
|
|
dq add, lit, 4, unroll
|
|
; new base, source, destination, length
|
|
dq memcopy
|
|
dq exit
|
|
|
|
; This also works on C-style strings, relying on the null terminator, but
|
|
; the packed data does not include it.
|
|
;
|
|
; Stack in:
|
|
; base address, string pointer
|
|
; Stack out:
|
|
; new base address
|
|
defword pack_raw_string, 0
|
|
dq docol
|
|
dq dup, stringlen, dup
|
|
; base/destination, source, length, length
|
|
dq lit, 4, roll, dup, lit, 4, unroll
|
|
; source, destination, length, length, base/destination
|
|
dq add, lit, 4, unroll
|
|
; new base, source, destination, length
|
|
dq memcopy
|
|
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
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;
|
|
;;; Input helpers ;;;
|
|
;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; These routines are for examining data structures in-memory.
|
|
;;;
|
|
;;; Similarly to the output routines, each routine takes an input address,
|
|
;;; which it updates to point after the data item being read. Since this is
|
|
;;; input, the routines return data items rather than accepting them.
|
|
|
|
; In:
|
|
; proposed size
|
|
; alignment
|
|
; Out:
|
|
; adjusted size
|
|
defword align_size, 0
|
|
dq docol
|
|
dq dup, unroll3, dup, unroll3
|
|
; (alignment, proposed size, alignment)
|
|
dq lit, 1, sub, add, swap, divmod, swap, drop, mul
|
|
dq exit
|
|
|
|
; In: base address
|
|
; Out: new base address, value
|
|
defword unpack64, 0
|
|
dq docol
|
|
dq dup, fetch, swap, lit, 8, add, swap
|
|
dq exit
|
|
defword unpack32, 0
|
|
dq docol
|
|
dq dup, fetch32, swap, lit, 4, add, swap
|
|
dq exit
|
|
defword unpack16, 0
|
|
dq docol
|
|
dq dup, fetch16, swap, lit, 2, add, swap
|
|
dq exit
|
|
defword unpack8, 0
|
|
dq docol
|
|
dq dup, fetch8, swap, lit, 1, add, swap
|
|
dq exit
|
|
|
|
; You might think this would be identical to packalign, but packalign has
|
|
; side effects.
|
|
;
|
|
; Stack in:
|
|
; base address
|
|
; byte size
|
|
; Stack out:
|
|
; new base address
|
|
defword unpackalign, 0
|
|
dq docol, align_size, exit
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;; Assembly language, but in Forth ;;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; It's all backwards and stuff.
|
|
;;;
|
|
;;; Okay, but seriously, the convention is: target on the top of the stack,
|
|
;;; source behind it. This is similar to how the Forth "store" and "fetch"
|
|
;;; words work.
|
|
;;;
|
|
;;; 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
|
|
defword eax, 0
|
|
dq docol, lit, eax, exit
|
|
defword ecx, 0
|
|
dq docol, lit, ecx, exit
|
|
defword edx, 0
|
|
dq docol, lit, edx, exit
|
|
defword ebx, 0
|
|
dq docol, lit, ebx, exit
|
|
defword esp, 0
|
|
dq docol, lit, esp, exit
|
|
defword ebp, 0
|
|
dq docol, lit, ebp, exit
|
|
defword esi, 0
|
|
dq docol, lit, esi, exit
|
|
defword edi, 0
|
|
dq docol, lit, edi, exit
|
|
defword ax, 0
|
|
dq docol, lit, ax, exit
|
|
defword cx, 0
|
|
dq docol, lit, cx, exit
|
|
defword dx, 0
|
|
dq docol, lit, dx, exit
|
|
defword bx, 0
|
|
dq docol, lit, bx, exit
|
|
defword sp, 0
|
|
dq docol, lit, sp, exit
|
|
defword bp, 0
|
|
dq docol, lit, bp, exit
|
|
defword si, 0
|
|
dq docol, lit, si, exit
|
|
defword di, 0
|
|
dq docol, lit, di, exit
|
|
defword al, 0
|
|
dq docol, lit, al, exit
|
|
defword cl, 0
|
|
dq docol, lit, cl, exit
|
|
defword dl, 0
|
|
dq docol, lit, dl, exit
|
|
defword bl, 0
|
|
dq docol, lit, bl, exit
|
|
defword ah, 0
|
|
dq docol, lit, ah, exit
|
|
defword ch, 0
|
|
dq docol, lit, ch, exit
|
|
defword dh, 0
|
|
dq docol, lit, dh, exit
|
|
defword bh, 0
|
|
dq docol, lit, bh, exit
|
|
defword cc_overflow, 0
|
|
dq docol, lit, cc_overflow, exit
|
|
defword cc_no_overflow, 0
|
|
dq docol, lit, cc_no_overflow, exit
|
|
defword cc_below, 0
|
|
dq docol, lit, cc_below, exit
|
|
defword cc_above_equal, 0
|
|
dq docol, lit, cc_above_equal, exit
|
|
defword cc_equal, 0
|
|
dq docol, lit, cc_equal, exit
|
|
defword cc_not_equal, 0
|
|
dq docol, lit, cc_not_equal, exit
|
|
defword cc_below_equal, 0
|
|
dq docol, lit, cc_below_equal, exit
|
|
defword cc_above, 0
|
|
dq docol, lit, cc_above, exit
|
|
defword cc_sign, 0
|
|
dq docol, lit, cc_sign, exit
|
|
defword cc_not_sign, 0
|
|
dq docol, lit, cc_not_sign, exit
|
|
defword cc_even, 0
|
|
dq docol, lit, cc_even, exit
|
|
defword cc_odd, 0
|
|
dq docol, lit, cc_odd, exit
|
|
defword cc_less, 0
|
|
dq docol, lit, cc_less, exit
|
|
defword cc_greater_equal, 0
|
|
dq docol, lit, cc_greater_equal, exit
|
|
defword cc_less_equal, 0
|
|
dq docol, lit, cc_less_equal, exit
|
|
defword cc_greater, 0
|
|
dq docol, lit, cc_greater, 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 litstring, "Parameter to reg64 is not a reg64.", emitstring
|
|
dq lit, 1, 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 litstring, "Parameter to extrareg64 is not an extrareg64.", emitstring
|
|
dq lit, 1, sys_exit
|
|
|
|
; Stack in:
|
|
; register name
|
|
; Stack out:
|
|
; 3-bit encoded value for register
|
|
defword reg32, 0
|
|
dq docol
|
|
dq dup, eax, eq, zbranch, 5*8, drop, lit, 0, exit
|
|
dq dup, ecx, eq, zbranch, 5*8, drop, lit, 1, exit
|
|
dq dup, edx, eq, zbranch, 5*8, drop, lit, 2, exit
|
|
dq dup, ebx, eq, zbranch, 5*8, drop, lit, 3, exit
|
|
dq dup, esp, eq, zbranch, 5*8, drop, lit, 4, exit
|
|
dq dup, ebp, eq, zbranch, 5*8, drop, lit, 5, exit
|
|
dq dup, esi, eq, zbranch, 5*8, drop, lit, 6, exit
|
|
dq dup, edi, eq, zbranch, 5*8, drop, lit, 7, exit
|
|
dq litstring, "Parameter to reg32 is not a reg32.", emitstring
|
|
dq lit, 1, sys_exit
|
|
|
|
; Stack in:
|
|
; register name
|
|
; Stack out:
|
|
; 3-bit encoded value for register
|
|
defword reg16, 0
|
|
dq docol
|
|
dq dup, ax, eq, zbranch, 5*8, drop, lit, 0, exit
|
|
dq dup, cx, eq, zbranch, 5*8, drop, lit, 1, exit
|
|
dq dup, dx, eq, zbranch, 5*8, drop, lit, 2, exit
|
|
dq dup, bx, eq, zbranch, 5*8, drop, lit, 3, exit
|
|
dq dup, sp, eq, zbranch, 5*8, drop, lit, 4, exit
|
|
dq dup, bp, eq, zbranch, 5*8, drop, lit, 5, exit
|
|
dq dup, si, eq, zbranch, 5*8, drop, lit, 6, exit
|
|
dq dup, di, eq, zbranch, 5*8, drop, lit, 7, exit
|
|
dq litstring, "Parameter to reg16 is not a reg16.", emitstring
|
|
dq lit, 1, sys_exit
|
|
|
|
; Stack in:
|
|
; register name
|
|
; Stack out:
|
|
; 3-bit encoded value for register
|
|
defword reg8, 0
|
|
dq docol
|
|
dq dup, al, eq, zbranch, 5*8, drop, lit, 0, exit
|
|
dq dup, cl, eq, zbranch, 5*8, drop, lit, 1, exit
|
|
dq dup, dl, eq, zbranch, 5*8, drop, lit, 2, exit
|
|
dq dup, bl, eq, zbranch, 5*8, drop, lit, 3, exit
|
|
dq dup, ah, eq, zbranch, 5*8, drop, lit, 4, exit
|
|
dq dup, ch, eq, zbranch, 5*8, drop, lit, 5, exit
|
|
dq dup, dh, eq, zbranch, 5*8, drop, lit, 6, exit
|
|
dq dup, bh, eq, zbranch, 5*8, drop, lit, 7, exit
|
|
dq litstring, "Parameter to reg8 is not a reg8.", 0, emitstring
|
|
dq lit, 1, sys_exit
|
|
|
|
; Stack in:
|
|
; scale factor, as a count of bytes
|
|
; Stack out:
|
|
; 2-bit encoded value for scale field in SIB byte
|
|
defword scalefield, 0
|
|
dq docol
|
|
dq dup, lit, 1, eq, zbranch, 5*8, drop, lit, 0, exit
|
|
dq dup, lit, 2, eq, zbranch, 5*8, drop, lit, 1, exit
|
|
dq dup, lit, 4, eq, zbranch, 5*8, drop, lit, 2, exit
|
|
dq dup, lit, 8, eq, zbranch, 5*8, drop, lit, 3, exit
|
|
dq litstring, "Parameter to scalefield is not 1, 2, 4, or 8.", emitstring
|
|
dq lit, 1, sys_exit
|
|
|
|
; [Intel] volume 2D, appendix B, section B-1.4.7, table B-10. Also see the
|
|
; individual opcode pages.
|
|
;
|
|
; Stack in:
|
|
; condition name
|
|
; Stack out:
|
|
; 4-bit encoded value for condition code in opcodes
|
|
defword conditioncode, 0
|
|
dq docol
|
|
dq dup, cc_overflow, eq, zbranch, 5*8, drop, lit, 0, exit
|
|
dq dup, cc_no_overflow, eq, zbranch, 5*8, drop, lit, 1, exit
|
|
dq dup, cc_below, eq, zbranch, 5*8, drop, lit, 2, exit
|
|
dq dup, cc_above_equal, eq, zbranch, 5*8, drop, lit, 3, exit
|
|
dq dup, cc_equal, eq, zbranch, 5*8, drop, lit, 4, exit
|
|
dq dup, cc_not_equal, eq, zbranch, 5*8, drop, lit, 5, exit
|
|
dq dup, cc_below_equal, eq, zbranch, 5*8, drop, lit, 6, exit
|
|
dq dup, cc_above, eq, zbranch, 5*8, drop, lit, 7, exit
|
|
dq dup, cc_sign, eq, zbranch, 5*8, drop, lit, 8, exit
|
|
dq dup, cc_not_sign, eq, zbranch, 5*8, drop, lit, 9, exit
|
|
dq dup, cc_even, eq, zbranch, 5*8, drop, lit, 10, exit
|
|
dq dup, cc_odd, eq, zbranch, 5*8, drop, lit, 11, exit
|
|
dq dup, cc_less, eq, zbranch, 5*8, drop, lit, 12, exit
|
|
dq dup, cc_greater_equal, eq, zbranch, 5*8, drop, lit, 13, exit
|
|
dq dup, cc_less_equal, eq, zbranch, 5*8, drop, lit, 14, exit
|
|
dq dup, cc_greater, eq, zbranch, 5*8, drop, lit, 15, exit
|
|
dq litstring, "Parameter to conditioncode is not a condition code."
|
|
dq emitstring
|
|
dq lit, 1, sys_exit
|
|
|
|
; Stack:
|
|
; output point
|
|
defword rex_w, 0
|
|
dq docol, lit, 0x48, pack8, exit
|
|
defword rex_b, 0
|
|
dq docol, lit, 0x41, 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
|
|
; 4-bit encoded value for condition code
|
|
; opcode byte
|
|
defword opcodecc, 0
|
|
dq docol, or, pack8, exit
|
|
|
|
; The low-level word that outputs a modrm byte given fully-processed,
|
|
; numeric values for its fields. Most code will want to call one of the
|
|
; higher-level modrm_* words, instead.
|
|
;
|
|
; 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
|
|
; scale field
|
|
; index field
|
|
; base field
|
|
defword sib, 0
|
|
dq docol, swap, lit, 8, mul, or, swap, lit, 64, mul, or, pack8, exit
|
|
|
|
; The simplest of the modrm modes: Direct register addressing. There are no
|
|
; special cases to check.
|
|
;
|
|
; It's important to notice that the R/M field may describe either a source,
|
|
; or a target, depending on what the instruction is. So, this helper doesn't
|
|
; get to know that. It also doesn't get to know whether the value in the
|
|
; reg/op field describes a register, or if instead it's an extension of the
|
|
; opcode. The caller is responsible for figuring that all out.
|
|
;
|
|
; Stack:
|
|
; output point
|
|
; reg/op field value (raw number)
|
|
; reg/mem field register name
|
|
defword addressing_reg64, 0
|
|
dq docol, reg64, lit, 3, unroll3, modrm, exit
|
|
|
|
; This is a helper for assembly instructions that want to do a form of
|
|
; addressing that requires a value of 1 in the modrm byte's mode field, and
|
|
; do not want to do any indexing.
|
|
;
|
|
; Its main responsibility is to deal with the scenario that requires an SIB
|
|
; byte, which happens when the R/M field has a value of 4, which would
|
|
; otherwise refer to the register rsp. In that situation, it also generates
|
|
; an SIB byte which indicates a scale of 1, no indexing, and rsp as the base
|
|
; register.
|
|
;
|
|
; Stack:
|
|
; output point
|
|
; reg/op field value (raw number)
|
|
; reg/mem field register name
|
|
defword addressing_indirect_reg64, 0
|
|
dq docol
|
|
; Exit with an error if the R/M register is rbp.
|
|
dq dup, rbp, ne, zbranch, 23*8
|
|
; Check whether the R/M register is rsp; save the test result for later.
|
|
dq dup, rsp, eq, lit, 4, unroll
|
|
; (equality result, output point, reg/op value, reg/mem name)
|
|
dq reg64, lit, 0, unroll3, modrm
|
|
; (equality result, output point)
|
|
; If the R/M register was rsp, we need an SIB byte; otherwise, skip it.
|
|
dq swap, zbranch, 8*8, lit, 0, lit, 4, rsp, reg64, sib
|
|
dq exit
|
|
dq litstring, "R/M parameter to addressing_indirect_reg64 is rbp."
|
|
dq emitstring
|
|
dq lit, 1, sys_exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; reg/op field value (raw number)
|
|
; reg/mem field register name
|
|
; displacement value
|
|
defword addressing_disp8_reg64, 0
|
|
dq docol
|
|
; This mode can do rbp fine, so no need to check for that.
|
|
; Check whether the R/M register is rsp; save the test result for later.
|
|
dq swap, dup, rsp, eq, lit, 5, unroll, swap
|
|
; Stash the displacement value out of the way, too.
|
|
dq lit, 4, unroll
|
|
dq reg64, lit, 1, unroll3, modrm
|
|
; If the R/M register was rsp, we need an SIB byte; otherwise, skip it.
|
|
dq roll3, zbranch, 8*8, lit, 0, lit, 4, rsp, reg64, sib
|
|
; The displacement byte.
|
|
dq swap, pack8
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; reg/op field value (raw number)
|
|
; reg/mem field register name
|
|
; displacement value
|
|
defword addressing_disp32_reg64, 0
|
|
dq docol
|
|
; This mode can do rbp fine, so no need to check for that.
|
|
; Check whether the R/M register is rsp; save the test result for later.
|
|
dq swap, dup, rsp, eq, lit, 5, unroll, swap
|
|
; Stash the displacement value out of the way, too.
|
|
dq lit, 4, unroll
|
|
dq reg64, lit, 2, unroll3, modrm
|
|
; If the R/M register was rsp, we need an SIB byte; otherwise, skip it.
|
|
dq roll3, zbranch, 8*8, lit, 0, lit, 4, rsp, reg64, sib
|
|
; The displacement value.
|
|
dq swap, pack32
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; reg/op field value (raw number)
|
|
; scale factor, as a count of bytes
|
|
; index register name
|
|
; base field register name
|
|
defword addressing_indexed_reg64, 0
|
|
dq docol
|
|
; Exit with an error if the base register is rbp.
|
|
dq dup, rbp, ne, zbranch, 23*8
|
|
; Reg/mem value 4 means to use an SIB byte (at least, with this mode).
|
|
dq lit, 5, roll, lit, 0, lit, 6, roll, lit, 4, modrm, lit, 4, unroll
|
|
dq reg64, unroll3, reg64, unroll3, scalefield, unroll3, sib
|
|
dq exit
|
|
dq litstring, "Base parameter to addressing_indexed_reg64 is rbp."
|
|
dq emitstring
|
|
dq lit, 1, sys_exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; reg/op field value (raw number)
|
|
; scale factor, as a count of bytes
|
|
; index register name
|
|
; base field register name
|
|
; displacement value
|
|
defword addressing_disp8_indexed_reg64, 0
|
|
dq docol
|
|
; This mode can do rbp fine, so no need to check for that.
|
|
; Reg/mem value 4 means to use an SIB byte (at least, with this mode).
|
|
dq lit, 6, roll, lit, 1, lit, 7, roll, lit, 4, modrm, lit, 5, unroll
|
|
dq lit, 5, unroll, reg64, unroll3, reg64, unroll3, scalefield, unroll3, sib
|
|
dq swap, pack8
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; reg/op field value (raw number)
|
|
; reg/mem field register name
|
|
defword addressing_reg8, 0
|
|
dq docol, reg8, lit, 3, unroll3, modrm, exit
|
|
|
|
; Stack:
|
|
; output point
|
|
defword cld, 0
|
|
dq docol, lit, 0xFC, pack8, exit
|
|
|
|
; Stack:
|
|
; output point
|
|
defword std, 0
|
|
dq docol, lit, 0xFD, pack8, exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; immediate value
|
|
; register name
|
|
defword mov_reg64_imm32, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0xC7, pack8, swap
|
|
dq lit, 0, swap, addressing_reg64
|
|
dq swap, pack32
|
|
dq 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 swap, reg64, swap, addressing_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword mov_indirect_reg64_reg64, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x89, pack8, unroll3
|
|
dq swap, reg64, swap, addressing_indirect_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
; target displacement value
|
|
defword mov_disp8_reg64_reg64, 0
|
|
dq docol
|
|
dq lit, 4, roll, rex_w, lit, 0x89, pack8, lit, 4, unroll
|
|
dq roll3, reg64, unroll3, addressing_disp8_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword mov_reg64_indirect_reg64, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x8B, pack8, unroll3
|
|
dq reg64, swap, addressing_indirect_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; source displacement value
|
|
; target register name
|
|
defword mov_reg64_disp8_reg64, 0
|
|
dq docol
|
|
dq lit, 4, roll, rex_w, lit, 0x8B, pack8, lit, 4, unroll
|
|
dq reg64, unroll3, addressing_disp8_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; source displacement value
|
|
; target register name
|
|
defword mov_reg64_disp32_reg64, 0
|
|
dq docol
|
|
dq lit, 4, roll, rex_w, lit, 0x89, pack8, lit, 4, unroll
|
|
dq roll3, reg64, swap, roll3, addressing_disp32_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source base register name
|
|
; source index register name
|
|
; source index scale factor, as a count of bytes
|
|
; target register name
|
|
defword mov_reg64_indexed_reg64, 0
|
|
dq docol
|
|
dq lit, 5, roll, rex_w, lit, 0x8B, pack8, lit, 5, unroll
|
|
dq reg64, lit, 4, unroll, unroll3, swap, addressing_indexed_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target base register name
|
|
; target index register name
|
|
; target index scale factor, as a count of bytes
|
|
defword mov_indexed_reg64_reg64, 0
|
|
dq docol
|
|
dq lit, 5, roll, rex_w, lit, 0x89, pack8, lit, 5, unroll
|
|
dq lit, 4, roll, reg64, lit, 4, unroll
|
|
dq unroll3, swap, addressing_indexed_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword mov_indirect_reg64_reg32, 0
|
|
dq docol
|
|
dq roll3, lit, 0x89, pack8, unroll3
|
|
dq swap, reg32, swap, addressing_indirect_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
; target displacement value
|
|
defword mov_disp8_reg64_reg32, 0
|
|
dq docol
|
|
dq lit, 4, roll, lit, 0x89, pack8, lit, 4, unroll
|
|
dq roll3, reg32, unroll3, addressing_disp8_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword mov_reg32_indirect_reg64, 0
|
|
dq docol
|
|
dq roll3, lit, 0x8B, pack8, unroll3
|
|
dq reg32, swap, addressing_indirect_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; source displacement value
|
|
; target register name
|
|
defword mov_reg32_disp8_reg64, 0
|
|
dq docol
|
|
dq lit, 4, roll, lit, 0x8B, pack8, lit, 4, unroll
|
|
dq reg32, unroll3, addressing_disp8_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword mov_indirect_reg64_reg16, 0
|
|
dq docol
|
|
dq roll3, lit, 0x66, pack8, lit, 0x89, pack8, unroll3
|
|
dq swap, reg16, swap, addressing_indirect_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
; target displacement value
|
|
defword mov_disp8_reg64_reg16, 0
|
|
dq docol
|
|
dq lit, 4, roll, lit, 0x66, pack8, lit, 0x89, pack8, lit, 4, unroll
|
|
dq roll3, reg16, unroll3, addressing_disp8_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword mov_reg16_indirect_reg64, 0
|
|
dq docol
|
|
dq roll3, lit, 0x66, pack8, lit, 0x8B, pack8, unroll3
|
|
dq reg16, swap, addressing_indirect_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; source displacement value
|
|
; target register name
|
|
defword mov_reg16_disp8_reg64, 0
|
|
dq docol
|
|
dq lit, 4, roll, lit, 0x66, pack8, lit, 0x8B, pack8, lit, 4, unroll
|
|
dq reg16, unroll3, addressing_disp8_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword mov_indirect_reg64_reg8, 0
|
|
dq docol
|
|
dq roll3, lit, 0x88, pack8, unroll3
|
|
dq swap, reg8, swap, addressing_indirect_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
; target displacement value
|
|
defword mov_disp8_reg64_reg8, 0
|
|
dq docol
|
|
dq lit, 4, roll, lit, 0x88, pack8, lit, 4, unroll
|
|
dq roll3, reg8, unroll3, addressing_disp8_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword mov_reg8_indirect_reg64, 0
|
|
dq docol
|
|
dq roll3, lit, 0x8A, pack8, unroll3
|
|
dq reg8, swap, addressing_indirect_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; source displacement value
|
|
; target register name
|
|
defword mov_reg8_disp8_reg64, 0
|
|
dq docol
|
|
dq lit, 4, roll, pack8, lit, 0x8A, pack8, lit, 4, unroll
|
|
dq reg8, unroll3, addressing_disp8_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword mov_reg8_reg8, 0
|
|
dq docol
|
|
dq roll3, lit, 0x88, pack8, unroll3
|
|
dq swap, reg8, swap, addressing_reg8
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; source displacement value
|
|
; target register name
|
|
defword lea_reg64_disp8_reg64, 0
|
|
dq docol
|
|
dq lit, 4, roll, rex_w, lit, 0x8D, pack8, lit, 4, unroll
|
|
dq reg64, unroll3, addressing_disp8_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; source displacement value
|
|
; target register name
|
|
defword lea_reg64_disp32_reg64, 0
|
|
dq docol
|
|
dq lit, 4, roll, rex_w, lit, 0x8D, pack8, lit, 4, unroll
|
|
dq reg64, unroll3, addressing_disp32_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source base register name
|
|
; source index register name
|
|
; source index scale factor, as a count of bytes
|
|
; target register name
|
|
defword lea_reg64_indexed_reg64, 0
|
|
dq docol
|
|
dq lit, 5, roll, rex_w, lit, 0x8D, pack8, lit, 5, unroll
|
|
dq reg64, lit, 4, unroll, unroll3, swap, addressing_indexed_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source base register name
|
|
; source index register name
|
|
; source index scale factor, as a count of bytes
|
|
; source displacement value
|
|
; target register name
|
|
defword lea_reg64_disp8_indexed_reg64, 0
|
|
dq docol
|
|
dq lit, 6, roll, rex_w, lit, 0x8D, pack8, lit, 6, unroll
|
|
dq reg64, lit, 5, unroll, lit, 3, roll, lit, 4, roll, lit, 3, roll
|
|
dq addressing_disp8_indexed_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
defword push_reg64, 0
|
|
dq docol, reg64, lit, 0x50, opcodereg, exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
defword push_extrareg64, 0
|
|
dq docol, swap, rex_b, swap, extrareg64, lit, 0x50, opcodereg, exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; target register name
|
|
defword pop_reg64, 0
|
|
dq docol, reg64, lit, 0x58, opcodereg, exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; target register name
|
|
defword pop_extrareg64, 0
|
|
dq docol, swap, rex_b, swap, extrareg64, lit, 0x58, opcodereg, exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; immediate value
|
|
defword push_imm32_extended64, 0
|
|
dq docol, swap, lit, 0x68, pack8, swap, pack32, exit
|
|
|
|
|
|
;;;
|
|
;;; String instructions
|
|
;;;
|
|
;;; What makes these useful is that they take their parameters from certain
|
|
;;; fixed registers, which are chosen such that the operations chain into each
|
|
;;; other well. Thus you can use them to build various block-memory and string
|
|
;;; operations, and even if you need unusual forms of loop unrolling or
|
|
;;; alignment tweaking, the code will end up uniform in structure. On modern
|
|
;;; processors, this is even the high-performance approach, due to highly
|
|
;;; optimized microcode, though these operations were inefficient when they
|
|
;;; were first invented.
|
|
;;;
|
|
;;; We break with the Intel mnemonics, which follow the pattern
|
|
;;; movsb/movsw/movsd/movsq, because this would otherwise be the only place we
|
|
;;; use the b/w/d/q thing instead of 8/16/32/64. Tradition and
|
|
;;; pronounceability are both nice things, but approachability to newcomers is
|
|
;;; important, too.
|
|
;;;
|
|
;;; Some of these are repeatable; whether you view the repeatable variants
|
|
;;; as different instructions is up to you. At any rate the machine code
|
|
;;; representation of the repeatable variants is the same as for the regular
|
|
;;; variants with an extra prefix, so we define them together.
|
|
;;;
|
|
;;; This is a proper superset of the flatassembler implementations of string
|
|
;;; instructions. The wisdom of that is questionable, but at least it's noted
|
|
;;; here...
|
|
|
|
; Stack:
|
|
; output point
|
|
defword movs8, 0
|
|
dq docol, lit, 0xA4, pack8, exit
|
|
defword movs16, 0
|
|
dq docol, lit, 0x66, pack8, lit, 0xA5, pack8, exit
|
|
defword movs32, 0
|
|
dq docol, lit, 0xA5, pack8, exit
|
|
defword movs64, 0
|
|
dq docol, rex_w, lit, 0xA5, pack8, exit
|
|
defword rep_movs8, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0xA4, pack8, exit
|
|
defword rep_movs16, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0x66, pack8, lit, 0xA5, pack8, exit
|
|
defword rep_movs32, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0xA5, pack8, exit
|
|
defword rep_movs64, 0
|
|
dq docol, lit, 0xF3, pack8, rex_w, lit, 0xA5, pack8, exit
|
|
|
|
; Stack:
|
|
; output point
|
|
defword lods8, 0
|
|
dq docol, lit, 0xAC, pack8, exit
|
|
defword lods16, 0
|
|
dq docol, lit, 0x66, pack8, lit, 0xAD, pack8, exit
|
|
defword lods32, 0
|
|
dq docol, lit, 0xAD, pack8, exit
|
|
defword lods64, 0
|
|
dq docol, rex_w, lit, 0xAD, pack8, exit
|
|
defword rep_lods8, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0xAC, pack8, exit
|
|
defword rep_lods16, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0x66, pack8, lit, 0xAD, pack8, exit
|
|
defword rep_lods32, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0xAD, pack8, exit
|
|
defword rep_lods64, 0
|
|
dq docol, lit, 0xF3, pack8, rex_w, lit, 0xAD, pack8, exit
|
|
|
|
; Stack:
|
|
; output pint
|
|
defword stos8, 0
|
|
dq docol, lit, 0xAA, pack8, exit
|
|
defword stos16, 0
|
|
dq docol, lit, 0x66, pack8, lit, 0xAB, pack8, exit
|
|
defword stos32, 0
|
|
dq docol, lit, 0xAB, pack8, exit
|
|
defword stos64, 0
|
|
dq docol, rex_w, lit, 0xAB, pack8, exit
|
|
defword rep_stos8, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0xAA, pack8, exit
|
|
defword rep_stos16, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0x66, pack8, lit, 0xAB, pack8, exit
|
|
defword rep_stos32, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0xAB, pack8, exit
|
|
defword rep_stos64, 0
|
|
dq docol, lit, 0xF3, pack8, rex_w, lit, 0xAB, pack8, exit
|
|
|
|
; Stack:
|
|
; output point
|
|
defword cmps8, 0
|
|
dq docol, lit, 0xA6, pack8, exit
|
|
defword cmps16, 0
|
|
dq docol, lit, 0x66, pack8, lit, 0xA7, pack8, exit
|
|
defword cmps32, 0
|
|
dq docol, lit, 0xA7, pack8, exit
|
|
defword cmps64, 0
|
|
dq docol, rex_w, lit, 0xA7, pack8, exit
|
|
defword repz_cmps8, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0xA6, pack8, exit
|
|
defword repz_cmps16, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0x66, pack8, lit, 0xA7, pack8, exit
|
|
defword repz_cmps32, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0xA7, pack8, exit
|
|
defword repz_cmps64, 0
|
|
dq docol, lit, 0xF3, pack8, rex_w, lit, 0xA7, pack8, exit
|
|
defword repnz_cmps8, 0
|
|
dq docol, lit, 0xF2, pack8, lit, 0xA6, pack8, exit
|
|
defword repnz_cmps16, 0
|
|
dq docol, lit, 0xF2, pack8, lit, 0x66, pack8, lit, 0xA7, pack8, exit
|
|
defword repnz_cmps32, 0
|
|
dq docol, lit, 0xF2, pack8, lit, 0xA7, pack8, exit
|
|
defword repnz_cmps64, 0
|
|
dq docol, lit, 0xF2, pack8, rex_w, lit, 0xA7, pack8, exit
|
|
|
|
; Stack:
|
|
; output point
|
|
defword scas8, 0
|
|
dq docol, lit, 0xAE, pack8, exit
|
|
defword scas16, 0
|
|
dq docol, lit, 0x66, pack8, lit, 0xAF, pack8, exit
|
|
defword scas32, 0
|
|
dq docol, lit, 0xAF, pack8, exit
|
|
defword scas64, 0
|
|
dq docol, rex_w, lit, 0xAF, pack8, exit
|
|
defword repz_scas8, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0xAE, pack8, exit
|
|
defword repz_scas16, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0x66, pack8, lit, 0xAF, pack8, exit
|
|
defword repz_scas32, 0
|
|
dq docol, lit, 0xF3, pack8, lit, 0xAF, pack8, exit
|
|
defword repz_scas64, 0
|
|
dq docol, lit, 0xF3, pack8, rex_w, lit, 0xAF, pack8, exit
|
|
defword repnz_scas8, 0
|
|
dq docol, lit, 0xF2, pack8, lit, 0xAE, pack8, exit
|
|
defword repnz_scas16, 0
|
|
dq docol, lit, 0xF2, pack8, lit, 0x66, pack8, lit, 0xAF, pack8, exit
|
|
defword repnz_scas32, 0
|
|
dq docol, lit, 0xF2, pack8, lit, 0xAF, pack8, exit
|
|
defword repnz_scas64, 0
|
|
dq docol, lit, 0xF2, pack8, rex_w, lit, 0xAF, pack8, exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword add_reg64_reg64, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x01, pack8, unroll3
|
|
dq swap, reg64, swap, addressing_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword add_indirect_reg64_reg64, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x01, pack8, unroll3
|
|
dq swap, reg64, swap, addressing_indirect_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword add_reg64_indirect_reg64, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x03, pack8, unroll3
|
|
dq reg64, swap, addressing_indirect_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source value
|
|
; target register name
|
|
defword add_reg64_imm8, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x83, pack8, swap, lit, 0, swap, addressing_reg64
|
|
dq swap, pack8
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword sub_reg64_reg64, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x2B, pack8, unroll3
|
|
dq reg64, swap, addressing_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword sub_indirect_reg64_reg64, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x2B, pack8, unroll3
|
|
dq swap, reg64, swap, addressing_indirect_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source value
|
|
; target register name
|
|
defword sub_reg64_imm8, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x83, pack8, swap, lit, 5, swap, addressing_reg64
|
|
dq swap, pack8
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source value
|
|
; target register name
|
|
defword sbb_reg64_imm8, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x83, pack8, swap, lit, 3, swap, addressing_reg64
|
|
dq swap, pack8
|
|
dq exit
|
|
|
|
; The target register is always rax.
|
|
;
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
defword mul_reg64, 0
|
|
dq docol
|
|
dq swap, rex_w, lit, 0xF7, pack8, swap
|
|
dq lit, 4, swap, addressing_reg64
|
|
dq exit
|
|
|
|
; The dividend is 128 bits, and is formed from rdx as the high half and rax
|
|
; as the low half. The divisor is a specified register. The quotient is
|
|
; returned in rax, truncated towards zero. The remainder is in rdx. This
|
|
; entire process is unsigned.
|
|
;
|
|
; The official mnemonic for this is "div", but divmod is what it does.
|
|
;
|
|
; Stack:
|
|
; output point
|
|
; divisor register name
|
|
defword divmod_reg64, 0
|
|
dq docol
|
|
dq swap, rex_w, lit, 0xF7, pack8, swap
|
|
dq lit, 6, swap, addressing_reg64
|
|
dq exit
|
|
|
|
; Same as divmod, but signed.
|
|
;
|
|
; Stack:
|
|
; output point
|
|
; divisor register name
|
|
defword idivmod_reg64, 0
|
|
dq docol
|
|
dq swap, rex_w, lit, 0xF7, pack8, swap
|
|
dq lit, 7, swap, addressing_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; target register name
|
|
defword inc_reg64, 0
|
|
dq docol
|
|
dq swap, rex_w, lit, 0xFF, pack8, swap, lit, 0, swap, addressing_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; target register name
|
|
defword dec_reg64, 0
|
|
dq docol
|
|
dq swap, rex_w, lit, 0xFF, pack8, swap, lit, 1, swap, addressing_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword and_reg64_reg64, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x23, pack8, unroll3
|
|
dq reg64, swap, addressing_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source value
|
|
; target register name
|
|
defword and_reg64_imm8, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x83, pack8, swap
|
|
dq lit, 4, swap, addressing_reg64
|
|
dq swap, pack8
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword or_reg64_reg64, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x0B, pack8, unroll3
|
|
dq reg64, swap, addressing_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source value
|
|
; target register name
|
|
defword or_reg64_imm8, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x83, pack8, swap
|
|
dq lit, 1, swap, addressing_reg64
|
|
dq swap, pack8
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; source register name
|
|
; target register name
|
|
defword xor_reg64_reg64, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x33, pack8, unroll3
|
|
dq reg64, swap, addressing_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; target register name
|
|
defword not_reg64, 0
|
|
dq docol
|
|
dq swap, rex_w, lit, 0xF7, pack8
|
|
dq swap, lit, 2, swap, addressing_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; left register name
|
|
; right register name
|
|
defword cmp_reg64_reg64, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x3B, pack8, unroll3
|
|
dq reg64, swap, addressing_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; left register name
|
|
; right register name
|
|
defword test_reg64_reg64, 0
|
|
dq docol
|
|
dq roll3, rex_w, lit, 0x85, pack8, unroll3
|
|
dq swap, reg64, swap, addressing_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; condition code name
|
|
; target register name
|
|
defword set_reg8_cc, 0
|
|
dq docol
|
|
dq roll3, lit, 0x0F, pack8
|
|
dq roll3, conditioncode, lit, 0x90, opcodecc
|
|
dq swap, reg8, lit, 3, lit, 0, roll3, modrm
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; address offset value
|
|
; condition code name
|
|
defword jmp_cc_rel_imm8, 0
|
|
dq docol
|
|
dq roll3, swap, conditioncode, lit, 0x70, opcodecc
|
|
dq swap, pack8
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; address offset value
|
|
; condition code name
|
|
defword jmp_cc_rel_imm32, 0
|
|
dq docol
|
|
dq unroll3, lit, 0x0F, pack8
|
|
dq swap, conditioncode, lit, 0x70, opcodecc
|
|
dq swap, pack32
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; register name
|
|
defword jmp_abs_indirect_reg64, 0
|
|
dq docol
|
|
dq swap, lit, 0xFF, pack8, swap
|
|
dq lit, 4, swap, addressing_indirect_reg64
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; address offset value
|
|
defword jmp_rel_imm8, 0
|
|
dq docol
|
|
dq swap, lit, 0xEB, pack8
|
|
dq swap, pack8
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
; address offset value
|
|
defword jmp_rel_imm32, 0
|
|
dq docol
|
|
dq swap, lit, 0xE9, pack8
|
|
dq swap, pack32
|
|
dq exit
|
|
|
|
; Stack:
|
|
; output point
|
|
defword syscall, 0
|
|
dq docol, lit, 0x0F, pack8, lit, 0x05, pack8, exit
|
|
|
|
; Stack:
|
|
; output point
|
|
defword hlt, 0
|
|
dq docol, lit, 0xF4, pack8, exit
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;; Runtime word definition ;;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; We need to be able to use Forth code that defines other Forth code; it
|
|
;;; will be the easiest way to create our Forth-flavored assembly languge. To
|
|
;;; do that, there's a critical bootstrapping problem: The variables that we
|
|
;;; allocate on the heap in _start must be used by the Forth words that define
|
|
;;; other Forth words (and, in general, they are needed for anything that
|
|
;;; does memory management). Since the heap's address isn't known until
|
|
;;; runtime, we can't use build-time labels to locate the heap or the
|
|
;;; variables on it, in the way we've done for everything up to now.
|
|
;;;
|
|
;;; In fact, it's worse than that: nothing we define at build time can
|
|
;;; statically reference anything on the heap; it must always be given the
|
|
;;; heap's address as a parameter. That also means statically defined words
|
|
;;; can't reference runtime words, at all, except via special code that goes
|
|
;;; outside the normal Forth execution model.
|
|
;;;
|
|
;;; So, what we'll want to do to deal with that is copy ourselves onto the
|
|
;;; heap, and run the rest of the program from there. It would be okay in
|
|
;;; principle to keep a few things such as docol in the static code segment,
|
|
;;; as long as they don't need to reference the heap, though it might in some
|
|
;;; sense be more elegant to entirely abandon the code segment and run
|
|
;;; heap-only. At any rate, to keep the set of stuff we have to copy small,
|
|
;;; we'll want to make the change-over as soon as possible.
|
|
;;;
|
|
;;; Following a common Forth practice, we implement variables as words that
|
|
;;; push the corresponding addresses onto the stack. Since the variables that
|
|
;;; define the heap are ON the heap, we will definitely need two distinct
|
|
;;; versions of these; having the two versions be almost-compatible allows us
|
|
;;; to minimize code duplication. Since they do have slightly different
|
|
;;; interfaces, we prefix the names of the early ones with "early_".
|
|
|
|
; First, we have some words that follow the pack* idioms and are used to
|
|
; build specific assembly-based constructs needed in word implementations.
|
|
; You can think of them as macros. They are in a sense reimplementations of
|
|
; their flatassembler equivalents, which are far, far above, and have more
|
|
; documentation.
|
|
;
|
|
; Stack in:
|
|
; base address
|
|
; Stack out:
|
|
; new base address
|
|
defword pack_next, 0
|
|
dq docol, lods64, rax, jmp_abs_indirect_reg64, exit
|
|
|
|
; This is another helper "macro" that we'll use in defining assembly words
|
|
; from Forth. As before, see the flatassembler version for more explanation.
|
|
;
|
|
; Stack in:
|
|
; base address
|
|
; destination address (absolute)
|
|
; Stack out:
|
|
; new base address
|
|
defword pack_beforenext, 0
|
|
dq docol, rax, mov_reg64_imm64, rax, jmp_abs_indirect_reg64, exit
|
|
|
|
; This is another helper "macro" that we'll use in defining assembly words
|
|
; from Forth. In particular, this one is used in docol. As before, see the
|
|
; flatassembler version for more explanation.
|
|
;
|
|
; Stack in:
|
|
; base address
|
|
; source register keyword
|
|
; Stack out:
|
|
; new base address
|
|
defword pack_pushcontrol, 0
|
|
dq docol
|
|
dq swap, rbp, lit, -8, rbp, lea_reg64_disp8_reg64, swap
|
|
dq rbp, lit, 0, mov_disp8_reg64_reg64
|
|
dq exit
|
|
|
|
; This is another helper "macro" that we'll use in defining assembly words
|
|
; from Forth. In particular, this one is used in "exit". See the flatassembler
|
|
; version for more explanation.
|
|
;
|
|
; Stack in:
|
|
; base address
|
|
; target register keyword
|
|
; Stack out:
|
|
; new base address
|
|
defword pack_popcontrol, 0
|
|
dq docol
|
|
dq rbp, lit, 0, roll3, mov_reg64_disp8_reg64
|
|
dq rbp, lit, 8, rbp, lea_reg64_disp8_reg64
|
|
dq exit
|
|
|
|
; Now, we have a bunch of words that are used for traversing the Forth
|
|
; core data structures that describe words. First, we have a couple that
|
|
; relate to individual words and their pieces...
|
|
;
|
|
; Jonesforth calls this "TFCA" and ">CFA"; its author speculates that the
|
|
; original meaning is "code field address".
|
|
defword entry_to_execution_token, 0
|
|
dq docol
|
|
; Skip next-entry pointer, flag byte, and start terminator.
|
|
dq lit, 10, add
|
|
; Skip string contents.
|
|
dq dup, stringlen, add
|
|
; Skip one for the null terminator, seven more for alignment.
|
|
dq lit, 8, add
|
|
; Zero the low bits and now it's aligned.
|
|
dq lit, 7, invert, and
|
|
dq exit
|
|
|
|
; Jonesforth calls this "CFA>". Jonesforth's implementation searches the
|
|
; entire dictionary, since its word header format isn't designed to be
|
|
; traversed in reverse, but ours is, so it should be fast.
|
|
defword execution_token_to_entry, 0
|
|
dq docol
|
|
dq lit, 1, sub
|
|
dq dup, reverse_padding_len, sub
|
|
dq dup, reverse_stringlen, sub
|
|
dq lit, 9, sub
|
|
dq exit
|
|
|
|
; Stack in:
|
|
; entry address
|
|
; Stack out:
|
|
; flags byte
|
|
defword fetch_entry_flags, 0
|
|
dq docol
|
|
dq lit, 8, add, fetch, lit, 0xFF, and
|
|
dq exit
|
|
|
|
; Stack in:
|
|
; entry address
|
|
; flags byte
|
|
defword store_entry_flags, 0
|
|
dq docol
|
|
dq swap, lit, 8, add, dup, fetch
|
|
; (new flags byte, address of flags byte, old flags byte + context)
|
|
dq roll3, lit, 0xFF, and
|
|
dq swap, lit, 0xFFFFFFFFFFFFFF00, and, or
|
|
dq swap, store
|
|
dq exit
|
|
|
|
defword entry_to_name, 0
|
|
dq docol
|
|
dq lit, 10, add
|
|
dq exit
|
|
|
|
; Now, having finished with individual words, we have a bunch of stuff that
|
|
; traverses the overall dictionary structure, which is formed by a linked list
|
|
; using the pointer that each word starts with.
|
|
;
|
|
; This one is the backend for early_find_in; it will eventually also be the
|
|
; backend for a non-early version.
|
|
;
|
|
; Stack in:
|
|
; dictionary to search within
|
|
; name string to find
|
|
; Stack out:
|
|
; execution token or 0
|
|
defword find_in, 0
|
|
dq docol
|
|
; It will be more convenient to have the dictionary pointer on top.
|
|
dq swap
|
|
|
|
; If the dictionary pointer is null, exit.
|
|
; (name string to find, current word pointer)
|
|
dq dup, lit, 0, eq, zbranch, 4*8, swap, drop, exit
|
|
|
|
; Check this entry's "hidden" flag.
|
|
; (name string to find, current word pointer)
|
|
dq dup, fetch_entry_flags, lit, 0x80, and, lit, 0x80, ne, zbranch, 8*8
|
|
|
|
; Test whether this entry is a match.
|
|
; (name string to find, current word pointer)
|
|
dq dup2, lit, 10, add, stringcmp, zbranch, 4*8
|
|
|
|
; If we're here, it's not a match; traverse the pointer and repeat.
|
|
; (name string to find, current word pointer)
|
|
dq fetch, branch, -28*8
|
|
|
|
; If we're here, it's a match. Clean up our working state and exit.
|
|
; (name string to find, current word pointer)
|
|
dq swap, drop, exit
|
|
|
|
; This is the backend for early_next_newer_entry_in; it will eventually also
|
|
; be the backend for a non-early version.
|
|
;
|
|
; This returns zero if the entry isn't found at all.
|
|
;
|
|
; Stack in:
|
|
; dictionary to search within
|
|
; entry address
|
|
; Stack out:
|
|
; entry address or 0
|
|
defword next_newer_entry_in, 0
|
|
dq docol
|
|
; Dictionary pointer on top
|
|
dq swap
|
|
; Exit if null
|
|
dq dup, lit, 0, eq, zbranch, 4*8, swap, drop, exit
|
|
; Test if it's a match
|
|
dq dup2, fetch, ne, zbranch, 4*8
|
|
; Non-match case; loop
|
|
dq fetch, branch, -16*8
|
|
; Match case; return
|
|
dq swap, drop, exit
|
|
|
|
; This is the backend for early_guess_entry_end; it will eventually also be
|
|
; the backend for a non-early version.
|
|
;
|
|
; Stack in:
|
|
; "here" value
|
|
; dictionary to search within
|
|
; entry address
|
|
; Stack out:
|
|
; next entry address or 0
|
|
defword guess_entry_end_in, 0
|
|
dq docol
|
|
; Check whether the entry is flagged as metadata...
|
|
dq dup, fetch_entry_flags, lit, 0x40, and, lit, 0x40, eq, zbranch, 6*8
|
|
; ... if so, return the same entry address as the result, which means we're
|
|
; saying the length is zero.
|
|
dq swap, drop, swap, drop, exit
|
|
; If not, search backwards from the end to find the following entry.
|
|
; (here, original entry address)
|
|
dq dup, unroll3
|
|
; (original entry address, here, original entry address)
|
|
dq next_newer_entry_in
|
|
; (original entry address, here, next entry address or 0)
|
|
|
|
; Check whether we were able to find the next-entry address.
|
|
dq dup, lit, 0, eq, zbranch, 4*8
|
|
|
|
; This is the branch where the original entry is not in the list. Return
|
|
; the original entry address as the result; as above, this means we're
|
|
; saying the length is zero. Since we don't have anything else to go on,
|
|
; this is the safe assumption.
|
|
dq drop, drop, exit
|
|
|
|
; This is the branch where we found it. Return the next entry address.
|
|
dq swap, drop, swap, drop, exit
|
|
|
|
; That's it for the code that traverses the dictionary; now we have some
|
|
; code meant for use in debugging, which prints out the contents of individual
|
|
; words' bodies.
|
|
;
|
|
; This one is the backend for early_show_hex; it will eventually also be the
|
|
; backend for a non-early version.
|
|
;
|
|
; Stack in:
|
|
; entry address
|
|
; end address
|
|
defword show_hex_between, 0
|
|
dq docol
|
|
dq swap, entry_to_execution_token, lit, 8, add
|
|
; (end address, current address)
|
|
dq dup2, ge, zbranch, 4*8, drop, drop, exit
|
|
dq litstring, " ", emitstring
|
|
dq dup, fetch, dothex64
|
|
dq lit, 8, add
|
|
dq branch, -17*8
|
|
|
|
; This one "decompiles" a Forth word, printing the names of the codewords it
|
|
; consists of. It also understands all the built-in literal-related words, and
|
|
; serves as an example of how to do that.
|
|
;
|
|
; This is the backend for early_show_source; it will eventually also be the
|
|
; backend for a non-early version.
|
|
;
|
|
; Stack in:
|
|
; entry address
|
|
; end address
|
|
defword show_source_between, 0
|
|
dq docol
|
|
|
|
dq swap, entry_to_execution_token, lit, 8, add
|
|
; (end address, current address)
|
|
|
|
; This is the start of the loop.
|
|
;
|
|
; If it's zero-length, don't try to print its contents.
|
|
dq dup2, ge, zbranch, 4*8, drop, drop, exit
|
|
|
|
; If it's not a word address, the fetch will segfault. We accept this.
|
|
dq dup, fetch, execution_token_to_entry, entry_to_name
|
|
|
|
; (end address, current address, name)
|
|
|
|
dq litstring, " ", emitstring
|
|
dq dup, emitstring
|
|
dq swap, lit, 8, add, swap
|
|
|
|
dq dup, litstring, "lit", stringcmp, zbranch, 57*8 ; 6 words
|
|
dq dup, litstring, "litpack8", 0, stringcmp, zbranch, 50*8 ; 7 words
|
|
dq dup, litstring, "litpack16", stringcmp, zbranch, 43*8 ; 7 words
|
|
dq dup, litstring, "litpack32", stringcmp, zbranch, 36*8 ; 7 words
|
|
dq dup, litstring, "litpack64", stringcmp, zbranch, 29*8 ; 7 words
|
|
dq dup, litstring, "branch", stringcmp, zbranch, 23*8 ; 6 words
|
|
dq dup, litstring, "zbranch", stringcmp, zbranch, 17*8 ; 6 words
|
|
dq dup, litstring, "0branch", stringcmp, zbranch, 11*8 ; 6 words
|
|
dq dup, litstring, "litstring", stringcmp, zbranch, 16*8 ; 7 words
|
|
|
|
; This is the plain, non-lit branch.
|
|
dq drop, branch, -82*8
|
|
|
|
; This is the lit branch that expects to be followed by a single word.
|
|
dq litstring, " ", emitstring
|
|
dq drop, dup, fetch, dot
|
|
dq lit, 8, add
|
|
dq branch, -94*8
|
|
|
|
; This is the lit branch that expects to be followed by a string. First, we
|
|
; print the string...
|
|
dq drop
|
|
dq litstring, " ", emitstring
|
|
dq lit, 0x22, fetch_value_stack, emitstring, drop
|
|
dq dup, emitstring
|
|
dq lit, 0x22, fetch_value_stack, emitstring, drop
|
|
|
|
; ... then, we skip the string.
|
|
;
|
|
; We always add a word as padding. If the length is a multiple of 8, this is
|
|
; the zero word following the contents. If it's not, the division rounds
|
|
; down so the padding word has the tail of the contents in it too.
|
|
dq dup, stringlen, lit, 8, divmod, swap, drop, lit, 1, add
|
|
; (end address, current address, n words including padding)
|
|
dq lit, 8, mul, add
|
|
|
|
dq branch, -126*8
|
|
|
|
; This is the backend for early_show_source_or_hex; it will eventually also
|
|
; be the backend for a non-early version.
|
|
;
|
|
; Stack in:
|
|
; entry address
|
|
; end address
|
|
defword show_source_or_hex_between, 0
|
|
dq docol
|
|
|
|
; If it's zero-length, don't try to print its contents.
|
|
dq dup2, eq, zbranch, 2*8, exit
|
|
|
|
dq swap, dup, unroll3, swap, roll3
|
|
; (entry address, end address, entry address)
|
|
dq entry_to_execution_token, dup, fetch, lit, 8, sub, eq, zbranch, 3*8
|
|
dq show_hex_between, exit
|
|
dq show_source_between, exit
|
|
|
|
|
|
;;;;;;;;;;;;;;
|
|
;;; Lexing ;;;
|
|
;;;;;;;;;;;;;;
|
|
|
|
|
|
; In:
|
|
; next input address
|
|
; Out:
|
|
; next input address (updated)
|
|
; input byte
|
|
defword key, 0
|
|
dq docol
|
|
dq dup, dup, lit, -8, and, fetch, swap, lit, 7, and
|
|
; (next input address, 64-bit input word, byte index within word)
|
|
dq dup, zbranch, 13*8
|
|
dq lit, 1, sub, swap, lit, 256, divmod, swap, drop, swap, branch, -14*8
|
|
dq drop, lit, 0xFF, and
|
|
dq swap, lit, 1, add, swap
|
|
dq exit
|
|
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;; Heap bootstrapping ;;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; Now, we have a little more work to do before we can bootstrap the heap.
|
|
;;; We have all these early_* words which rely on being told explicitly where
|
|
;;; the heap is, most of them pertaining to defining words at runtime. Once
|
|
;;; the heap exists, these won't be needed, so we never actually copy them to
|
|
;;; the heap. To make sure that's easy to keep track of, they're all together
|
|
;;; at the end here.
|
|
;;;
|
|
;;; The goal is that none of these do any particularly interesting work,
|
|
;;; instead deferring to implementations defined in other sections that will
|
|
;;; be re-used by the later, fully-bootstrapped stuff. At the moment, some of
|
|
;;; them still do interesting things; it's a work in progress.
|
|
|
|
; Stack in:
|
|
; heap address
|
|
; Stack out:
|
|
; heap address
|
|
; requested variable address
|
|
defword early_heap, 0
|
|
dq docol, dup, lit, control_stack_size, add, exit
|
|
defword early_s0, 0
|
|
dq docol, early_heap, lit, 8, add, exit
|
|
defword early_r0, 0
|
|
dq docol, early_heap, lit, 16, add, exit
|
|
defword early_latest, 0
|
|
dq docol, early_heap, lit, 24, add, exit
|
|
defword early_here, 0
|
|
dq docol, early_heap, lit, 32, add, exit
|
|
|
|
; Stack in:
|
|
; heap address
|
|
; name string to find
|
|
; Stack out:
|
|
; heap address
|
|
; execution token or 0
|
|
defword early_find, 0
|
|
dq docol, swap, early_latest, fetch, swap, unroll3, swap, find_in, exit
|
|
|
|
; Stack in:
|
|
; heap address
|
|
; entry address
|
|
; Stack out:
|
|
; heap address
|
|
; entry address or 0
|
|
defword early_next_newer_entry, 0
|
|
dq docol
|
|
dq swap, early_latest, fetch, swap, unroll3, swap, next_newer_entry_in
|
|
dq exit
|
|
|
|
; This doesn't work on the entry at the end of the ELF .text segment. It does
|
|
; work on everything else.
|
|
; Stack in:
|
|
; heap address
|
|
; entry address
|
|
; Stack out:
|
|
; heap address
|
|
; guessed entry end address (first byte that's not part of it)
|
|
defword early_guess_entry_end, 0
|
|
dq docol
|
|
dq swap, early_here, fetch, swap, early_latest, fetch, swap
|
|
; (entry, here, latest, heap)
|
|
dq lit, 4, unroll, roll3
|
|
; (heap, here, latest, entry)
|
|
dq guess_entry_end_in
|
|
dq exit
|
|
|
|
; Stack in:
|
|
; heap address
|
|
; entry address
|
|
; Stack out:
|
|
; heap address
|
|
defword early_show_hex, 0
|
|
dq docol
|
|
dq dup, unroll3, early_guess_entry_end, swap, unroll3
|
|
; (heap address, entry address, end address)
|
|
dq show_hex_between
|
|
dq exit
|
|
|
|
; Stack in:
|
|
; heap address
|
|
; entry address
|
|
; Stack out:
|
|
; heap address
|
|
defword early_show_source, 0
|
|
dq docol
|
|
dq dup, unroll3, early_guess_entry_end, swap, unroll3
|
|
; (heap address, entry address, end address)
|
|
dq show_source_between
|
|
dq exit
|
|
|
|
; Stack in:
|
|
; heap address
|
|
; entry address
|
|
; Stack out:
|
|
; heap address
|
|
defword early_show_source_or_hex, 0
|
|
dq docol
|
|
dq dup, unroll3, early_guess_entry_end, swap, unroll3
|
|
; (heap address, entry address, end address)
|
|
dq show_source_or_hex_between
|
|
dq exit
|
|
|
|
; Stack in:
|
|
; heap address
|
|
; entry address
|
|
; Stack out:
|
|
; heap address
|
|
defword early_describe, 0
|
|
dq docol
|
|
dq litstring, 0x0a, emitstring
|
|
dq dup, dothex64
|
|
dq litstring, 0x0a, emitstring
|
|
dq dup, entry_to_name, emitstring, litstring, ":", emitstring
|
|
dq litstring, 0x0a, emitstring
|
|
dq litstring, " ", emitstring
|
|
dq early_show_source_or_hex
|
|
dq litstring, 0x0a, emitstring
|
|
dq exit
|
|
|
|
; Stack in:
|
|
; heap address
|
|
defword early_describe_all, 0
|
|
dq docol
|
|
dq early_latest
|
|
dq dup, lit, 0, eq, zbranch, 3*8, drop, exit
|
|
; Start of the loop
|
|
dq fetch
|
|
dq dup, lit, 0, eq, zbranch, 3*8, drop, exit
|
|
dq dup2, early_describe, drop
|
|
dq branch, -13*8
|
|
dq exit
|
|
|
|
; Allocate space by incrementing "here", and output a word header in it.
|
|
; Also add it to the "latest" linked list. Use zero as the flag values;
|
|
; callers that want something else can do that themselves.
|
|
;
|
|
; We'll use the pack* words to do this, the way they update the pointer is
|
|
; convenient.
|
|
;
|
|
; See "Execution model", above, for reminders of the details of this format.
|
|
; Create is responsible for everything up to the codeword, not including it.
|
|
;
|
|
; This is surprisingly painful to implement, in terms of stack juggling, but
|
|
; then there's a sense in which it's the core trick to bootstrapping the heap.
|
|
;
|
|
; Stack in:
|
|
; heap address
|
|
; name string
|
|
; Stack out:
|
|
; heap address
|
|
defword early_create, 0
|
|
dq docol
|
|
; Retrieve the values of "here" and "latest".
|
|
dq swap, early_here, fetch, swap, early_latest, fetch, swap, lit, 4, unroll
|
|
; Pack the old value of "latest" as the first field of the header, linking
|
|
; from the newly-defined word to the next-newest word.
|
|
dq pack64
|
|
; Pack a null byte as the flags.
|
|
dq lit, 0, pack8
|
|
; Pack another null byte as the start terminator of the name (which is
|
|
; terminated at both ends).
|
|
dq lit, 0, pack8
|
|
; Pack the name and its end terminator.
|
|
dq swap, packstring
|
|
; Alignment before the codeword.
|
|
dq lit, 8, packalign
|
|
; Retrieve the value of "here" (which still doesn't reflect our additions),
|
|
; and store it at the address of "latest". It's the start of our
|
|
; newly-defined word, which makes it the latest word.
|
|
dq swap, early_here, fetch, swap, early_latest, swap, unroll3, store, swap
|
|
; Retrieve the address of "here" again and store our updated value there.
|
|
dq swap, early_here, swap, unroll3, store
|
|
dq exit
|
|
|
|
; Stack in:
|
|
; heap address
|
|
; value to append to current word-in-progress
|
|
; Stack out:
|
|
; heap address
|
|
defword early_comma, 0
|
|
dq docol
|
|
; Retrieve the value of "here" and pack the value there.
|
|
dq swap, early_here, fetch, swap, unroll3, swap, pack64
|
|
; Store the updated value of "here".
|
|
dq swap, early_here, swap, unroll3, store
|
|
dq exit
|
|
|
|
; Stack in:
|
|
; heap address
|
|
; Stack out:
|
|
; heap address
|
|
defword early_self_codeword, 0
|
|
dq docol, early_here, fetch, lit, 8, add, early_comma, exit
|
|
|
|
; Stack in:
|
|
; heap address
|
|
; Stack out:
|
|
; heap address
|
|
defword early_docol_codeword, 0
|
|
dq docol
|
|
dq litstring, "docol", early_find
|
|
dq entry_to_execution_token, execute, early_comma
|
|
dq exit
|
|
|
|
; Stack in:
|
|
; heap address
|
|
; new value to overwrite "here"
|
|
; Stack out:
|
|
; heap address
|
|
defword early_here_store, 0
|
|
dq docol, swap, early_here, swap, unroll3, store, exit
|
|
|
|
; Stack in:
|
|
; heap address
|
|
; address for new variable word to return
|
|
; name string
|
|
; Stack out:
|
|
; heap address
|
|
defword early_variable, 0
|
|
dq docol
|
|
dq swap, unroll3, early_create, early_self_codeword
|
|
; (address to return, heap address)
|
|
dq early_here, fetch, swap, unroll3, swap
|
|
; (heap address, modified "here" value, address to return)
|
|
dq rax, mov_reg64_imm64, rax, push_reg64
|
|
; (heap address, modified "here" value)
|
|
dq pack_next, lit, 8, packalign, early_here_store
|
|
dq exit
|
|
|
|
; Stack in:
|
|
; heap address
|
|
; name string
|
|
; Stack out:
|
|
; heap address
|
|
defword early_keyword, 0
|
|
dq docol
|
|
dq early_create, early_here, fetch, swap
|
|
; (self codeword address, heap address)
|
|
dq early_docol_codeword
|
|
dq litstring, "lit", early_find, entry_to_execution_token, early_comma
|
|
dq swap, early_comma
|
|
; (heap address)
|
|
dq litstring, "exit", early_find, entry_to_execution_token, early_comma
|
|
dq early_here, fetch, lit, 8, packalign, early_here_store
|
|
dq exit
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;; Now.... what was our original goal, again? ;;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; Finally, having fully bootstrapped our runtime environment, we move on
|
|
;;; to the core stuff we actually want to accomplish. For this quine, that's
|
|
;;; outputting itself.
|
|
|
|
;;;
|
|
;;; One of the most charming naming traditions in Forth is that the
|
|
;;; top-level word that stays running forever, is called "quit".
|
|
;;;
|
|
defword quit, 0
|
|
dq docol
|
|
|
|
;;;
|
|
;;; Although we initialized rbp already, we do so again because we'll want
|
|
;;; that on subsequent visits to this word - it's the main thing it's for.
|
|
;;; Keep in mind that rsi is the actual "instruction pointer", and we're
|
|
;;; leaving it unchanged, we just get rid of everything above it.
|
|
;;;
|
|
;dq r0, control! ; overwrite rbp to reset the control stack
|
|
; TODO though the implementation of r0 is trivial, it depends on where we
|
|
; put the heap, so it can't be hardcoded, we'll have to build it in RAM.
|
|
; the same therefore goes for anything that needs to call it. so we can't
|
|
; call it here, now, yet - we have prep work to do first
|
|
|
|
;;;
|
|
;;; Do the read-eval-print-loop, which is the main body of the Forth
|
|
;;; interpreter.
|
|
;;;
|
|
;dq interpret ; run the repl
|
|
dq quine
|
|
|
|
;;;
|
|
;;; If the repl ever exits, do it all again.
|
|
;;;
|
|
;dq branch, quit - $
|
|
dq lit, 0, sys_exit
|
|
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;; (new) Implementation strategy ;;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;
|
|
;;; We assemble the entire file contents in a heap-allocated buffer. When
|
|
;;; the file is fully assembled, we output it.
|
|
;;;
|
|
defword quine, 0
|
|
dq docol
|
|
|
|
; We still have "heap" on the stack, so we can call early_here. Add a
|
|
; constant to "here" in-place, keeping a copy of the pointer ...
|
|
dq early_here, lit, 0x78, swap, addstore
|
|
; ... and now we have allocated a block of memory, with its address on the
|
|
; stack. We also still have "heap" at the bottom of the stack, for future
|
|
; use.
|
|
|
|
; We have one label, and two pieces of information about it: value and
|
|
; status. We keep them on the stack. We also have a mutable copy of the
|
|
; buffer's address.
|
|
;
|
|
; This stack layout is the interface used throughout the "assembler"; this
|
|
; quine routine uses it when calling the routines that build the various
|
|
; pieces of the output, and those pieces in turn use it when calling the
|
|
; label-handling routines.
|
|
;
|
|
; Stack:
|
|
; "heap"
|
|
; start address of allocated output
|
|
; label's value
|
|
; label's status
|
|
; address of current output point within allocated block
|
|
; (top)
|
|
;
|
|
; Status is a bit field:
|
|
; bit zero is whether it was used before being defined
|
|
; bit one is whether it's been defined
|
|
; bit two is whether the guessed value wound up equaling the actual value
|
|
dq dup, lit, 0, lit, 0, roll3
|
|
|
|
; This takes an address to write to on the stack, writes stuff there, and
|
|
; returns the next address after where it stopped Writing.
|
|
dq all_contents
|
|
|
|
; The two-pass magick: ; Reset the output offset to the beginning of the
|
|
; block.
|
|
dq drop, roll3, dup, lit, 4, unroll
|
|
dq all_contents
|
|
|
|
; Drop the copy of the buffer's address.
|
|
dq drop
|
|
|
|
; Drop the label data.
|
|
dq drop, drop
|
|
|
|
; This takes a buffer's address on the stack, skips an ELF file header and
|
|
; program header based on hardcoded size, computes an offset (secretly
|
|
; hardcoded), and writes that offset into an appopriate place in the middle
|
|
; of those headers. It then returns the length of the used portion of the
|
|
; buffer.
|
|
;dq lit, 0x78, swap
|
|
dq lit, file_size, swap
|
|
|
|
; write() from stack-allocated buffer
|
|
dq sys_write
|
|
|
|
dq exit
|
|
|
|
; Stack in:
|
|
; output memory start
|
|
; label value (guessed or actual)
|
|
; label status
|
|
; output memory current point
|
|
; Stack out:
|
|
; output memory start
|
|
; label value (guessed or actual)
|
|
; label status (potentially modified)
|
|
; output memory current point
|
|
; label value for caller to use
|
|
defword use_label, 0
|
|
dq docol
|
|
|
|
; Fetch the status
|
|
dq swap
|
|
; Check the bit that indicates it's been set.
|
|
dq dup, lit, 2, and, zbranch, 10*8
|
|
|
|
; If we're here, it has been set already, so just put the status back...
|
|
dq swap
|
|
; Fetch the actual value...
|
|
dq lit, 3, roll, dup, lit, 4, unroll
|
|
; ... and exit
|
|
dq exit
|
|
|
|
; If we're here, it hasn't been set yet, so mark it used-before-set.
|
|
dq lit, 1, or
|
|
; Put the status back...
|
|
dq swap
|
|
; Fetch the guessed value...
|
|
dq lit, 3, roll, dup, lit, 4, unroll
|
|
; ... and exit
|
|
dq exit
|
|
|
|
; Stack in:
|
|
; output memory start
|
|
; label value (guessed or actual)
|
|
; label status
|
|
; output memory current point
|
|
; Stack out:
|
|
; output memory start
|
|
; label value (now set to actual)
|
|
; label status (modified)
|
|
; output memory current point
|
|
defword set_label, 0
|
|
dq docol
|
|
|
|
; Compute the current offset, to use as the actual value
|
|
dq dup, lit, 5, roll, dup, lit, 6, unroll, sub
|
|
; old value, status, point, new value
|
|
|
|
; Overwrite the old actual value; keep a copy
|
|
dq dup, lit, 5, roll
|
|
; status, point, new value, new value, old value
|
|
dq eq, swap
|
|
; status, point, equality, new value
|
|
dq lit, 4, unroll
|
|
; new value, status, point, equality
|
|
|
|
; We don't need to branch. Now we mark the status as having been defined,
|
|
; and we also set bit 2 if appropriate.
|
|
dq lit, 4, mul
|
|
dq lit, 3, roll, or, lit, 2, or, swap
|
|
|
|
dq exit
|
|
|
|
|
|
; This takes an address to write to on the stack, writes stuff there, and
|
|
; returns the next address after where it stopped Writing.
|
|
;
|
|
; It also makes use of label stuff, further back on the stack.
|
|
defword all_contents, 0
|
|
dq docol
|
|
dq elf_file_header, elf_program_header
|
|
dq output_start_routine
|
|
dq self_raw
|
|
dq set_label
|
|
dq exit
|
|
|
|
;;;
|
|
;;; ELF header
|
|
;;;
|
|
;;; This is the top-level ELF header, for the entire file. An ELF always has
|
|
;;; exactly one of this header, which is always at the start of the file.
|
|
;;;
|
|
defword elf_file_header, 0
|
|
dq docol
|
|
|
|
dq litpack32, 0x7f bappend "ELF" ; magic number
|
|
dq litpack8, 2 ; 64-bit
|
|
dq litpack8, 1 ; little-endian
|
|
dq litpack8, 1 ; ELF header format v1
|
|
dq litpack8, 0 ; System-V ABI
|
|
dq litpack64, 0 ; (padding)
|
|
|
|
dq litpack16, 2 ; executable
|
|
dq litpack16, 0x3e ; Intel x86-64
|
|
dq litpack32, 1 ; ELF format version
|
|
|
|
; Compute the entry pointer.
|
|
dq litpack64, _start ; entry point
|
|
; The offset of _start. This includes the origin, intentionally.
|
|
|
|
dq litpack64, 64 ; program header offset
|
|
; We place the program header immediately after the ELF header. This
|
|
; offset is from the start of the file.
|
|
dq litpack64, 0 ; section header offset
|
|
dq litpack32, 0 ; processor flags
|
|
dq litpack16, 64 ; ELF header size
|
|
dq litpack16, 56 ; program header entry size
|
|
dq litpack16, 1 ; number of program header entries
|
|
dq litpack16, 0 ; section header entry size
|
|
dq litpack16, 0 ; number of section header entries
|
|
dq litpack16, 0 ; section name string table index
|
|
|
|
dq exit
|
|
|
|
|
|
;;;
|
|
;;; Program header
|
|
;;;
|
|
;;; An ELF program header consists of any number of these entries; they are
|
|
;;; always consecutive, but may be anywhere in the file. We always have
|
|
;;; exactly one, and it's always right after the ELF file header.
|
|
;;;
|
|
defword elf_program_header, 0
|
|
dq docol
|
|
|
|
dq litpack32, 1 ; "loadable" segment type
|
|
dq litpack32, 0x05 ; read+execute permission
|
|
dq litpack64, 0 ; offset in file
|
|
dq litpack64, $$ ; virtual address
|
|
; required, but can be anything, subject to alignment
|
|
dq litpack64, 0 ; physical address (ignored)
|
|
|
|
; Fill in 0 as the file size for now, to avoid unitialized memory.
|
|
dq use_label, pack64 ; size in file
|
|
dq use_label, pack64 ; size in memory
|
|
|
|
dq litpack64, 0 ; segment alignment
|
|
; for relocation, but this doesn't apply to us
|
|
|
|
dq exit
|
|
|
|
|
|
defword output_start_routine, 0
|
|
dq docol
|
|
dq cld
|
|
dq lit, 9, rax, mov_reg64_imm64
|
|
dq lit, heap_requested_address, rdi, mov_reg64_imm64
|
|
dq lit, heap_size, rsi, mov_reg64_imm64
|
|
dq lit, 0x07, rdx, mov_reg64_imm64
|
|
dq lit, 0x22, r10, mov_extrareg64_imm64
|
|
dq lit, 0, r8, mov_extrareg64_imm64
|
|
dq lit, 0, r9, mov_extrareg64_imm64
|
|
dq syscall
|
|
dq rax, rdi, mov_reg64_reg64
|
|
dq exit
|
|
|
|
|
|
; write() the machine code by using self-reference
|
|
; TODO do this in a "real" quine way
|
|
defword self_raw, 0
|
|
dq docol
|
|
dq dup
|
|
dq lit, elf_header + 0xc4 ; source
|
|
dq lit, file_size - 0xc4 ; length
|
|
; destination destination source length
|
|
dq dup, lit, 4, roll, add, lit, 4, unroll
|
|
; result destination source length
|
|
dq memcopy ; broken since memcopy args change
|
|
dq exit
|
|
|
|
|
|
; Routines that traverse the raw code need a way to guess where the end of a
|
|
; word's contents are, lest they traverse off the edge of the world and
|
|
; segfault. On the heap, we have the "here" pointer to provide an upper bound.
|
|
; For code that's loaded from the ELF's text segment, we don't get to do that,
|
|
; so we need another way.
|
|
;
|
|
; We could notionally use syscalls to check how large the text segment is, but
|
|
; that would make us more dependent on specifics of the ABI and the kernel.
|
|
; Instead, we invent this concept of a metadata word, which is designated with
|
|
; a new flag bit and exists to annotate the address space rather than to be
|
|
; invoked. The traversal routines hardcode the expectation that the text
|
|
; segment ends with a metadata word. Also, they skip metadata words when
|
|
; describing things.
|
|
;
|
|
; Since the boot source is a raw string, not a Forth word, it also needs to
|
|
; be flagged as metadata. For convenience's sake, we use a single metadata
|
|
; word both to delimit the segment end, and to hold the boot source. Cute,
|
|
; right?
|
|
defword boot_source, 0x40
|
|
; Keep in mind that these words don't exist in memory, so branching won't
|
|
; have the intended effect. Any logic that requires branching needs to be
|
|
; written to the heap instead, and branch while running there. In fact,
|
|
; let's start out with an example of that, which is also our top-level
|
|
; routine!
|
|
dq ": quit r0 @ control! interpret branch [ -2 8 * , ] ; quit "
|
|
; o/~ Like a whirlpool and it never ends. o/~
|
|
;
|
|
; This implementation of quit does the same thing it does in Jonesforth:
|
|
; First, it wipes the control stack, completely emptying it so that whatever
|
|
; calls brought us here are forgotten and no longer relevant to what happens
|
|
; going forward. Second, it calls interpret repeatedly, forever.
|
|
;
|
|
; Interpret will return control to quit after every iteration. The control
|
|
; stack doesn't get wiped on those iterations, but user code that wants to
|
|
; halt its own execution can always call quit to do that, which will once
|
|
; again wipe the control stack. Isn't that trippy? Instead of unwinding the
|
|
; stack it just overwrites it!
|
|
;
|
|
; Notice that we immediately call quit, before doing anything else. That's
|
|
; load-bearing. Keep it that way. To get this far, we used a trampoline,
|
|
; created in cold_start, that calls interpret in an unrolled loop, just
|
|
; barely enough times to successfully reach that invocation. If you make
|
|
; quit longer, make sure to also make the trampoline longer and adjust its
|
|
; starting location. It's been defined with no extra length, in order to
|
|
; make sure things will crash in a noticeable way if anyone modifies it
|
|
; without that follow-through. It would be important to have a close look at
|
|
; the trampoline setup regardless, because it's allocated in space that this
|
|
; code could easily overwrite by accident, so it's better to have it fail in
|
|
; a predictable way than an unpredictable one.
|
|
|
|
; From here, we can do more or less whatever we want; nearly all the
|
|
; bootstrapping concerns have been dealt with. We do have to make sure every
|
|
; line in boot_source that outputs a string outputs one that's an exact
|
|
; multiple of eight bytes long; any accidental null-padding that
|
|
; flatassembler inserts will be treated as a string terminator by
|
|
; attach-string-to-input-buffer.
|
|
|
|
; In general, we're going to want to be able to go on little excursions
|
|
; where we define utility words that are only useful for one task, then
|
|
; deallocate that stuff after we're done with it. We implement "forget",
|
|
; which removes both dictionary entries and heap allocations for the entry
|
|
; pointer it's given and everything that came after.
|
|
;
|
|
; The implementation strategy is the same as Jonesforth's version, but
|
|
; Jonesforth runs in immediate mode and reads a word to operate on, whereas
|
|
; ours takes an entry pointer and runs in either compiled or immediate
|
|
; modes.
|
|
;
|
|
; In:
|
|
; entry pointer
|
|
dq ": forget dup @ latest ! here ! ; "
|
|
|
|
; We'll be defining a lot of immediate words, so we should set up a terse
|
|
; way to do that.
|
|
dq ": make-immediate latest @ set-word-immediate ; "
|
|
dq ": make-hidden latest @ hide-entry ; "
|
|
dq ": make-visible latest @ unhide-entry ; "
|
|
|
|
; The word "'" quotes the following word, looking it up and treating it as
|
|
; a constant. In immediate mode, the constant winds up on the stack; in
|
|
; compile mode it gets compiled.
|
|
;
|
|
; There are a few possible implementation strategies here. Running as an
|
|
; immediate word means there's a clear and unambiguous concept of "the
|
|
; following word", so that's what we do; otherwise we'd have to get clever
|
|
; about somehow finding out where we were called from. That means we take on
|
|
; what would otherwise be the interpreter's responsibility, of checking what
|
|
; mode we're in. Happily, that's easy to do.
|
|
;
|
|
; Though it might be nice to have high-level flow control for this, our
|
|
; implementation of "if" below relies on "'" several times, whereas "'" only
|
|
; branches once. So we bootstrap "'" first.
|
|
dq ": ' word value@ find dropstring-with-result "
|
|
dq " interpreter-flags @ 1 & 0branch [ 2 8 * , ] literal "
|
|
dq " ; make-immediate "
|
|
|
|
; Sooner or later we'll want to define recursive words; this one lets us
|
|
; do that. It compiles into a call to the word that's currently being
|
|
; defined (strictly speaking, the one whose definition was most recently
|
|
; begun).
|
|
dq ": recurse latest @ entry-to-execution-token , ; make-immediate "
|
|
|
|
; We use a novel suffix-based approach to flow control. We define words
|
|
; { and } which describe the boundaries of blocks of code, leaving a
|
|
; description on the value stack, while still compiling the contents
|
|
; normally.
|
|
;
|
|
; Then follow-up words such as "if" can use that information to slide
|
|
; the blocks around and insert any needed branches and other logic.
|
|
;
|
|
; After compiling a { ... } block, the stack is (start pointer, length).
|
|
dq ": { here @ ; make-immediate "
|
|
dq ": } dup here @ swap - ; make-immediate "
|
|
|
|
; (start pointer, length)
|
|
dq ": if 2dup swap dup 5 8 * + 3roll "
|
|
; (start pointer, length, start pointer, adjusted start pointer, length)
|
|
dq " memmove "
|
|
; (start pointer, length)
|
|
dq " swap here @ swap here ! swap "
|
|
; (old here, length)
|
|
dq " ' lit entry-to-execution-token , 0 , "
|
|
dq " ' != entry-to-execution-token , "
|
|
; The branch length needs to be one word longer than the block length,
|
|
; because the length field itself is part of the scope of the branch.
|
|
dq " ' 0branch entry-to-execution-token , dup 8 + , "
|
|
; (old here, length)
|
|
dq " drop 5 8 * + here ! ; make-immediate "
|
|
|
|
; (start pointer, length)
|
|
dq ": unless 2dup swap dup 5 8 * + 3roll "
|
|
; (start pointer, length, start pointer, adjusted start pointer, length)
|
|
dq " memmove "
|
|
; (start pointer, length)
|
|
dq " swap here @ swap here ! swap "
|
|
; (old here, length)
|
|
dq " ' lit entry-to-execution-token , 0 , "
|
|
dq " ' = entry-to-execution-token , "
|
|
; The branch length needs to be one word longer than the block length,
|
|
; because the length field itself is part of the scope of the branch.
|
|
dq " ' 0branch entry-to-execution-token , dup 8 + , "
|
|
; (old here, length)
|
|
dq " drop 5 8 * + here ! ; make-immediate "
|
|
|
|
; (true start, true length, false start, false length)
|
|
dq ": if-else "
|
|
;dq " dup 4 roll dup 5 unroll + "
|
|
;
|
|
; First we slide the false-block forward, then the true-block. We slide
|
|
; them both directly into their final positions, leaving space at the start
|
|
; for a test and branch, and space in between for an unconditional branch.
|
|
; Those spaces will take five words, and two words, respectively. So the
|
|
; false-block gets moved by seven words, and the true-block gets moved by
|
|
; five words.
|
|
;
|
|
; Note that this has diverged slightly from the self-hosted version,
|
|
; because in this version we don't have "pick" yet.
|
|
dq " 2dup swap dup 7 8 * + 3roll memmove "
|
|
dq " 4 roll dup 5 unroll 4 roll dup 5 unroll "
|
|
dq " swap dup 5 8 * + 3roll memmove "
|
|
|
|
; (true start, true length, false start, false length)
|
|
;
|
|
; Now we write out the initial test-and-branch.
|
|
dq " 4 roll dup 5 unroll here @ 6 unroll here ! "
|
|
; (old here, true start, true length, false start, false length)
|
|
dq " ' lit entry-to-execution-token , 0 , "
|
|
dq " ' != entry-to-execution-token , "
|
|
; Branch past the length field, the true-block, and the unconditional
|
|
; branch in the middle.
|
|
dq " ' 0branch entry-to-execution-token , "
|
|
dq " 3roll dup 4 unroll 3 8 * + , "
|
|
;
|
|
; Next, write out the unconditional branch in the middle.
|
|
dq " swap dup 3unroll 5 8 * + here ! "
|
|
dq " ' branch entry-to-execution-token , "
|
|
; Branch past the length field and the false-block.
|
|
dq " dup 8 + , "
|
|
;
|
|
; Set "here" to point to the true end.
|
|
dq " drop drop drop drop 7 8 * + here ! "
|
|
dq " ; make-immediate "
|
|
|
|
; (start, length)
|
|
dq ": forever "
|
|
dq " ' branch entry-to-execution-token , 8 + -1 * , drop "
|
|
dq " ; make-immediate "
|
|
|
|
; This slides the body forward, leaving the test where it is. It puts a
|
|
; conditional branch in-between them, then appends an unconditional branch
|
|
; at the end.
|
|
;
|
|
; (test start, test length, body start, body length)
|
|
dq ": while "
|
|
; The conditional branch needs five words.
|
|
dq " 2dup swap dup 5 8 * + 3roll memmove "
|
|
dq " here @ 5 unroll swap dup 3unroll here ! "
|
|
; (old here, test start, test length, body start, body length)
|
|
dq " ' lit entry-to-execution-token , 0 , "
|
|
dq " ' != entry-to-execution-token , "
|
|
; Branch past the length field, the body, and the unconditional branch.
|
|
dq " ' 0branch entry-to-execution-token , "
|
|
dq " dup 3 8 * + , "
|
|
; Set "here" to the new end.
|
|
dq " 5 8 * 6 roll + here ! "
|
|
; (test start, test length, body start, body length)
|
|
; Unconditionally branch backwards past the branch word, the body, the
|
|
; conditional branch, and the test.
|
|
dq " ' branch entry-to-execution-token , "
|
|
dq " 6 8 * + swap drop + swap drop -1 * , "
|
|
dq " ; make-immediate "
|
|
|
|
; This use of bitwise and is okay because they're both either 0 or 1.
|
|
; We'll have logical and real soon now, be patient... :)
|
|
dq ": is-in-heap dup log @ <= swap here @ > & ; "
|
|
|
|
; dq ": unlink-pre-heap-words "
|
|
; dq " latest @ "
|
|
; dq " dup { dup is-in-heap 0 = { drop exit } if } "
|
|
; dq " { drop exit } if-else "
|
|
; dq " { dup @ is-in-heap } { @ } while "
|
|
; dq " 0 swap ! ; "
|
|
; Do it immediately, so that we don't accidentally rely on any of that.
|
|
;dq "unlink-pre-heap-words "
|
|
|
|
; Now some fancier stack combinators.
|
|
;
|
|
; While it might be nice, for performance reasons, to do these in
|
|
; assembler, for now it's more important to have them at all.
|
|
dq ": 1- 1 - ; "
|
|
dq ": 1+ 1 + ; "
|
|
dq ": max 2dup >= { swap drop } { drop } if-else ; "
|
|
dq ": min 2dup <= { swap drop } { drop } if-else ; "
|
|
|
|
dq ": over swap dup 3unroll ; "
|
|
dq ": pick 2 + dup roll dup 3roll unroll ; "
|
|
; Standard Forth doesn't have equivalents of our ndrop and ndup. The HP
|
|
; calls them DROPN and DUPN but that doesn't go well with ie. 2dup or 3roll,
|
|
; so we do it like this.
|
|
dq ": ndrop { dup } { swap drop 1- } while drop ; "
|
|
dq ": ndup dup 1+ swap { dup } "
|
|
dq " { swap dup pick 3unroll swap 1- } while 2drop ; "
|
|
dq ": 3drop drop drop drop ; "
|
|
dq ": 3dup 2 pick 2 pick 2 pick ; "
|
|
|
|
dq ": && 0 != swap 0 != * ; "
|
|
dq ": || | 0 != ; "
|
|
dq ": not 0 = ; "
|
|
dq ": negate -1 * ; "
|
|
|
|
dq ": align-floor dup 3unroll /% swap drop * ; "
|
|
|
|
dq ": nexit 8 * control@ + r0 @ min control! ; "
|
|
|
|
; Let's have strings now.
|
|
dq ": s"" "
|
|
dq " consume "
|
|
dq " interpreter-flags @ 1 & "
|
|
dq " { ' litstring entry-to-execution-token , } if "
|
|
dq " here @ key { dup dup 34 != && } { pack8 key } while "
|
|
dq " drop 0 pack8 "
|
|
dq " interpreter-flags @ 1 & "
|
|
dq " { 8 packalign here ! } "
|
|
dq " { drop here @ } if-else "
|
|
dq " ; make-immediate "
|
|
|
|
; Finicky semantics, but also important.
|
|
dq ": ."" "
|
|
dq " ' s"" entry-to-execution-token execute "
|
|
dq " interpreter-flags @ 1 & "
|
|
dq " { ' emitstring entry-to-execution-token , } "
|
|
dq " { emitstring } if-else "
|
|
dq " ; make-immediate "
|
|
|
|
; While we're thinking about input, let's also have comments.
|
|
dq ": ~ "
|
|
dq " key { dup dup 10 != && } { drop key } while drop "
|
|
dq " ; make-immediate "
|
|
|
|
; Some output formatting tools.
|
|
dq ": space 32 value@ emitstring drop ; "
|
|
dq ": newline 10 value@ emitstring drop ; "
|
|
dq ": indent { dup } { space 1- } while drop ; "
|
|
dq ": .hexn 16 swap .base-unsigned ; "
|
|
|
|
; Some debugging tools.
|
|
dq ": stack "
|
|
dq " s0 @ 8 - { dup value@ 8 + != } "
|
|
dq " { dup s0 @ 8 - != { space } if dup @ . 8 - } "
|
|
dq " while drop newline ; "
|
|
dq ": stackhex "
|
|
dq " s0 @ 8 - { dup value@ 8 + != } "
|
|
dq " { dup s0 @ 8 - != { space } if dup @ .hex64 8 - } "
|
|
dq " while drop newline ; "
|
|
|
|
dq ": oldest-entry "
|
|
dq " latest @ { dup @ } { @ } while ; "
|
|
|
|
dq ": oldest-entry-in "
|
|
dq " dup "
|
|
dq " dup { { dup @ } { @ } while } if "
|
|
dq " dup 3roll = { drop 0 } if ; "
|
|
|
|
dq ": next-newer-entry "
|
|
dq " latest @ "
|
|
dq " 2dup = { 2drop 0 exit } if "
|
|
dq " { dup { 2dup @ != } if } "
|
|
dq " { @ } while swap drop ; "
|
|
|
|
dq ": guess-entry-end "
|
|
dq " dup entry-flags@ 64 & 64 = { exit } if "
|
|
dq " dup next-newer-entry dup "
|
|
dq " { drop dup is-in-heap { drop here @ } { drop } if-else "
|
|
dq " exit } unless "
|
|
dq " swap drop ; "
|
|
|
|
dq ": containing-entry "
|
|
dq " dup is-in-heap { drop 0 exit } unless "
|
|
dq " latest @ { dup { 2dup > } { 0 } if-else } "
|
|
dq " { @ } while swap drop ; "
|
|
|
|
dq ": is-assembly-word "
|
|
dq " entry-to-execution-token dup 8 + swap @ = ; "
|
|
|
|
dq ": is-docol-itself "
|
|
dq " entry-to-name s"" docol"" stringcmp 0 = ; "
|
|
|
|
|
|
; If the buffer is empty, make sure its logical position is at the
|
|
; physical start. Otherwise, leave it alone.
|
|
;
|
|
; In:
|
|
; pointer to buffer metadata
|
|
dq ": normalize-buffer "
|
|
dq " dup buffer-logical-length @ 0 = "
|
|
dq " { dup buffer-physical-start @ swap "
|
|
dq " buffer-logical-start ! } { drop } if-else "
|
|
dq " ; "
|
|
|
|
|
|
; Find the next contiguous area of a buffer to write incoming data to.
|
|
; This will begin at the logical end. Depending on the order things are in,
|
|
; the available space might run from there to the physical end, or to the
|
|
; logical start. Those are the only two possibilities.
|
|
;
|
|
; If the buffer is full, this will return as normal but the length will
|
|
; be zero. The caller should make sure to respect that.
|
|
;
|
|
; In:
|
|
; pointer to buffer metadata
|
|
; Out:
|
|
; destination start
|
|
; destination length
|
|
dq ": compute-next-buffer-free-block "
|
|
dq " dup buffer-physical-start @ swap dup buffer-physical-length @ "
|
|
dq " swap 3unroll + swap "
|
|
; (physical end, metadata pointer)
|
|
dq " dup buffer-logical-start @ swap dup buffer-logical-length @ "
|
|
dq " swap 3unroll + swap 3unroll "
|
|
; (metadata pointer, physical end, logical end not yet wrapped)
|
|
|
|
dq " 2dup >= "
|
|
dq " { "
|
|
; If the logical end is greater than or equal to the physical end, find
|
|
; where it wraps to and start from there.
|
|
dq " swap - swap dup buffer-physical-start @ swap 3unroll + "
|
|
; (metadata pointer, destination start)
|
|
; In this scenario, the logical start is the end of the free space, so
|
|
; compute how far away it is.
|
|
dq " dup 3roll "
|
|
; (destination start, destination start, metadata pointer)
|
|
dq " buffer-logical-start @ swap - } "
|
|
|
|
dq " { "
|
|
dq " 3roll drop "
|
|
dq " dup 3roll swap - "
|
|
; If the logical end is less than the physical end, it is the destination;
|
|
; the physical end is also the end of the free space, so compute how far
|
|
; away it is.
|
|
dq " } if-else "
|
|
; (destination start, destination length)
|
|
dq " ; "
|
|
|
|
|
|
|
|
; In:
|
|
; pointer to buffer metadata
|
|
dq ": refill-input-buffer-from-stdin "
|
|
dq " dup normalize-buffer "
|
|
dq " dup compute-next-buffer-free-block "
|
|
; Check whether the buffer is full. If not, do a read. If so, that's not
|
|
; an error, just clean up and take no action.
|
|
dq " dup { swap sys-read "
|
|
dq " dup -2 = "
|
|
dq " { drop drop s"" Read error."" emitstring 0 sys-exit } "
|
|
dq " { swap dup buffer-logical-length @ 3roll + "
|
|
dq " swap buffer-logical-length ! } if-else } "
|
|
dq " { drop drop } if-else ; "
|
|
|
|
|
|
; Though we only do it once, this is a bit involved so we provide it as a
|
|
; word. Notionally there are situations in which it could come up again, so
|
|
; it seems worth having around.
|
|
;
|
|
; It actually needs to run as a compiled word no matter what; if it were
|
|
; run in interpret mode it would cut itself off from the rest of itself.
|
|
; However, if we didn't want to keep it around we could have it forget
|
|
; itself...
|
|
dq ": relink-main-input-buffer-to-stdin "
|
|
dq " 1024 allocate dup main-input-buffer buffer-physical-start ! "
|
|
dq " main-input-buffer buffer-logical-start ! "
|
|
dq " 1024 main-input-buffer buffer-physical-length ! "
|
|
dq " 0 main-input-buffer buffer-logical-length ! "
|
|
dq " ' refill-input-buffer-from-stdin entry-to-execution-token "
|
|
dq " main-input-buffer input-buffer-refill ! "
|
|
dq " ; "
|
|
|
|
|
|
; Notionally, it might make sense to define "create" in terms of
|
|
; "create-in". Any change like that is being postponed to after the removal
|
|
; of flatassembler, when refactorings will be easier.
|
|
;
|
|
; In:
|
|
; name string pointer
|
|
; dictionary handle (points to a pointer to the first item)
|
|
dq ": create-in "
|
|
dq " dup @ here @ swap pack64 "
|
|
; (name string pointer, dictionary handle, output point)
|
|
dq " 0 pack8 0 pack8 "
|
|
dq " 3roll packstring "
|
|
dq " 8 packalign "
|
|
; (dictionary handle, output point)
|
|
dq " swap here @ swap ! "
|
|
; (output point)
|
|
dq " here ! "
|
|
dq " ; "
|
|
|
|
|
|
; The word named "docol" has the job of returning the value that gets used
|
|
; as the actual codeword. We make the assumption that the codeword will
|
|
; point somewhere near the entry header; we allow for the possibility that
|
|
; it might be before or after.
|
|
;
|
|
; Generally, it's possible for there to be several copies of docol due to
|
|
; alternate heaps and things like that, so the goal is to recognize any of
|
|
; them.
|
|
dq ": is-docol-codeword "
|
|
dq " dup is-in-heap { drop 0 exit } unless "
|
|
dq " containing-entry dup "
|
|
dq " { dup is-docol-itself "
|
|
dq " { drop 1 } "
|
|
dq " { next-newer-entry dup { is-docol-itself } if } if-else "
|
|
dq " } if ; "
|
|
|
|
; TODO this only works on heap words
|
|
dq ": is-docol-word "
|
|
dq " dup is-assembly-word { drop 0 exit } if "
|
|
dq " entry-to-execution-token @ is-docol-codeword ; "
|
|
|
|
dq ": word-heading "
|
|
dq " dup entry-to-name dup emitstring space "
|
|
dq " stringlen 1+ 54 swap - 0 max indent dup .hex64 "
|
|
dq " dup entry-flags@ dup "
|
|
dq " { space "
|
|
dq " dup 128 & { s"" H"" emitstring } if "
|
|
dq " dup 64 & { s"" M"" emitstring } if "
|
|
dq " dup 1 & { s"" I"" emitstring } if "
|
|
dq " } if drop "
|
|
dq " dup is-assembly-word { s"" asm"" emitstring } "
|
|
dq " { dup is-docol-word { s"" raw"" emitstring } unless "
|
|
dq " } if-else drop "
|
|
dq " newline ; "
|
|
|
|
dq ": list-dictionary "
|
|
dq " oldest-entry { dup } "
|
|
dq " { dup word-heading next-newer-entry } while drop ; "
|
|
|
|
; (content end, content start, label start)
|
|
dq ": hexdump-row "
|
|
dq " 2 indent dup .hex32 dup 4 unroll "
|
|
dq " 0 { dup 16 > } "
|
|
dq " { dup 7 & 0 = { space } if space "
|
|
dq " 2dup + dup 4 pick <= swap 5 pick > && "
|
|
dq " { 2dup + 8@ .hex8 } { space space } if-else "
|
|
dq " 1+ } while "
|
|
dq " newline 5 ndrop ; "
|
|
|
|
; (end, start)
|
|
dq ": hexdump-between "
|
|
dq " dup 16 1- invert & "
|
|
dq " { dup 3 pick > } "
|
|
dq " { 3dup hexdump-row 16 + } while 3 ndrop ; "
|
|
|
|
; (start, length)
|
|
dq ": hexdump-from swap dup 3unroll + swap hexdump-between ; "
|
|
|
|
; (start)
|
|
dq ": hexdump 64 hexdump-from ; "
|
|
|
|
dq ": describe-hex "
|
|
dq " dup word-heading "
|
|
dq " dup guess-entry-end swap entry-to-execution-token "
|
|
dq " hexdump-between ; "
|
|
|
|
dq ": is-codeword "
|
|
dq " dup is-in-heap { drop 0 exit } unless "
|
|
dq " dup containing-entry dup { 2drop 0 exit } unless "
|
|
dq " entry-to-execution-token = ; "
|
|
|
|
dq ": describe-docol "
|
|
dq " dup word-heading "
|
|
dq " dup guess-entry-end swap entry-to-execution-token 8 + "
|
|
dq " { 2dup < } "
|
|
dq " { space dup @ dup is-codeword "
|
|
dq " { execution-token-to-entry entry-to-name emitstring } "
|
|
dq " { . } if-else "
|
|
dq " 8 + } while newline ; "
|
|
|
|
dq ": describe "
|
|
dq " dup is-docol-word "
|
|
dq " { describe-docol } { describe-hex } if-else ; "
|
|
|
|
dq ": describe-all "
|
|
dq " oldest-entry { dup } "
|
|
dq " { dup describe next-newer-entry } while drop ; "
|
|
|
|
dq ": bye 0 sys-exit ; "
|
|
|
|
;dq ": foo 5 { dup } "
|
|
;dq " { 4 indent 97 value@ emitstring drop newline 1- } "
|
|
;dq " while drop ; foo "
|
|
;dq ": foo 5 6 > { 42 . } if ; foo ' foo forget "
|
|
;dq ": foo 5 6 > { 42 } { 69 } if-else . ; foo ' foo forget "
|
|
;dq ": foo { 5 . } forever ; foo ' foo forget "
|
|
;dq ": foo 0 { dup 5 > } { dup . 1+ } while drop ; foo ' foo forget "
|
|
|
|
;dq "s"" foo"" value@ emitstring dropstring "
|
|
;dq ": foo s"" zotzotza"" emitstring ; ' foo describe "
|
|
;dq ": foo 1 { s"" zotzotza"" emitstring } if ; ' foo describe "
|
|
;dq "s"" zotzotza"" emitstring stack "
|
|
;dq "68719476736 containing-entry stackhex "
|
|
;dq "68719587456 containing-entry stackhex "
|
|
;dq "587456 containing-entry stackhex "
|
|
;dq "68719607808 containing-entry stackhex "
|
|
;dq "list-dictionary "
|
|
;dq "describe-all "
|
|
;dq ": doittoit 8 allocate-input-buffer "
|
|
;dq " dup stackhex refill-input-buffer-from-stdin "
|
|
;dq " dup key-from drop "
|
|
;dq " dup key-from drop "
|
|
;dq " dup key-from drop "
|
|
;dq " dup key-from drop "
|
|
;dq " stackhex dup 256 hexdump-from "
|
|
;dq " dup refill-input-buffer-from-stdin "
|
|
;dq " stackhex dup 256 hexdump-from "
|
|
;dq " dup refill-input-buffer-from-stdin "
|
|
;dq " stackhex dup 256 hexdump-from "
|
|
;dq " dup refill-input-buffer-from-stdin "
|
|
;dq " stackhex dup 256 hexdump-from "
|
|
;dq " bye ; doittoit "
|
|
dq " "
|
|
|
|
; TODO running "variable" interactively doesn't work because the string and
|
|
; the "create" invocation step on each other. this is a big deal and really
|
|
; needs to be fixed.
|
|
; TODO find_in/find-in is backwards compared to create-in.
|
|
; TODO define ( ... ) comments
|
|
; TODO define constant (double-check variable)
|
|
; TODO consider defining is-hidden and is-immediate
|
|
; TODO define ?
|
|
; TODO define allot and cells
|
|
; TODO consider what text stuff to define
|
|
; TODO control stack trace
|
|
; TODO make an interactive debugger
|
|
; TODO argc argv envp etc
|
|
; TODO consider "unused" and some replacement for "brk"
|
|
; TODO consider file API
|
|
; TODO consider ";asm" or something
|
|
; TODO consider a welcome message
|
|
|
|
; The last in a long series of perilous handoffs. :)
|
|
dq " relink-main-input-buffer-to-stdin "
|
|
; We'll never get here, but if we do, it's an error.
|
|
dq " 1 sys-exit "
|
|
|
|
dq 0
|
|
|
|
|
|
final_word_name = latest_word
|
|
code_size = $ - code_start
|
|
file_size = $ - $$
|
|
|