From 6cb31a3ecea681051cfa36fde3f17b18f8eacfea Mon Sep 17 00:00:00 2001 From: Aaron Taylor Date: Fri, 26 Jul 2019 01:28:52 -0700 Subject: [PATCH] Modified stdlib to use stack rotations to timeshare heap registers. The stdlib is probably broken at this commit. Next step is a test suite. --- stdlib/README.md | 6 +- stdlib/debug.pvvs | 7 ++ stdlib/heap.pvvs | 259 +++++++++++++++++----------------------------- stdlib/stack.pvvs | 70 ++++++------- stdlib/stdio.pvvs | 149 +++++++++++++++++--------- 5 files changed, 235 insertions(+), 256 deletions(-) diff --git a/stdlib/README.md b/stdlib/README.md index b41e251..a98b7c7 100644 --- a/stdlib/README.md +++ b/stdlib/README.md @@ -19,9 +19,9 @@ following reservations: ## 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. diff --git a/stdlib/debug.pvvs b/stdlib/debug.pvvs index 138b2cb..4cc8a73 100644 --- a/stdlib/debug.pvvs +++ b/stdlib/debug.pvvs @@ -6,6 +6,13 @@ @ 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 diff --git a/stdlib/heap.pvvs b/stdlib/heap.pvvs index 4953fad..2c5eb79 100644 --- a/stdlib/heap.pvvs +++ b/stdlib/heap.pvvs @@ -14,35 +14,30 @@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 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 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@ -58,39 +53,33 @@ NTN | RTS @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 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 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@ -106,28 +95,29 @@ NTN | RTS @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ #include 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 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@ -147,41 +137,54 @@ 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 @@ -200,133 +203,57 @@ 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: -@ -@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -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 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@ -343,6 +270,7 @@ NTN | RTS @ heap[address+1] @ heap[address] <-- TOS @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#include NSSVTTTTSN | Mark: 11110 (slurp) @ Load one word from heap on each pass. @@ -390,44 +318,43 @@ NTN | RTS @ Return Stack: @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#include 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 diff --git a/stdlib/stack.pvvs b/stdlib/stack.pvvs index 417b3bb..c543d98 100644 --- a/stdlib/stack.pvvs +++ b/stdlib/stack.pvvs @@ -5,8 +5,7 @@ @ 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 @ ... @@ -23,19 +22,19 @@ NSSVTSTSN | Mark: 1010 (stackrotate) @ 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 @@ -43,7 +42,7 @@ TTS | STORE @ See if the loop is complete. SNS | DUP -SSSTTTSN | PUSH 14 (ptr) +SSSTTTTN | PUSH 15 (ptr) TTT | LOAD SSSTN | PUSH 1 TSSS | ADD @@ -51,11 +50,11 @@ TSST | SUBTRACT 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 @@ -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. -@ 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 @@ -109,8 +108,7 @@ NTN | RTS @ 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 @ ... @@ -127,19 +125,19 @@ NSSVTSTTN | Mark: 1011 (stackrotatereverse) @ 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 @@ -147,7 +145,7 @@ TTS | STORE @ See if the loop is complete. SNS | DUP -SSSTTTSN | PUSH 14 (ptr) +SSSTTTTN | PUSH 15 (ptr) TTT | LOAD SSSTN | PUSH 1 TSSS | ADD @@ -155,11 +153,11 @@ TSST | SUBTRACT 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 @@ -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. -@ 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 diff --git a/stdlib/stdio.pvvs b/stdlib/stdio.pvvs index 950ad6c..539df7d 100644 --- a/stdlib/stdio.pvvs +++ b/stdlib/stdio.pvvs @@ -140,7 +140,8 @@ NTN | RTS @ ASCII '\0' @ substitution n @ -@ Maximum of 7 substitutions. +@ Maximum substitutions determined by upper heap limit in stackrotate and +@ stackrotatereverse subroutines. @ Call Stack: @ ACSII '\0' @ string word n @@ -157,32 +158,27 @@ NTN | RTS #include 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. @@ -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 +@ 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 @@ -238,6 +236,8 @@ NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001 @@@@@@@@@@@@@@@@@@@@ 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' @@ -282,6 +282,8 @@ NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001 @@@@@@@@@@@@@@@@@@@@ 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' @@ -317,73 +319,118 @@ NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001 @@@@@@@@@@@@@@@@@@@@ @ 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 -- 2.20.1