Modified stdlib to use stack rotations to timeshare heap registers.
authorAaron Taylor <ataylor@subgeniuskitty.com>
Fri, 26 Jul 2019 08:28:52 +0000 (01:28 -0700)
committerAaron Taylor <ataylor@subgeniuskitty.com>
Fri, 26 Jul 2019 08:28:52 +0000 (01:28 -0700)
The stdlib is probably broken at this commit. Next step is a test suite.

stdlib/README.md
stdlib/debug.pvvs
stdlib/heap.pvvs
stdlib/stack.pvvs
stdlib/stdio.pvvs

index b41e251..a98b7c7 100644 (file)
@@ -19,9 +19,9 @@ following reservations:
 ## Heap and Pointers ##
 
 The first 16 heap addresses (`0-15`) are reserved when using the stdlib.
 ## 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.
 
 By convention, functions which return a pointer will use the address `0` to
 represent a `NULL` pointer.
index 138b2cb..4cc8a73 100644 (file)
@@ -6,6 +6,13 @@
 @   dumpheap (111000)
 @ Description:
 @   Dumps the heap from 'startaddr' to 'endaddr'.
 @   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
 @ Call Stack:
 @   endaddr
 @   startaddr  <-- TOS
index 4953fad..2c5eb79 100644 (file)
 @   <empty>
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 NSSVTTSSSN              | Mark: 11000 (memset)
 @   <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
 
 @ 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
 TSSS                    | ADD
-SSSTTN                  | PUSH 3 (ptr)
-TTT                     | LOAD
+SSSTSSN                 | PUSH 4
+NSTTTSSN                | JSR > 1100 (deepdup)
 TTS                     | STORE
 
 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
 SNS                     | DUP
 NTSSSSTTSSSSSSSSSSTN    | BRZ > 00011000 00000001
+@ Decrement and loop again.
 SSSTN                   | PUSH 1
 TSST                    | SUBTRACT
 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
 NSNSSSTTSSSSSSSSSSSN    | JMP > 00011000 00000000
 
 @ Clean up and return
 NSSVSSSTTSSSSSSSSSSTN   | Mark: 00011000 00000001
 SNN                     | DROP
+SNN                     | DROP
+SNN                     | DROP
 NTN                     | RTS
 
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 NTN                     | RTS
 
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -58,39 +53,33 @@ NTN                     | RTS
 @   <empty>
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 NSSVTTSSTN              | Mark: 11001 (memcpy)
 @   <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
 
 @ 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
 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
 
 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
 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
 NSNSSSTTSSTSSSSSSSSN    | JMP > 00011001 00000000
 
 @ Clean up and return
 NSSVSSSTTSSTSSSSSSSTN   | Mark: 00011001 00000001
 SNN                     | DROP
+SNN                     | DROP
+SNN                     | DROP
 NTN                     | RTS
 
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 NTN                     | RTS
 
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -106,28 +95,29 @@ NTN                     | RTS
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 #include <math.pvvs>
 NSSVTTSTSN              | Mark: 11010 (memrand)
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 #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
 
 @ 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
 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
 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
 NSNSSSTTSTSSSSSSSSSN    | JMP > 00011010 00000000
 
 @ Clean up and return
 NSSVSSSTTSTSSSSSSSSTN   | Mark: 00011010 00000001
 SNN                     | DROP
+SNN                     | DROP
 NTN                     | RTS
 
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 NTN                     | RTS
 
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -147,41 +137,54 @@ NTN                     | RTS
 @   retvalue <-- TOS
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 NSSVTTSTTN              | Mark: 11011 (memcmp)
 @   retvalue <-- TOS
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 NSSVTTSTTN              | Mark: 11011 (memcmp)
-SSSTSN                  | PUSH 2
-NSTTSSSSSTN             | JSR > 1000001 (spewreg)
 
 @ Compare one word on each pass through this loop.
 
 @ Compare one word on each pass through this loop.
+@ TOS> blk2ptr, blk1ptr, count
 NSSVSSSTTSTTSSSSSSSSN   | Mark: 00011011 00000000
 NSSVSSSTTSTTSSSSSSSSN   | Mark: 00011011 00000000
+@ Retrieve *blk2ptr
 SNS                     | DUP
 SNS                     | DUP
-SNS                     | DUP
-SSSTN                   | PUSH 1 (ptr)
-TTT                     | LOAD
+SSSTSSN                 | PUSH 4
+NSTTTSSN                | JSR > 1100 (deepdup)
 TSSS                    | ADD
 TTT                     | LOAD
 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
 TSSS                    | ADD
 TTT                     | LOAD
+@ Compare
 TSST                    | SUBTRACT
 TSST                    | SUBTRACT
