/ Stack interpreter - token/subroutine-threaded version, #0 in AC /
/// ZP tables/initial values ///
*0000 / begin in zero page
/ Default configuration is for return stack to begin (upper bound) at
/ 7200, with three pages reserved for interpreter code, and parameter
/ stack to begin immediately below the lower bound of the return stack.
/ Note: since #0 is always in register, actual stack storage will begin
/ one word below the specified address.
rsp, 7200 / begin return stack immediately below interpreter
psp, 7160 / begin parameter stack at 7160 - 16 words of return
/ --- Temporary variable(s)/common constants --- /
tmp, 0
c7777, 7777
/ --- Auto-increment variable(s) --- /
*0010
tmpinc, 0
tmpinc2, 0
/ --- Jump table --- /
*0120 / Reserve the last 48 words for the jump table
jlit, dolit
jchf, dochf
jld, dold
jldn, doldn
jst, dost
jstn, dostn
jadd, doadd
jsub, dosub
jmul, domul
jdiv, dodiv
jand, doand
jor, door
jxor, doxor
jasr, doasr
jrnd, dornd
jskn, doskn
jskp, doskp
jskz, doskz
jiskz, doiskz
jrtn, dortn
jjp, dojp
jjpi, dojpi
jcl, docl
jcli, docli
jjpf, dojpf
jclf, doclf
jdup, dodup
jdrop, dodrop
jdrip, dodrip
jswap, doswap
jover, doover
jpick, dopick
jptor, doptor
jrtop, dortop
jgetr, dogetr
jrot, dorot
/// Initializer routine ///
/ TODO: this
/// Resident interpreter code begins here ///
*7200 / Default resident address for interpreter code
/ --- Control instructions --- /
doskn, / DOSKN - skip (IP += 2) if #0 is negative
0
spa cla / if #0 is not negative,
jmp sn / skip skipping
isz doskn / otherwise, skip
isz doskn
sn, tad i z psp / get the new #0
isz z psp / increment the stack pointer
jmp i doskn / 7 instructions, 8 words
/ HD6120: 47* cycles, 8/e: 15* us, 8: 19.5* us
/ * 61 cycles/19 us/22.5 us if skip taken
doskp, / DOSKP - skip (IP += 2) if #0 is positive (non-negative, non-zero)
0
sma sza cla / if #0 is zero or negative,
jmp sp / skip skipping
isz doskp / otherwise, skip
isz doskp
sp, tad i z psp / get the new #0
isz z psp / increment the stack pointer
jmp i doskp / 7 instructions, 8 words
/ HD6120: 47* cycles, 8/e: 15* us, 8: 19.5* us
/ * 61 cycles/19 us/22.5 us if skip taken
doskz, / DOSKZ - skip (IP += 2) if #0 is zero
0
sna cla / if #0 is nonzero,
jmp sz / skip skipping
isz doskz / otherwise, skip
isz doskz
sz, tad i z psp / get the new #0
isz z psp / increment the stack pointer
jmp i doskz / 7 instructions, 8 words
/ HD6120: 47* cycles, 8/e: 15* us, 8: 19.5* us
/ * 61 cycles/19 us/22.5 us if skip taken
doiskz, / DOISKZ - increment RSP #0 and drop/skip if zero
0
isz i z rsp / increment return-stack #0
jmp i doiskz / if result is nonzero, do nothing
isz z rsp / otherwise, drop it
isz doiskz / and skip
isz doiskz
jmp i doiskz / 6 instructions, 7 words
/ HD6120: 29* cycles, 8/e: 10* us, 8: 12* us
/ * 58 cycles/17.8 us/21 us if skip taken
dort, / DORT - jump to return-stack (#0)
mql / save #0
tad i z rsp / get the return address
dca z tmp / save it
isz z rsp / increment the return-stack pointer
mqa / retrieve #0
jmp i z tmp / 6 instructions, 6 words
/ HD6120: 52 cycles, 8/e: 16.2 us, 8: 19.5 us
dojp, / DOJP - jump to (#0)
dca z tmp / save the address
tad i z psp / load the new #0
isz z psp / increment the stack pointer
jmp i z tmp / 4 instructions, 4 words
/ HD6120: 46 cycles, 8/e: 15.2 us, 8: 18 us
dojpi, / DOJPI - jump to (IP)
0
mql / save #0
tad i dojpi / get address from the instruction stream
dca z tmp / save the address
mqa / retrieve #0
jmp i z tmp / 5 instructions, 5 words
/ HD6120: 46 cycles, 8/e: 16.4 us, 8: 19.5 us
docl, / DOCL - save IP and jump to (#0)
0
dca z tmp / save the address
cla cma / load AC with -1
tad z rsp / load/decrement RSP
dca z rsp / save it back
tad docl / get the return address
dca i z rsp / save it on the return stack
tad i z psp / get the new #0
isz z psp / increment the stack pointer
jmp i z tmp / 9 instructions, 9 words
/ HD6120: 80 cycles, 8/e: 29.4 us, 8: 34.5 us
docli, / DOCLI - save IP and jump to (IP)++
0
mql / save #0
cla cma / load AC with -1
tad z rsp / load/decrement RSP
dca z rsp / save it back
tad i doicall / get the address
dca z tmp / save it
tad doicall / get the return address
iac / increment it
dca i z rsp / save it on the return stack
mqa / retrieve #0
jmp i z tmp / 11 instructions, 11 words
/ HD6120: 92 cycles, 8/e: 30.4 us, 8: 36 us
/// --- MUST BE IN THE SAME FIELD! --- ///
cthunk, thunk / pointer to return thunk
doclf, / DOCLF - save IP and jump to (#1) in field #0
0
mql / save #0
cla cma cll rtl / load AC with -3
tad z rsp / load/decrement the return-stack pointer
dca z rsp / save it back
tad z rsp / get it again
dca z tmpinc / save it in an autoincrement location
tad cthunk / get the return-thunk address
/ Field and address are swapped here because the return thunk pops
/ them to the parameter stack (reversing order) before doing a JPF
dca i z tmpinc / save it on top of the return stack
rif / get the current instruction field
dca i z tmpinc / save it next on the stack
tad doclf / get the return address
dca i z tmpinc / save it last on the stack
mqa / retrieve #0
/ 13 instructions, 14 words
/ HD6120: 103 cycles, 8/e: 35.6 us, 8: 42 us
dojpf, / DOJPF - jump to (#1) in field #0
tad ccdf / add in the CDF instruction
dca jfdf / save it
tad jfdf / get it back
iac / make it a CIF instruction
dca jfif / save it
tad i z psp / get the address
dca z tmp / save it
isz z psp / increment the stack pointer
tad i z psp / get the new #0
mql / save i
jfdf, .-. / work in the new instruction field
tad z psp / get the stack pointer
dca i z ppsp / transfer it to the new field
tad z rsp / get the return-stack pointer
dca i z prsp / transfer it to the new field
cdf 00 / work in the stack field again
mqa / retrieve #0
jfif, .-. / switch to the new instruction field
jmp i z tmp / 19 instructions, 21 words - GAHHHHH
/ HD6120: 176* cycles, 8/e: 48* us, 8: 57* us
/ * 169/45.6 us/54 us when falling through from DOCLF
ppsp, psp / pointer to the stack pointer
prsp, rsp / pointer to the return-stack pointer
/ --- Load/store instructions --- /
ccdf, cdf 00
dochf, / DOCHF - changes the data field to #0
0
tad ccdf / add in the CDF instruction
dca ldfld / store the result in place
tad ldfld / get it back
dca stfld / store it in the other place
tad i z psp / get the new #0
isz z psp / increment the stack pointer
jmp i dochf / 7 instructions, 9 words
/ HD6120: 64 cycles, 8/e: 23 us, 8: 27 us
dold, / DOLD - pushes (#0)
0
dca z tmp / save the address
ldfld, .-. / select the data field
tad i z tmp / get the datum
cdf 00 / select the stack field
jmp i dold / 5 instructions, 6 words
/ HD6120: 46 cycles, 8/e: 15 us, 8: 18 us
dost, / DOST - saves #1 to (#0)
0
dca z tmp / save the address
tad i z psp / get the datum
stfld, .-. / select the data field
dca i z tmp / save the datum to memory
cdf 00 / select the stack field
isz z psp / increment the stack pointer
tad i z psp / get the new #0
isz z psp / increment the stack pointer
jmp i dost / 9 instructions, 10 words
/ HD6120: 84 cycles, 8/e: 26.8 us, 8: 30 us
/// --- END FIELD RESTRICTION --- ///
dolit, / DOLIT - pushes (IP)++
0
mql / save #0
cla cma / load AC with -1
tad z psp / load/decrement PSP
dca z psp / save it back
mqa / retrieve #0
dca i z psp / save it to the stack
tad i dolit / get constant as the new #0
isz dolit / increment return address
jmp i dolit / 9 instructions, 10 words
/ HD6120: 76 cycles, 8/e: 24 us, 8: 30 us
doldn, / DOLDN - pushes (#0) in the stack field
0
dca z tmp / save the address
tad i z tmp / get the datum
jmp i doldn / 3 instructions, 4 words
/ HD6120: 34 cycles, 8/e: 12.6 us, 8: 15 us
dostn, / DOSTN - saves #1 to (#0) in the stack field
0
dca z tmp / save the address
tad i z psp / get the datum
dca i z tmp / save the datum to memory
isz z psp / increment the stack pointer
tad i z psp / get the new #0
isz z psp / increment the stack pointer
jmp i dostn / 7 instructions, 8 words
/ HD6120: 72 cycles, 8/e: 25.4 us, 8: 30 us
/ --- Arithmetic/logic instructions --- /
/donop, / DONOP - do nothing of consequence
/ 0
/ jmp i z donop
/ / HD6120: 17 cycles, 8/e: 7.6 us, 8: 9 us
/ HD6120: 6 cycles, 8/e: 1.2 us, 8: 1.5 us
doadd, / DOADD - add #0 and #1
0
tad i z psp / add #1 to #0
isz z psp / increment the stack pointer
jmp i doadd / 3 instructions, 4 words
/ HD6120: 36 cycles, 8/e: 12.6 us, 8: 15 us
dosub, / DOSUB - subtract #0 from #1
0
cma iac / negate #0
tad i z psp / add #1 to #0
isz z psp / increment the stack pointer
jmp i dosub / 4 instructions, 5 words
/ HD6120: 42 cycles, 8/e: 13.8 us, 8: 16.5 us
domul, / DOMUL - multiply #0 and #1
/ TODO: manual and hardware-assisted multiplication options
0
dodiv, / DODIV - divide #1 by #0
/ TODO: manual and hardware-assisted division options
0
/doinc, / DOINC - increment #0
/ 0
/ iac / increment #0
/ jmp i doinc / 2 instructions, 3 words
/ / HD6120: 23 cycles, 8/e: 7.4 us, 8: 9 us
/ HD6120: 6 cycles, 8/e: 1.2 us, 8: 1.5 us
/dodec, / DODEC - decrement #0
/ 0
/ tad c7777 / add -1 to #0
/ jmp i dodec / 2 instructions, 4 words
/ / HD6120: 34 cycles, 8/e: 8.8 us, 8: 10.5 us
/ HD6120: 7 cycles, 8/e: 2.6 us, 8: 3 us
/doneg, / DONEG - negate #0
/ 0
/ cma iac / negate #0
/ jmp i doneg / 2 instructions, 3 words
/ / HD6120: 23 cycles, 8/e: 7.4 us, 8: 9 us
/ HD6120: 6 cycles, 8/e: 1.2 us, 8: 1.5 us
/donot, / DONOT - complement #0
/ 0
/ cma / complement #0
/ jmp i donot / 2 instructions, 3 words
/ / HD6120: 23 cycles, 8/e: 7.4 us, 8: 9 us
/ HD6120: 6 cycles, 8/e: 1.2 us, 8: 1.5 us
doand, / DOAND - AND #0 and #1
0
and i z psp / AND #1 with #0
isz z psp / increment the stack pointer
jmp i doand / 3 instructions, 4 words
/ HD6120: 36 cycles, 8/e: 12.6 us, 8: 15 us
/ Thanks to Doug Jones for the OR and XOR algorithms.
door, / DOOR - OR #0 and #1
0
dca z tmp / save #0 to memory
tad i z psp / get #1
and z tmp / find common (carry-causing) 1s
cma / invert the result
and z tmp / mask out all common 1s from #0
tad i z psp / add it to #1
isz z psp / increment the stack pointer
jmp i door / 8 instructions, 9 words
/ HD6120: 73 cycles, 8/e: 25.4 us, 8: 30 us
doxor, / DOXOR - XOR #0 and #1
0
dca z tmp / save #0 to memory
tad z tmp / retrieve it
and i z psp / find common (carry-causing) 1s
cma iac / negate the result
cll ral / double it
tad z tmp / pre-un-carry any carries
tad i z psp / and add this to #1
isz z psp / increment the stack pointer
jmp i doxor / 9 instructions, 10 words
/ HD6120: 79 cycles, 8/e: 26.4 us, 8: 31.5 us
/dolsl, / DOLSL - shift #0 left
/ 0
/ cll ral / shift #0 left
/ jmp i dolsl / 2 instructions, 3 words
/ / HD6120: 23 cycles, 8/e: 7.4 us, 8: 9 us
/ HD6120: 6 cycles, 8/e: 1.2 us, 8: 1.5 us
/dolsr, / DOLSR - shift #0 right
/ 0
/ cll rar / shift #0 right
/ jmp i dolsr / 2 instructions, 3 words
/ / HD6120: 23 cycles, 8/e: 7.4 us, 8: 9 us
/ HD6120: 6 cycles, 8/e: 1.2 us, 8: 1.5 us
doasr, / DOASR - arithmetic-shift #0 right
0
cll / clear the link
tad c4000 / complement MSB, shifting it to link
ral / rotate complemented MSB into L
cml rtr / un-complement MSB and shift the whole thing right
jmp i doasr / 5 instructions, 7 words
/ HD6120: 42 cycles, 8/e: 12.4 us, 8: 15 us
c4000, 4000
/dobswp, / DOBSWP - byte-swap #0
/ 0
/ bsw / rotate #0 six places
/ jmp i dobswp / 2 instructions, 3 words
/ / HD6120: 23 cycles, 8/e: 7.4 us, 8: 9 us
/ HD6120: 6 cycles, 8/e: 1.2 us, 8: 1.5 us
dornd, / DORND - LFSR pseudorandom-number generation with seed/state #0
0
cll rar / shift #0 right
szl / if carry-out was nonzero,
jmp i dornd / just return
dca z tmp / save #0 to memory
tad z tmp / and get it back
and rnmask / find common (carry-causing) 1s
cma iac / negate the result
cll ral / and double it
tad z tmp / pre-un-carry the common 1s
tad rnmask / and add the mask value
jmp i dornd / 11 instructions, 13 words
/ HD6120: 29* cycles, 8/e: 10* us, 8: 10.5* us
/ * 76/24 us/28.5 us if XOR is required**
/ ** Yes, it's pseudo-random how long the pseudo-random number routine
/ will take to execute. How fitting!
rnmask, 4051 / the magic number
/ --- Stack operations --- /
dodup, / DODUP - duplicate #0 on the stack
0
mql / save #0
cla cma / load AC with -1
tad z psp / load/decrement the stack pointer
dca z psp / save it back
mqa / retrieve #0
dca i z psp / save it to the stack
mqa / retrieve it again
jmp i dodup / 8 instructions, 9 words
/ HD6120: 65 cycles, 8/e: 18.8 us, 8: 24 us
dodrop, / DODROP - drop #0 from the stack
0
cla / discard #0
tad i z psp / get the new #0
isz z psp / increment the stack pointer
jmp i dodrop / 4 instructions, 5 words
/ HD6120: 42 cycles, 8/e: 13.8 us, 8: 16.5 us
dodrip, / DODRIP - retrieve dropped #0
0
mql / save current #0
cla cma cll ral / load AC with -2
tad z psp / load/decrement the stack pointer
dca z psp / save it back
tad i z psp / get dropped #0
isz z psp / increment the stack pointer
mqa mql / retrieve initial #0
dca i z psp / save it to the stack
mqa / retrieve restored #0
jmp i doundrop / 10 instructions, 11 words
/ HD6120: 83 cycles, 8/e: 26.4 us, 8: 31.5 us
doswap, / DOSWAP - exchange #0 and #1
0
mql / save #0
tad i z psp / get #1
mqa mql / swap AC & MQ
dca i z psp / save #0 as #1
mqa / retrieve #1 as the new #0
jmp i doswap / 6 instructions, 7 words
/ HD6120: 55 cycles, 8/e: 17.4 us, 8: 21 us
doover, / DOOVER - copy #1 to TOS
0
mql / save #0
tad z psp / get the stack pointer
dca z tmp / save it
cla cma / load AC with -1
tad z psp / load/decrement the stack pointer
dca z psp / save it back
mqa / retrieve #0
dca i z psp / save it to the stack
tad i z tmp / get #1 as the new #0
jmp i doover / 10 instructions, 11 words
/ HD6120: 83 cycles, 8/e: 27.4 us, 8: 33 us
/ Note: 0 PICK is *not* equivalent to DUP, but rather DRIP SWAP DROP
dopick, / DOPICK - copy item ##0 to TOS
0
tad z c7777 / adjust for #0 being in register and not in memory
tad z psp / add #0 to the stack pointer
dca z tmp / save it for indirection
tad i z tmp / get the specified stack item
jmp i dopick / 4 instructions, 5 words
/ HD6120: 48 cycles, 8/e: 17.8 us, 8: 21 us
doptor, / DOPTOR - move #0 to the return stack
0
mql / save #0
cla cma / load AC with -1
tad z rsp / load/decrement the return stack pointer
dca z rsp / save it back
mqa / retrieve #0
dca i z rsp / save it to the return stack
tad i z psp / get the new #0
isz z psp / increment the stack pointer
jmp i doptor / 9 instructions, 10 words
/ HD6120: 78 cycles, 8/e: 25.2 us, 8: 30 us
dortop, / DORTOP - move return-stack #0 to the stack
0
mql / save #0
cla cma / load AC with -1
tad z psp / load/decrement the stack pointer
dca z psp / save it back
mqa / retrieve #0
dca i z psp / save it to the stack
tad i z rsp / get the new #0
isz z rsp / increment the stack pointer
jmp i dortop / 9 instructions, 10 words
/ HD6120: 78 cycles, 8/e: 25.2 us, 8: 30 us
dogetr, / DOGETR - copy return-stack #0 to the stack
0
mql / save #0
cla cma / load AC with -1
tad z psp / load/decrement the stack pointer
dca z psp / save it back
mqa / retrieve #0
dca i z psp / save it to the stack
tad i z rsp / get the new #0
jmp i dogetr / 8 instructions, 9 words
/ HD6120: 69 cycles, 8/e: 22.6 us, 8: 27 us
dorot, / DOROT - bump #2 to top-of-stack and shift #0/#1 down accordingly
0
mql / save #0
tad z psp / get the stack pointer
iac / increment it
dca z tmp / save it
tad i z psp / get #1
mqa mql / swap #0 and #1
dca i z psp / save the new #1
tad i z tmp / get #2
mqa mql / swap #0 and #2
dca i z tmp / "The new Number Two..."
mqa / retrieve the new #0
jmp i dorot / 12 instructions, 13 words
/ HD6120: 101 cycles, 8/e: 32.6 us, 8: 39 us
doroll, / DOROLL - bump ##0 to top-of-stack and shift #0-#n down accordingly
0
cma iac / negate #0
iac / increment it for counting and index purposes
dca z tmp / save it as a counter
tad z psp / get the stack pointer
cma iac / negate it
tad z tmp / add it to #0
cma iac / de-negate it
dca z tmpinc / save it as a pointer
tad i z tmpinc / get ##0
mql / save it for later
tad z psp / get the stack pointer
dca z tmpinc / save it for auto-increment
tad z psp / get it again
dca z tmpinc2 / save it for a second auto-increment
/ loop begins here
rloop, tad i z tmpinc / get the next item on the stack
mqa mql / save it and retrieve the previous
dca i z tmpinc2 / save the previous item in its place
isz z tmp / loop (#0 - 1) times
jmp rloop
/ loop end - cleanup
mqa / get the last saved item
dca i z tmpinc2 / save it in place
tad i z psp / get the new #0
isz z psp / increment the stack pointer
jmp i doroll / 24 instructions, 25 words
/ HD6120: 190* cycles, 8/e: 61.8* us, 8: 72* us
/ * add 43 cycles/12.6 us/15 us per extra (#0 > 1) iteration
/// Opcode defines ///
lit = jms i z jlit
chf = jms i z jchf
ld = jms i z jld
st = jms i z jst
ldn = jms i z jldn
stn = jms i z jstn
nop = cll
add = jms i z jadd
sub = jms i z jsub
mul = jms i z jmul
div = jms i z jdiv
dec = tad z c7777 /jdec, dodec
inc = iac /jinc, doinc
neg = cma iac /jneg, doneg
not = cma /jnot, donot
and = jms i z jand
or = jms i z jor
xor = jms i z jxor
lsl = cll ral /jlsl, dolsl
lsr = cll rar /jlsr, dolsr
asr = jms i z jasr
bswp = bsw /jbswp, dobswp
rnd = jms i z jrnd
skn = jms i z jskn
skp = jms i z jskp
skz = jms i z jskz
iskz = jms i z jiskz
rt = jmp i z jrt
jp = jmp i z jjp
jpi = jms i z jjpi
cl = jms i z jcl
cli = jms i z jcli
jpf = jmp i z jjpf
clf = jms i z jclf
dup = jms i z jdup
drop = jms i z jdrop
drip = jms i z jdrip
swap = jms i z jswap
over = jms i z jover
pick = jms i z jpick
ptor = jms i z jptor
rtop = jms i z jrtop
getr = jms i z jgetr
rot = jms i z jrot
/// Far-call return thunk ///
*7775 / placed at the end of the field, safeguards rollover
thunk, / Return thunk - pops address and field to the parameter stack and JPFs
rtop
rtop
jpf
/ HD6120: 332 cycles, 8/e: 98.4 us, 8: 117 us