The stdlib is probably broken at this commit. Next step is a test suite.
## Heap and Pointers ##
The first 16 heap addresses (`0-15`) are reserved when using the stdlib.
-Within that reservation, heap[0] is used by `random` and heap[15] is used
-by `spewreg`. The remaining 14 locations, heap[1]-heap[14] are used as
-general-purpose registers.
+Within that reservation, heap[0] is used by `random` and the block
+heap[2]-heap[15] by the stack rotation subroutines which time-share these
+pseudo-registers between the various stdlib subroutines.
By convention, functions which return a pointer will use the address `0` to
represent a `NULL` pointer.
@ dumpheap (111000)
@ Description:
@ Dumps the heap from 'startaddr' to 'endaddr'.
+@ This subroutine stomps on heap[1] after printing the first heap location.
+@ If you dump starting from heap[0], then heap[1] will print inaccurately.
+@ Starting the dump from any other location will work without error.
+@ TODO: Should I use heap[0] and DIE rather than RTS?
+@ At the moment, the ability to continue is too useful to me.
+@ If it's useful to me, it's probably useful to other people.
+@ For now, leave dumpheap as-is.
@ Call Stack:
@ endaddr
@ startaddr <-- TOS
@ <empty>
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
NSSVTTSSSN | Mark: 11000 (memset)
-SSSTTN | PUSH 3
-NSTTSSSSSTN | JSR > 1000001 (spewreg)
@ Store 'pattern' into one memory location on each pass through this loop.
NSSVSSSTTSSSSSSSSSSSN | Mark: 00011000 00000000
-SSSTN | PUSH 1 (ptr)
-TTT | LOAD
-SSSTSN | PUSH 2 (ptr)
-TTT | LOAD
+SNS | DUP
+SSSTTN | PUSH 3
+NSTTTSSN | JSR > 1100 (deepdup)
TSSS | ADD
-SSSTTN | PUSH 3 (ptr)
-TTT | LOAD
+SSSTSSN | PUSH 4
+NSTTTSSN | JSR > 1100 (deepdup)
TTS | STORE
-@ Decrement and check for loop end condition 'count == 0'.
-SSSTN | PUSH 1 (ptr)
-TTT | LOAD
+@ Check for loop end condition 'count == 0'.
SNS | DUP
NTSSSSTTSSSSSSSSSSTN | BRZ > 00011000 00000001
+@ Decrement and loop again.
SSSTN | PUSH 1
TSST | SUBTRACT
-SSSTN | PUSH 1 (ptr)
-SNT | SWAP
-TTS | STORE
NSNSSSTTSSSSSSSSSSSN | JMP > 00011000 00000000
@ Clean up and return
NSSVSSSTTSSSSSSSSSSTN | Mark: 00011000 00000001
SNN | DROP
+SNN | DROP
+SNN | DROP
NTN | RTS
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ <empty>
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
NSSVTTSSTN | Mark: 11001 (memcpy)
-SSSTTN | PUSH 3
-NSTTSSSSSTN | JSR > 1000001 (spewreg)
@ Copy one word on each pass through this loop.
NSSVSSSTTSSTSSSSSSSSN | Mark: 00011001 00000000
-SSSTSN | PUSH 2 (ptr)
-TTT | LOAD
-SSSTN | PUSH 1 (ptr)
-TTT | LOAD
+SNS | DUP
+SSSTTN | PUSH 3
+NSTTTSSN | JSR > 1100 (deepdup)
TSSS | ADD
-SSSTTN | PUSH 3 (ptr)
-TTT | LOAD
-SSSTN | PUSH 1 (ptr)
-TTT | LOAD
+SSSTSN | PUSH 2
+NSTTTSSN | JSR > 1100 (deepdup)
+SSSTSTN | PUSH 5
+NSTTTSSN | JSR > 1100 (deepdup)
TSSS | ADD
TTT | LOAD
TTS | STORE
-@ Decrement and check for loop end conditions.
-SSSTN | PUSH 1 (ptr)
-TTT | LOAD
+@ Check for loop end conditions and decrement.
SNS | DUP
NTSSSSTTSSTSSSSSSSTN | BRZ > 00011001 00000001
SSSTN | PUSH 1
TSST | SUBTRACT
-SSSTN | PUSH 1 (ptr)
-SNT | SWAP
-TTS | STORE
NSNSSSTTSSTSSSSSSSSN | JMP > 00011001 00000000
@ Clean up and return
NSSVSSSTTSSTSSSSSSSTN | Mark: 00011001 00000001
SNN | DROP
+SNN | DROP
+SNN | DROP
NTN | RTS
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
#include <math.pvvs>
NSSVTTSTSN | Mark: 11010 (memrand)
-SSSTN | PUSH 1
-NSTTSSSSSTN | JSR > 1000001 (spewreg)
@ Store random word into one memory location on each pass through this loop.
NSSVSSSTTSTSSSSSSSSSN | Mark: 00011010 00000000
SNS | DUP
-SSSTN | PUSH 1 (ptr)
-TTT | LOAD
+SSSTTN | PUSH 3
+NSTTTSSN | JSR > 1100 (deepdup)
TSSS | ADD
NSTTSSSSN | JSR > 10000 (random)
TTS | STORE
@ Decrement and check loop end conditions
+SNT | SWAP
SNS | DUP
NTSSSSTTSTSSSSSSSSTN | BRZ > 00011010 00000001
SSSTN | PUSH 1
TSST | SUBTRACT
+SNT | SWAP
NSNSSSTTSTSSSSSSSSSN | JMP > 00011010 00000000
@ Clean up and return
NSSVSSSTTSTSSSSSSSSTN | Mark: 00011010 00000001
SNN | DROP
+SNN | DROP
NTN | RTS
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ retvalue <-- TOS
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
NSSVTTSTTN | Mark: 11011 (memcmp)
-SSSTSN | PUSH 2
-NSTTSSSSSTN | JSR > 1000001 (spewreg)
@ Compare one word on each pass through this loop.
+@ TOS> blk2ptr, blk1ptr, count
NSSVSSSTTSTTSSSSSSSSN | Mark: 00011011 00000000
+@ Retrieve *blk2ptr
SNS | DUP
-SNS | DUP
-SSSTN | PUSH 1 (ptr)
-TTT | LOAD
+SSSTSSN | PUSH 4
+NSTTTSSN | JSR > 1100 (deepdup)
TSSS | ADD
TTT | LOAD
-SNT | SWAP
-SSTSN | PUSH 2 (ptr)
-TTT | LOAD
+@ Retrieve *blk1ptr
+SSSTTN | PUSH 3
+NSTTTSSN | JSR > 1100 (deepdup)
+SSSTSTN | PUSH 5
+NSTTTSSN | JSR > 1100 (deepdup)
TSSS | ADD
TTT | LOAD
+@ Compare
TSST | SUBTRACT
+@ TOS> *blk2ptr-*blk1ptr, blk2ptr, blk1ptr, count
NTSSSSTTSTTSSSSSSTSN | BRZ > 00011011 00000010 (jump if words match)
@ Return 'match? = false'
SNN | DROP
+SNN | DROP
+SNN | DROP
SSSTN | PUSH 1
NTN | RTS
@ Decrement and loop again if loop is not complete.
NSSVSSSTTSTTSSSSSSTSN | Mark: 00011011 00000010
-SNS | DUP
+SSSTTN | PUSH 3
+NSTTTSSN | JSR > 1100 (deepdup)
+@ TOS> count, blk2ptr, blk1ptr, count
NTSSSSTTSTTSSSSSSSTN | BRZ > 00011011 00000001 (jump if loop is complete)
+SSSTTN | PUSH 3
+NSTTSTTN | JSR > 1011 (stackrotatereverse)
SSSTN | PUSH 1
-TSST | SUBTRACT
+TSSS | ADD
+SSSTTN | PUSH 3
+NSTTSTSN | JSR > 1010 (stackrotate)
NSNSSSTTSTTSSSSSSSSN | JMP > 00011011 00000000
@ Return 'match? = true'
NSSVSSSTTSTTSSSSSSSTN | Mark: 00011011 00000001
SNN | DROP
+SNN | DROP
+SNN | DROP
SSSSN | PUSH 0
NTN | RTS
@ pointer <-- TOS
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
NSSVTTTSSN | Mark: 11100 (memsrch)
-SSSTTN | PUSH 3
-NSTTSSSSSTN | JSR > 1000001 (spewreg)
+
+@ Setup an 'offset counter' on the stack.
+SSSSN | PUSH 0
@ Compare one word on each pass through this loop.
+@ TOS> counter, address, count, pattern
NSSVSSSTTTSSSSSSSSSSN | Mark: 00011100 00000000
+SNT | SWAP
SNS | DUP
-SSSTN | PUSH 1 (ptr)
-TTT | LOAD
+SSSTTN | PUSH 3
+NSTTSTTN | JSR > 1011 (stackrotatereverse)
+SNS | DUP
+SSSTTN | PUSH 3
+NSTTSTTN | JSR > 1011 (stackrotatereverse)
TSSS | ADD
TTT | LOAD
-SSSTTN | PUSH 3 (ptr)
-TTT | LOAD
+SSSTSTN | PUSH 5
+NSTTTSSN | JSR > 1100 (deepdup)
TSST | SUBTRACT
+@ TOS> pattern-(address+counter), counter, address, count, pattern
NTSSSSTTTSSSSSSSSSTN | BRZ > 00011100 00000001
+
+@ Test for end of loop by comparing 'counter' and 'count'.
SNS | DUP
-SSSTSN | PUSH 2 (ptr)
-TTT | LOAD
+SSSTSSN | PUSH 4
+NSTTTSSN | JSR > 1100 (deepdup)
TSST | SUBTRACT
+@ TOS> counter-count, counter, address, count, pattern
NTSSSSTTTSSSSSSSSTSN | BRZ > 00011100 00000010
+
+@ Increment 'counter' and loop again.
SSSTN | PUSH 1
TSSS | ADD
NSNSSSTTTSSSSSSSSSSN | JMP > 00011100 00000000
@ Found a match. Clean up and return.
NSSVSSSTTTSSSSSSSSSTN | Mark: 00011100 00000001
-SSSTN | PUSH 1 (ptr)
-TTT | LOAD
TSSS | ADD
+SNT | SWAP
+SNN | DROP
+SNT | SWAP
+SNN | DROP
NTN | RTS
@ No match found. Clean up and return.
NSSVSSSTTTSSSSSSSSTSN | Mark: 00011100 00000010
SNN | DROP
-SSSSN | PUSH 0
-NTN | RTS
-
-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-@ Name:
-@ slurpreg (1000000)
-@ Description:
-@ Reads 'count' values from heap to stack in complementary order to 'spewreg'.
-@ Call Stack:
-@ count
-@ Return Stack:
-@ heap[count]
-@ ...
-@ heap[2]
-@ heap[1] <-- TOS
-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-NSSVTSSSSSSN | Mark: 1000000 (slurpreg)
-
-@ Load one word from heap on each pass.
-NSSVSTSSSSSSSSSSSSSSN | Mark: 01000000 00000000
-SNS | DUP
-TTT | LOAD
-SNT | SWAP
-
-@ Check for loop completion.
-@ As a side effect, prepare the next address.
-SSSTN | PUSH 1
-TSST | SUBTRACT
-SNS | DUP
-NTSSTSSSSSSSSSSSSSTN | BRZ > 01000000 00000001
-NSNSTSSSSSSSSSSSSSSN | JMP > 01000000 00000000
-NSSVSTSSSSSSSSSSSSSTN | Mark: 01000000 00000001
SNN | DROP
-NTN | RTS
-
-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-@ Name:
-@ spewreg (1000001)
-@ Description:
-@ Writes 'count' values from stack to heap in this order:
-@ TOS -> heap[1]
-@ TOS+1 -> heap[2]
-@ ...
-@ TOS+n -> heap[count]
-@ This function uses heap[15] for temporary storage, thus limiting the total
-@ registers to 14 since heap[0] is reserved. Since this function populates
-@ the registers, encoding the value here seems a natural location to document
-@ the limit. TODO: Should this be turned into a CPP define?
-@ Call Stack:
-@ data-words
-@ ...
-@ data-words
-@ count <-- TOS
-@ Return Stack:
-@ <empty>
-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-NSSVTSSSSSTN | Mark: 1000001 (spewreg)
-
-@ To simplify other functions, sprewreg shall accept 0 as a valid count value.
-SNS | DUP
-NTSSTSSSSSTSSSSSSSTN | BRZ > 01000001 00000001
-
-@ Create a counter in heap[15] that doubles as a destination pointer generator.
-SSSTTTTN | PUSH 15 (ptr)
-SSSTN | PUSH 1
-TTS | STORE
-
-@ Store one word to heap on each pass.
-NSSVSTSSSSSTSSSSSSSSN | Mark: 01000001 00000000
-SNT | SWAP
-SSSTTTTN | PUSH 15 (ptr)
-TTT | LOAD
-SNT | SWAP
-TTS | STORE
-
-@ Check for loop completion.
-SNS | DUP
-SSSTTTTN | PUSH 15 (ptr)
-TTT | LOAD
-TSST | SUBTRACT
-NTSSTSSSSSTSSSSSSSTN | BRZ > 01000001 00000001
-
-@ Increment heap[15] if continuing.
-SSSTTTTN | PUSH 15 (ptr)
-SNS | DUP
-TTT | LOAD
-SSSTN | PUSH 1
-TSSS | ADD
-TTS | STORE
-NSNSTSSSSSTSSSSSSSSN | JMP > 01000001 00000000
-
-@ Clean up and return.
-NSSVSTSSSSSTSSSSSSSTN | Mark: 01000001 00000001
SNN | DROP
+SNN | DROP
+SSSSN | PUSH 0
NTN | RTS
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ heap[address+1]
@ heap[address] <-- TOS
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#include <stack.pvvs>
NSSVTTTTSN | Mark: 11110 (slurp)
@ Load one word from heap on each pass.
@ Return Stack:
@ <empty>
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#include <stack.pvvs>
NSSVTTTTTN | Mark: 11111 (spew)
-SSSTSN | PUSH 2
-NSTTSSSSSTN | JSR > 1000001 (spewreg)
-@ Create a counter in heap[3] that doubles as a dest. pointer offset generator.
-SSSTTN | PUSH 3 (ptr)
+@ Create a counter that doubles as a dest. pointer offset generator.
SSSSN | PUSH 0
-TTS | STORE
@ Store one word to heap on each pass.
NSSVSSSTTTTTSSSSSSSSN | Mark: 00011111 00000000
-SSSTSN | PUSH 2 (ptr)
-TTT | LOAD
-SSSTTN | PUSH 3 (ptr)
-TTT | LOAD
+SNS | DUP
+SSSTSSN | PUSH 4
+NSTTTSSN | JSR > 1100 (deepdup)
TSSS | ADD
-SNT | SWAP
+SSSTSTN | PUSH 5
+NSTTSTTN | JSR > 1011 (stackrotatereverse)
TTS | STORE
@ Check for loop completion.
-SSSTN | PUSH 1 (ptr)
-TTT | LOAD
-SSSTTN | PUSH 3 (ptr)
-TTT | LOAD
+SNT | SWAP
+SNS | DUP
+SSSTTN | PUSH 3
+NSTTSTTN | JSR > 1011 (stackrotatereverse)
+SNS | DUP
+SSSTTN | PUSH 3
+NSTTSTTN | JSR > 1011 (stackrotatereverse)
TSST | SUBTRACT
NTSSSSTTTTTSSSSSSSTN | BRZ > 00011111 00000001
-@ Increment heap[3] if continuing.
-SSSTTN | PUSH 3 (ptr)
-SNS | DUP
-TTT | LOAD
-SSSTN | PUSH 1
+@ Increment counter.
+SSSTN | PUSH 1
TSSS | ADD
-TTS | STORE
NSNSSSTTTTTSSSSSSSSN | JMP > 00011111 00000000
@ Clean up and return.
NSSVSSSTTTTTSSSSSSSTN | Mark: 00011111 00000001
+SNN | DROP
+SNN | DROP
+SNN | DROP
NTN | RTS
#endif
@ Name:
@ stackrotate
@ Description:
-@ Maximum rotation depth is five. Stomps on heap[9]-heap[14].
-@ Assumes rotation depth greater than two, otherwise use SWAP.
+@ Maximum rotation depth is 14. Stomps on heap[1]-heap[15].
@ Call Stack:
@ stack word n
@ ...
@ For the convenience of other functions, modulo the
@ rotation depth by the available registers.
-SSSTSTN | PUSH 5
+SSSTTTSN | PUSH 14
TSTT | MODULO
-@ Use heap[14] for generating register addresses.
-SSSTTTSN | PUSH 14 (ptr)
+@ Use heap[15] for generating register addresses.
+SSSTTTTN | PUSH 15 (ptr)
SSSSN | PUSH 0
TTS | STORE
@ Dump one word from stack to heap each pass through the loop.
NSSVSSSSTSTSSSSSSSSSN | Mark: 00001010 00000000
SNT | SWAP
-SSSTSSTN | PUSH 9 (starting register)
-SSSTTTSN | PUSH 14 (ptr)
+SSSTN | PUSH 1 (starting register)
+SSSTTTTN | PUSH 15 (ptr)
TTT | LOAD
TSSS | ADD
SNT | SWAP
@ See if the loop is complete.
SNS | DUP
-SSSTTTSN | PUSH 14 (ptr)
+SSSTTTTN | PUSH 15 (ptr)
TTT | LOAD
SSSTN | PUSH 1
TSSS | ADD
NTSSSSSTSTSSSSSSSSTN | BRZ > 00001010 00000001
@ Increment the loop counter
-SSSTTTSN | PUSH 14 (ptr)
+SSSTTTTN | PUSH 15 (ptr)
TTT | LOAD
SSSTN | PUSH 1
TSSS | ADD
-SSSTTTSN | PUSH 14 (ptr)
+SSSTTTTN | PUSH 15 (ptr)
SNT | SWAP
TTS | STORE
NSNSSSSTSTSSSSSSSSSN | JMP > 00001010 00000000
@ The correct number of words have been stored to registers.
@ Time to read them back in rotated order.
-@ First, prepare the counter in heap[14] again.
+@ First, prepare the counter in heap[15] again.
@ This consumes 'rd' from the stack.
NSSVSSSSTSTSSSSSSSSTN | Mark: 00001010 00000001
SSSTN | PUSH 1
TSST | SUBTRACT
-SSSTTTSN | PUSH 14 (ptr)
+SSSTTTTN | PUSH 15 (ptr)
SNT | SWAP
TTS | STORE
@ Second, read in the old TOS manually.
-SSSTSSTN | PUSH 9 (starting register)
+SSSTN | PUSH 1 (starting register)
TTT | LOAD
@ Read one word per pass through this loop.
NSSVSSSSTSTSSSSSSSTSN | Mark: 00001010 00000010
-SSSTSSTN | PUSH 9 (starting register)
-SSSTTTSN | PUSH 14 (ptr)
+SSSTN | PUSH 1 (starting register)
+SSSTTTTN | PUSH 15 (ptr)
TTT | LOAD
TSSS | ADD
TTT | LOAD
@ See if the loop is complete.
-SSSTTTSN | PUSH 14 (ptr)
+SSSTTTTN | PUSH 15 (ptr)
TTT | LOAD
SSSTN | PUSH 1
TSST | SUBTRACT
NTSSSSSTSTSSSSSSSTTN | BRZ > 00001010 00000011
@ Decrement the loop counter and loop again.
-SSSTTTSN | PUSH 14 (ptr)
+SSSTTTTN | PUSH 15 (ptr)
TTT | LOAD
SSSTN | PUSH 1
TSST | SUBTRACT
-SSSTTTSN | PUSH 14 (ptr)
+SSSTTTTN | PUSH 15 (ptr)
SNT | SWAP
TTS | STORE
NSNSSSSTSTSSSSSSSTSN | JMP > 00001010 00000010
@ Name:
@ stackrotatereverse
@ Description:
-@ Maximum rotation depth is five. Stomps on heap[9]-heap[14].
-@ Assumes rotation depth greater than two, otherwise use SWAP.
+@ Maximum rotation depth is 14. Stomps on heap[1]-heap[15].
@ Call Stack:
@ stack word n
@ ...
@ For the convenience of other functions, modulo the
@ rotation depth by the available registers.
-SSSTSTN | PUSH 5
+SSSTTTSN | PUSH 14
TSTT | MODULO
-@ Use heap[14] for generating register addresses.
-SSSTTTSN | PUSH 14 (ptr)
+@ Use heap[15] for generating register addresses.
+SSSTTTTN | PUSH 15 (ptr)
SSSSN | PUSH 0
TTS | STORE
@ Dump one word from stack to heap each pass through the loop.
NSSVSSSSTSTTSSSSSSSSN | Mark: 00001011 00000000
SNT | SWAP
-SSSTSSTN | PUSH 9 (starting register)
-SSSTTTSN | PUSH 14 (ptr)
+SSSTN | PUSH 1 (starting register)
+SSSTTTTN | PUSH 15 (ptr)
TTT | LOAD
TSSS | ADD
SNT | SWAP
@ See if the loop is complete.
SNS | DUP
-SSSTTTSN | PUSH 14 (ptr)
+SSSTTTTN | PUSH 15 (ptr)
TTT | LOAD
SSSTN | PUSH 1
TSSS | ADD
NTSSSSSTSTTSSSSSSSTN | BRZ > 00001011 00000001
@ Increment the loop counter
-SSSTTTSN | PUSH 14 (ptr)
+SSSTTTTN | PUSH 15 (ptr)
TTT | LOAD
SSSTN | PUSH 1
TSSS | ADD
-SSSTTTSN | PUSH 14 (ptr)
+SSSTTTTN | PUSH 15 (ptr)
SNT | SWAP
TTS | STORE
NSNSSSSTSTTSSSSSSSSN | JMP > 00001011 00000000
@ The correct number of words have been stored to registers.
@ Time to read them back in rotated order.
-@ First, prepare the counter in heap[14] again.
+@ First, prepare the counter in heap[15] again.
NSSVSSSSTSTTSSSSSSSTN | Mark: 00001011 00000001
SSSTN | PUSH 1
TSST | SUBTRACT
SNS | DUP
SSSTN | PUSH 1
TSST | SUBTRACT
-SSSTTTSN | PUSH 14 (ptr)
+SSSTTTTN | PUSH 15 (ptr)
SNT | SWAP
TTS | STORE
@ Read one word per pass through this loop.
@ Store it behind 'rd' on the stack.
NSSVSSSSTSTTSSSSSSTSN | Mark: 00001011 00000010
-SSSTSSTN | PUSH 9 (starting register)
-SSSTTTSN | PUSH 14 (ptr)
+SSSTN | PUSH 1 (starting register)
+SSSTTTTN | PUSH 15 (ptr)
TTT | LOAD
TSSS | ADD
TTT | LOAD
SNT | SWAP
@ See if the loop is complete.
-SSSTTTSN | PUSH 14 (ptr)
+SSSTTTTN | PUSH 15 (ptr)
TTT | LOAD
NTSSSSSTSTTSSSSSSTTN | BRZ > 00001011 00000011
@ Decrement the loop counter and loop again.
-SSSTTTSN | PUSH 14 (ptr)
+SSSTTTTN | PUSH 15 (ptr)
TTT | LOAD
SSSTN | PUSH 1
TSST | SUBTRACT
-SSSTTTSN | PUSH 14 (ptr)
+SSSTTTTN | PUSH 15 (ptr)
SNT | SWAP
TTS | STORE
NSNSSSSTSTTSSSSSSTSN | JMP > 00001011 00000010
@ Read in the final value manually and return.
NSSVSSSSTSTTSSSSSSTTN | Mark: 00001011 00000011
-SSSTSSTN | PUSH 9 (starting register)
+SSSTN | PUSH 1 (starting register)
TSSS | ADD
TTT | LOAD
NTN | RTS
@ ASCII '\0'
@ substitution n
@ <remainder of call stack is unchanged>
-@ Maximum of 7 substitutions.
+@ Maximum substitutions determined by upper heap limit in stackrotate and
+@ stackrotatereverse subroutines.
@ Call Stack:
@ ACSII '\0'
@ string word n
#include <string.pvvs>
NSSVTSSSN | Mark: 1000 (printf)
-@ Copy any substitution words into heap registers.
-NSTTSSSSSTN | JSR > 1000001 (spewreg)
-
-@ heap[8] will track the current substitution register.
-SSSTSSSN | PUSH 8 (ptr)
-SSSTN | PUSH 1
-TTS | STORE
-
@ If the stack contains an empty string (i.e. just an ASCII '\0'), the next
@ word is a pointer we must use to load the string from the heap.
+@ This will leave the stack looking exactly like the example call stack above.
@ Do the test this way so we can keep the code inline.
SNS | DUP
+SSSTSN | PUSH 2
+TSSS | ADD
+NSTTTSSN | JSR > 1100 (deepdup)
SSTTN | PUSH -1
TSSN | MULTIPLY
NTTSSSSTSSSSSSSSSSTN | BMI > 00001000 00000001
+SNS | DUP
+SSSTSN | PUSH 2
+TSSS | ADD
+NSTTSTTN | JSR > 1011 (stackrotatereverse)
SNN | DROP
SNS | DUP
-NSTTSSSSSN | JSR > 100000 (strlen)
-NSTTTTTSN | JSR > 11110 (slurp)
-
-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-@ Initialization is now complete.
-@ Stack contains a printf-compatible, null-terminated string.
-@ heap[1]-heap[7] contain the substitutions, if any.
-@ heap[8] tracks which substitution is next.
-@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+SSSTSN | PUSH 2
+TSSS | ADD
+NSTTSTTN | JSR > 1011 (stackrotatereverse)
+NSTSSSSTSSSTSSSTTSSN | JSR > 00001000 10001100 (printf_deepslurp)
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ The rest of printf parses a string according to the following information.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@
-@ The next block tests the TOS against all possible level 1 branches (see above).
+@ The next block tests the char against all possible level 1 branches (see above).
@ If there is a match, execution jumps to the appropriate level 2 branch label.
@ If no match is found, print the character and move on.
@@@@@@@@@@@@@@@@@@@@
NSSVSSSSTSSSSSSSSSSTN | Mark: 00001000 00000001
+@ Move the next character of the string to TOS.
+NSTSSSSTSSSTSSSTSTTN | JSR > 00001000 10001011 (next char to TOS)
@ TOS is an ASCII '\ '. Jump to process the possible level 2 branches.
SNS | DUP
SSSTSTTTSSN | PUSH ASCII slash
@@@@@@@@@@@@@@@@@@@@
NSSVSSSSTSSSSSSSSSTSN | Mark: 00001000 00000010
SNN | DROP
+@ Move the next character of the string to TOS.
+NSTSSSSTSSSTSSSTSTTN | JSR > 00001000 10001011 (next char to TOS)
@ Check for ASCII '\n'
SNS | DUP
SSSTTSTTTSN | PUSH ASCII 'n'
@@@@@@@@@@@@@@@@@@@@
NSSVSSSSTSSSSSSSSSTTN | Mark: 00001000 00000011
SNN | DROP
+@ Move the next character of the string to TOS.
+NSTSSSSTSSSTSSSTSTTN | JSR > 00001000 10001011 (next char to TOS)
@ Check for ASCII 'c' - Print character
SNS | DUP
SSSTTSSSTTN | PUSH ASCII 'c'
@@@@@@@@@@@@@@@@@@@@
@ These are utility labels to call the appropriate type of output subroutine.
-@ After output, they increment the substition counter (heap[8])
-@ and loop back to testing level 1 branches.
+@ After output, they decrement the substition counter and loop back to testing
+@ level 1 branches.
@@@@@@@@@@@@@@@@@@@@
@ Print a character
NSSVSSSSTSSSSSSSSTTSN | Mark: 00001000 00000110
SNN | DROP
-SSSTSSSN | PUSH 8 (ptr)
-TTT | LOAD
-TTT | LOAD
+SNT | SWAP
TNSS | PUTC
-NSTSSSSTSSSTSSSSSSSN | JSR > 00001000 10000000 (increment heap[8])
+SSSTN | PUSH 1
+TSST | SUBTRACT
NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
@ Print a string
NSSVSSSSTSSSSSSSSTTTN | Mark: 00001000 00000111
SNN | DROP
-SSSTSSSN | PUSH 8 (ptr)
-TTT | LOAD
-TTT | LOAD
+SNT | SWAP
NSTTSSSTSTN | JSR > 1000101 (print string from heap)
-NSTSSSSTSSSTSSSSSSSN | JSR > 00001000 10000000 (increment heap[8])
+SSSTN | PUSH 1
+TSST | SUBTRACT
NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
@ Print a decimal digit
NSSVSSSSTSSSSSSSTSSSN | Mark: 00001000 00001000
SNN | DROP
-SSSTSSSN | PUSH 8 (ptr)
-TTT | LOAD
-TTT | LOAD
+SNT | SWAP
TNST | PUTDIGIT
-NSTSSSSTSSSTSSSSSSSN | JSR > 00001000 10000000 (increment heap[8])
+SSSTN | PUSH 1
+TSST | SUBTRACT
NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
@ Print an unsigned integer
NSSVSSSSTSSSSSSSTSSTN | Mark: 00001000 00001001
SNN | DROP
-SSSTSSSN | PUSH 8 (ptr)
-TTT | LOAD
-TTT | LOAD
+SNT | SWAP
NSTTSSSSTTN | JSR > 1000011 (print magnitude of number from stack)
-NSTSSSSTSSSTSSSSSSSN | JSR > 00001000 10000000 (increment heap[8])
+SSSTN | PUSH 1
+TSST | SUBTRACT
NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
@ Print a signed integer
NSSVSSSSTSSSSSSSTSTSN | Mark: 00001000 00001010
SNN | DROP
-SSSTSSSN | PUSH 8 (ptr)
-TTT | LOAD
-TTT | LOAD
+SNT | SWAP
NSTTSSTN | JSR > 1001 (print number from stack)
-NSTSSSSTSSSTSSSSSSSN | JSR > 00001000 10000000 (increment heap[8])
+SSSTN | PUSH 1
+TSST | SUBTRACT
NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ These are misc labels associated with the printf function.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
-@ Increments heap[8]. Used after a substitution is complete.
-NSSVSSSSTSSSTSSSSSSSN | Mark: 00001000 10000000 (increment heap[8])
-SSSTSSSN | PUSH 8 (ptr)
-TTT | LOAD
-SSSTN | PUSH 1
+@ Found an ASCII "\0" when processing the format string. Clean up and exit.
+NSSVSSSSTSSSSSSSSSSSN | Mark: 00001000 00000000
+SNN | DROP
+NTN | RTS
+
+@ Move the next string character to TOS.
+@ Stack should look like the printf call stack, with num-of-subs at TOS.
+NSSVSSSSTSSSTSSSTSTTN | Mark: 00001000 10001011 (next char to TOS)
+SNS | DUP
+SSSTSN | PUSH 2
TSSS | ADD
-SSSTSSSN | PUSH 8 (ptr)
-SNT | SWAP
-TTS | STORE
+NSTTSTTN | JSR > 1011 (stackrotatereverse)
NTN | RTS
-@ Found an ASCII "\0" when processing the format string. Clean up and exit.
-NSSVSSSSTSSSSSSSSSSSN | Mark: 00001000 00000000
+@ Slurps a string from the heap to the stack, storing it behind the substitutions.
+@ Call Stack:
+@ substitution n
+@ ...
+@ substitution 1
+@ number of substitutions <-- TOS
+@ pointer to string
+@ Return Stack:
+@ ACSII '\0'
+@ string word n
+@ ...
+@ string word 1
+@ substitution n
+@ ...
+@ substitution 1
+@ number of substitutions <-- TOS
+@ TODO: This, along with a deepspew, should probably be stdlib routines.
+NSSVSSSSTSSSTSSSTTSSN | Mark: 00001000 10001100 (printf_deepslurp)
+SNS | DUP
+@ Advance a duplicate copy of the pointer until it points to the null-terminator.
+NSSVSSSSTSSSTSSSTTSTN | Mark: 00001000 10001101
+SNS | DUP
+TTT | LOAD
+NTSSSSSTSSSTSSSTTTSN | BRZ > 00001000 10001110
+SSSTN | PUSH 1
+TSSS | ADD
+NSNSSSSTSSSTSSSTTSTN | JMP > 00001000 10001101
+@ Load a character to the stack on each pass through this loop.
+NSSVSSSSTSSSTSSSTTTSN | Mark: 00001000 10001110
+SNS | DUP
+TTT | LOAD
+SSSTSSN | PUSH 4
+NSTTTSSN | JSR > 1100 (deepdup)
+SSSTSSN | PUSH 4
+TSSS | ADD
+NSTTSTSN | JSR > 1010 (stackrotate)
+@ Test for end of loop.
+SNS | DUP
+SSSTTN | PUSH 3
+NSTTTSSN | JSR > 1100 (deepdup)
+TSST | SUBTRACT
+NTSSSSSTSSSTSSSTTTTN | BRZ > 00001000 10001111
+@ Decrement pointer to end of string, loop again.
+SSSTN | PUSH 1
+TSST | SUBTRACT
+NSNSSSSTSSSTSSSTTTSN | JMP > 00001000 10001110
+@ Clean up and return.
+NSSVSSSSTSSSTSSSTTTTN | Mark: 00001000 10001111
+SNN | DROP
SNN | DROP
NTN | RTS