+@ TOS> *blk2ptr-*blk1ptr, blk2ptr, blk1ptr, count
 NTSSSSTTSTTSSSSSSTSN    | BRZ > 00011011 00000010 (jump if words match)
 
 @ Return 'match? = false'
 SNN                     | DROP
 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
 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)
 NTSSSSTTSTTSSSSSSSTN    | BRZ > 00011011 00000001 (jump if loop is complete)
+SSSTTN                  | PUSH 3
+NSTTSTTN                | JSR > 1011 (stackrotatereverse)
 SSSTN                   | PUSH 1
 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
 NSNSSSTTSTTSSSSSSSSN    | JMP > 00011011 00000000
 
 @ Return 'match? = true'
 NSSVSSSTTSTTSSSSSSSTN   | Mark: 00011011 00000001
 SNN                     | DROP
+SNN                     | DROP
+SNN                     | DROP
 SSSSN                   | PUSH 0
 NTN                     | RTS
 
 SSSSN                   | PUSH 0
 NTN                     | RTS
 
@@ -200,133 +203,57 @@ NTN                     | RTS
 @   pointer <-- TOS
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 NSSVTTTSSN              | Mark: 11100 (memsrch)
 @   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.
 
 @ Compare one word on each pass through this loop.
+@ TOS> counter, address, count, pattern
 NSSVSSSTTTSSSSSSSSSSN   | Mark: 00011100 00000000
 NSSVSSSTTTSSSSSSSSSSN   | Mark: 00011100 00000000
+SNT                     | SWAP
 SNS                     | DUP
 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
 TSSS                    | ADD
 TTT                     | LOAD
-SSSTTN                  | PUSH 3 (ptr)
-TTT                     | LOAD
+SSSTSTN                 | PUSH 5
+NSTTTSSN                | JSR > 1100 (deepdup)
 TSST                    | SUBTRACT
 TSST                    | SUBTRACT
+@ TOS> pattern-(address+counter), counter, address, count, pattern
 NTSSSSTTTSSSSSSSSSTN    | BRZ > 00011100 00000001
 NTSSSSTTTSSSSSSSSSTN    | BRZ > 00011100 00000001
+
+@ Test for end of loop by comparing 'counter' and 'count'.
 SNS                     | DUP
 SNS                     | DUP
-SSSTSN                  | PUSH 2 (ptr)
-TTT                     | LOAD
+SSSTSSN                 | PUSH 4
+NSTTTSSN                | JSR > 1100 (deepdup)
 TSST                    | SUBTRACT
 TSST                    | SUBTRACT
+@ TOS> counter-count, counter, address, count, pattern
 NTSSSSTTTSSSSSSSSTSN    | BRZ > 00011100 00000010
 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
 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
 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
 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
 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
+SNN                     | DROP
+SSSSN                   | PUSH 0
 NTN                     | RTS
 
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 NTN                     | RTS
 
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@ -343,6 +270,7 @@ NTN                     | RTS
 @   heap[address+1]
 @   heap[address]  <-- TOS
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 @   heap[address+1]
 @   heap[address]  <-- TOS
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#include <stack.pvvs>
 NSSVTTTTSN              | Mark: 11110 (slurp)
 
 @ Load one word from heap on each pass.
 NSSVTTTTSN              | Mark: 11110 (slurp)
 
 @ Load one word from heap on each pass.
@@ -390,44 +318,43 @@ NTN                     | RTS
 @ Return Stack:
 @   <empty>
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 @ Return Stack:
 @   <empty>
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#include <stack.pvvs>
 NSSVTTTTTN              | Mark: 11111 (spew)
 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
 SSSSN                   | PUSH 0
-TTS                     | STORE
 
 @ Store one word to heap on each pass.
 NSSVSSSTTTTTSSSSSSSSN   | Mark: 00011111 00000000
 
 @ 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
 TSSS                    | ADD
-SNT                     | SWAP
+SSSTSTN                 | PUSH 5
+NSTTSTTN                | JSR > 1011 (stackrotatereverse)
 TTS                     | STORE
 
 @ Check for loop completion.
 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
 
 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
 TSSS                    | ADD
-TTS                     | STORE
 NSNSSSTTTTTSSSSSSSSN    | JMP > 00011111 00000000
 
 @ Clean up and return.
 NSSVSSSTTTTTSSSSSSSTN   | Mark: 00011111 00000001
 NSNSSSTTTTTSSSSSSSSN    | JMP > 00011111 00000000
 
 @ Clean up and return.
 NSSVSSSTTTTTSSSSSSSTN   | Mark: 00011111 00000001
+SNN                     | DROP
+SNN                     | DROP
+SNN                     | DROP
 NTN                     | RTS
 
 #endif
 NTN                     | RTS
 
 #endif
index 417b3bb..c543d98 100644 (file)
@@ -5,8 +5,7 @@
 @ Name:
 @   stackrotate
 @ Description:
 @ 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
 @   ...
 @ Call Stack:
 @   stack word n
 @   ...
@@ -23,19 +22,19 @@ NSSVTSTSN               | Mark: 1010 (stackrotate)
 
 @ For the convenience of other functions, modulo the
 @ rotation depth by the available registers.
 
 @ For the convenience of other functions, modulo the
 @ rotation depth by the available registers.
-SSSTSTN                 | PUSH 5
+SSSTTTSN                | PUSH 14
 TSTT                    | MODULO
 
 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
 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
 TTT                     | LOAD
 TSSS                    | ADD
 SNT                     | SWAP
@@ -43,7 +42,7 @@ TTS                     | STORE
 
 @ See if the loop is complete.
 SNS                     | DUP
 
 @ See if the loop is complete.
 SNS                     | DUP
-SSSTTTSN                | PUSH 14 (ptr)
+SSSTTTTN                | PUSH 15 (ptr)
 TTT                     | LOAD
 SSSTN                   | PUSH 1
 TSSS                    | ADD
 TTT                     | LOAD
 SSSTN                   | PUSH 1
 TSSS                    | ADD
@@ -51,11 +50,11 @@ TSST                    | SUBTRACT
 NTSSSSSTSTSSSSSSSSTN    | BRZ > 00001010 00000001
 
 @ Increment the loop counter
 NTSSSSSTSTSSSSSSSSTN    | BRZ > 00001010 00000001
 
 @ Increment the loop counter
-SSSTTTSN                | PUSH 14 (ptr)
+SSSTTTTN                | PUSH 15 (ptr)
 TTT                     | LOAD
 SSSTN                   | PUSH 1
 TSSS                    | ADD
 TTT                     | LOAD
 SSSTN                   | PUSH 1
 TSSS                    | ADD
-SSSTTTSN                | PUSH 14 (ptr)
+SSSTTTTN                | PUSH 15 (ptr)
 SNT                     | SWAP
 TTS                     | STORE
 NSNSSSSTSTSSSSSSSSSN    | JMP > 00001010 00000000
 SNT                     | SWAP
 TTS                     | STORE
 NSNSSSSTSTSSSSSSSSSN    | JMP > 00001010 00000000
@@ -63,40 +62,40 @@ NSNSSSSTSTSSSSSSSSSN    | JMP > 00001010 00000000
 @ The correct number of words have been stored to registers.
 @ Time to read them back in rotated order.
 
 @ 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
 @ 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.
 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
 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.
 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.
 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
 TTT                     | LOAD
 SSSTN                   | PUSH 1
 TSST                    | SUBTRACT
-SSSTTTSN                | PUSH 14 (ptr)
+SSSTTTTN                | PUSH 15 (ptr)
 SNT                     | SWAP
 TTS                     | STORE
 NSNSSSSTSTSSSSSSSTSN    | JMP > 00001010 00000010
 SNT                     | SWAP
 TTS                     | STORE
 NSNSSSSTSTSSSSSSSTSN    | JMP > 00001010 00000010
@@ -109,8 +108,7 @@ NTN                     | RTS
 @ Name:
 @   stackrotatereverse
 @ Description:
 @ 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
 @   ...
 @ Call Stack:
 @   stack word n
 @   ...
@@ -127,19 +125,19 @@ NSSVTSTTN               | Mark: 1011 (stackrotatereverse)
 
 @ For the convenience of other functions, modulo the
 @ rotation depth by the available registers.
 
 @ For the convenience of other functions, modulo the
 @ rotation depth by the available registers.
-SSSTSTN                 | PUSH 5
+SSSTTTSN                | PUSH 14
 TSTT                    | MODULO
 
 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
 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
 TTT                     | LOAD
 TSSS                    | ADD
 SNT                     | SWAP
@@ -147,7 +145,7 @@ TTS                     | STORE
 
 @ See if the loop is complete.
 SNS                     | DUP
 
 @ See if the loop is complete.
 SNS                     | DUP
-SSSTTTSN                | PUSH 14 (ptr)
+SSSTTTTN                | PUSH 15 (ptr)
 TTT                     | LOAD
 SSSTN                   | PUSH 1
 TSSS                    | ADD
 TTT                     | LOAD
 SSSTN                   | PUSH 1
 TSSS                    | ADD
@@ -155,11 +153,11 @@ TSST                    | SUBTRACT
 NTSSSSSTSTTSSSSSSSTN    | BRZ > 00001011 00000001
 
 @ Increment the loop counter
 NTSSSSSTSTTSSSSSSSTN    | BRZ > 00001011 00000001
 
 @ Increment the loop counter
-SSSTTTSN                | PUSH 14 (ptr)
+SSSTTTTN                | PUSH 15 (ptr)
 TTT                     | LOAD
 SSSTN                   | PUSH 1
 TSSS                    | ADD
 TTT                     | LOAD
 SSSTN                   | PUSH 1
 TSSS                    | ADD
-SSSTTTSN                | PUSH 14 (ptr)
+SSSTTTTN                | PUSH 15 (ptr)
 SNT                     | SWAP
 TTS                     | STORE
 NSNSSSSTSTTSSSSSSSSN    | JMP > 00001011 00000000
 SNT                     | SWAP
 TTS                     | STORE
 NSNSSSSTSTTSSSSSSSSN    | JMP > 00001011 00000000
@@ -167,45 +165,45 @@ NSNSSSSTSTTSSSSSSSSN    | JMP > 00001011 00000000
 @ The correct number of words have been stored to registers.
 @ Time to read them back in rotated order.
 
 @ 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
 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
 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.
 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.
 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
 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
 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
 TSSS                    | ADD
 TTT                     | LOAD
 NTN                     | RTS
index 950ad6c..539df7d 100644 (file)
@@ -140,7 +140,8 @@ NTN                     | RTS
 @         ASCII '\0'
 @         substitution n
 @         <remainder of call stack is unchanged>
 @         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
 @ Call Stack:
 @   ACSII '\0'
 @   string word n
@@ -157,32 +158,27 @@ NTN                     | RTS
 #include <string.pvvs>
 NSSVTSSSN               | Mark: 1000 (printf)
 
 #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.
 @ 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
 @ 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
 SSTTN                   | PUSH -1
 TSSN                    | MULTIPLY
 NTTSSSSTSSSSSSSSSSTN    | BMI > 00001000 00000001
+SNS                     | DUP
+SSSTSN                  | PUSH 2
+TSSS                    | ADD
+NSTTSTTN                | JSR > 1011 (stackrotatereverse)
 SNN                     | DROP
 SNS                     | DUP
 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 rest of printf parses a string according to the following information.
@@ -204,11 +200,13 @@ NSTTTTTSN               | JSR > 11110 (slurp)
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 @@@@@@@@@@@@@@@@@@@@
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 @@@@@@@@@@@@@@@@@@@@
-@ 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
 @ 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
 @ TOS is an ASCII '\ '. Jump to process the possible level 2 branches.
 SNS                     | DUP
 SSSTSTTTSSN             | PUSH ASCII slash
@@ -238,6 +236,8 @@ NSNSSSSTSSSSSSSSSSTN    | JMP > 00001000 00000001
 @@@@@@@@@@@@@@@@@@@@
 NSSVSSSSTSSSSSSSSSTSN   | Mark: 00001000 00000010
 SNN                     | DROP
 @@@@@@@@@@@@@@@@@@@@
 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'
 @ Check for ASCII '\n'
 SNS                     | DUP
 SSSTTSTTTSN             | PUSH ASCII 'n'
@@ -282,6 +282,8 @@ NSNSSSSTSSSSSSSSSSTN    | JMP > 00001000 00000001
 @@@@@@@@@@@@@@@@@@@@
 NSSVSSSSTSSSSSSSSSTTN   | Mark: 00001000 00000011
 SNN                     | DROP
 @@@@@@@@@@@@@@@@@@@@
 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'
 @ Check for ASCII 'c' - Print character
 SNS                     | DUP
 SSSTTSSSTTN             | PUSH ASCII 'c'
@@ -317,73 +319,118 @@ NSNSSSSTSSSSSSSSSSTN    | JMP > 00001000 00000001
 
 @@@@@@@@@@@@@@@@@@@@
 @ These are utility labels to call the appropriate type of output subroutine.
 
 @@@@@@@@@@@@@@@@@@@@
 @ 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
 @@@@@@@@@@@@@@@@@@@@
 
 @ Print a character
 NSSVSSSSTSSSSSSSSTTSN   | Mark: 00001000 00000110
 SNN                     | DROP
-SSSTSSSN                | PUSH 8 (ptr)
-TTT                     | LOAD
-TTT                     | LOAD
+SNT                     | SWAP
 TNSS                    | PUTC
 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
 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)
 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
 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
 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
 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)
 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
 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)
 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.
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
 
 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
 TSSS                    | ADD
-SSSTSSSN                | PUSH 8 (ptr)
-SNT                     | SWAP
-TTS                     | STORE
+NSTTSTTN                | JSR > 1011 (stackrotatereverse)
 NTN                     | RTS
 
 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
 
 SNN                     | DROP
 NTN                     | RTS