Twenty four places moved Q into A or B by pushing it and popping it back. That is four bus cycles and two bytes to do what MVQA does in one of each, and several of them are inside loops - Life, the calculator, int8. Nineteen more loaded zero with INIA 0d0 where RSTA says the same thing in one byte. Both are equivalent at the CPU rather than by assertion: RSTA and INIA both leave Status alone, and PSHQ followed by POPA nets to A = Q with the Stack Pointer where it started. The one difference is that the pair leaves a copy of Q in memory just below the Stack Pointer and MVQA does not, which nothing here reads. Five recorded outputs moved and every one of them says the change worked: - 16x16Life fits five more generations into the same cycle budget, the first 457 lines identical, because the loop got cheaper. - Life.sbx is 1409 bytes rather than 1411, in three tests that list it. - Edit.sbx is 1995 rather than 1996. That last one broke a check I added this morning, and the hole is worth recording: the CosmOS README's claim about Edit's size did not have the word "Edit" on the same line as the number, because the subject was in the sentence before, so the check that measures quoted sizes skipped it silently. The sentence now names what it is talking about, which makes it both checkable and clearer, and the check fails on a wrong number there. Comments on either half of a replaced pair are carried onto the instruction that replaces them, so nothing anybody wrote was lost.
139 lines
6.2 KiB
NASM
139 lines
6.2 KiB
NASM
; print.asm
|
|
|
|
; Some simple SplitBit subroutines for printing.
|
|
; Anachronaut
|
|
; 10/27/2024
|
|
|
|
#Program
|
|
BRI start ; Branch immediately to the start of the program.
|
|
|
|
lineFeed:
|
|
INIA 0x0A ; Load the character for linefeed into A.
|
|
OUTA 0x00 ; Output it.
|
|
RET ; Return to the caller.
|
|
|
|
blankSpace:
|
|
INIB 0x20 ; Set B to the ASCII value for space.
|
|
OUTB 0x00 ; Print it.
|
|
RET
|
|
|
|
; Expects A to contain the number of spaces to print.
|
|
blankSpaces:
|
|
INIB 0x20 ; Set B to the ASCII value for space.
|
|
OUTB 0x00 ; Print it.
|
|
BRA printDone ; If A is zero, we're done.
|
|
DECA ; Decrement A.
|
|
BRI blankSpace ; Branch back to the loop again.
|
|
|
|
printString: ; Expects Data Pointer to be set to the beginning of the string to be printed.
|
|
LDA ; Move the first character of the string into A.
|
|
BRA printDone ; If A is NULL, the string is finished, so return.
|
|
OUTA 0x00 ; Output the character.
|
|
INCD ; Increment Data Pointer to the next character.
|
|
BRI printString ; Branch to the beginning of the loop.
|
|
printDone:
|
|
RET ; Return to the caller.
|
|
|
|
; Expects A to contain the value to be printed in decimal form.
|
|
printByteDecimal:
|
|
; Clear the buffer we're going to write into.
|
|
SETD DecimalValue ; Set the Data Pointer to the buffer.
|
|
RSTB ; Set B to 0.
|
|
STB ; Store it in the buffer.
|
|
INCD ; Increment to the tens place.
|
|
STB ; Store 0 in it.
|
|
INCD ; Increment to the hundred's place.
|
|
STB ; Store 0 in it.
|
|
INIB 0d10 ; Load 10 into B.
|
|
PSHA ; Save the value onto the stack.
|
|
printDecimalLoopStart:
|
|
POPA ; Pop the value to A from the stack.
|
|
CCF ; Clear the Carry Flag.
|
|
SUB ; Subtract 10 from the value in A.
|
|
BRC getOnes ; If 10 is bigger than A, We're done looping and A contains the ones.
|
|
BRA getOnes ; If the value 0, we're also done.
|
|
; Otherwise, increment the tens place.
|
|
SETD DecimalValue ; Set the Data Pointer to the buffer.
|
|
INCD ; Increment to the tens place.
|
|
PSHQ ; Save the new value onto the stack.
|
|
LDA ; Load the number of tens into A.
|
|
INCA ; Increment it.
|
|
; Now check to see if there are ten tens and we need to carry to the hundreds.
|
|
CCF ; Clear the Carry Flag.
|
|
SUB ; Subtract 10 from A.
|
|
BRQ incrementHundreds ; If Q is 0, set the tens to 0 and increment the hundreds place.
|
|
STA ; Otherwise, store the value back to the tens place.
|
|
BRI printDecimalLoopStart ; and loop again.
|
|
incrementHundreds:
|
|
STQ ; Store 0 in the tens place.
|
|
INCD ; Increment the Data Pointer to the hundreds place.
|
|
LDA ; Load it into A.
|
|
INCA ; Increment it.
|
|
STA ; Store it back again.
|
|
BRI printDecimalLoopStart ; and Loop again.
|
|
getOnes:
|
|
SETD DecimalValue ; Set the Data Pointer to the ones place.
|
|
STA ; Store A in it.
|
|
; At this point we're done. We just need to print the digits with the printDecimalDigit subroutine.
|
|
INCD INCD ; Increment the Data Pointer twice to the hundreds place.
|
|
decimalCheckLoop:
|
|
LDA ; Load the value into A.
|
|
BRA checkTens ; If the hundreds are 0, skip printing their digit.
|
|
CALL printDecimalDigit ; Otherwise, print it.
|
|
DECD
|
|
LDA
|
|
CALL printDecimalDigit ; And the tens place, too.
|
|
BRI printOnes ; And finally, the ones.
|
|
checkTens:
|
|
DECD ; Decrement to the tens place.
|
|
LDA ; Load it into A.
|
|
BRA printOnes ; If the tens are zero, skip printing their digit, too.
|
|
CALL printDecimalDigit ; Otherwise, print it.
|
|
printOnes:
|
|
DECD ; Decrement to the ones place.
|
|
LDA
|
|
CALL printDecimalDigit ; Print it no matter what.
|
|
RET ; We're done, return to the caller.
|
|
|
|
; Expects A to contain the byte you want to print as a hexadecimal value.
|
|
printByteHex:
|
|
RSTB ; Set B to 0.
|
|
SHR SHR SHR SHR ; Shift Right four times to move the high nybble into the lower half of A.
|
|
CALL printHexDigit ; Print the nybble.
|
|
RSTA ; Set A to 0.
|
|
SHL SHL SHL SHL ; Shift left four times to move the low nybble back into the lower half of A.
|
|
CALL printHexDigit ; Print the nybble.
|
|
RET ; Return to the caller.
|
|
|
|
; Expects A to contain the nybble you want to print.
|
|
printHexDigit:
|
|
INIB 0d10 ; Set B to 10.
|
|
SUB ; Subtract it.
|
|
BRC printDecimalDigit ; If the Carry Flag is set, the digit is less than 9. Print it.
|
|
; Since it's greater than 9, add the ASCII offset for capital letters.
|
|
INIB 0x37 ; Set B to the offset.
|
|
ADD ; Add it to A.
|
|
OUTQ 0x00 ; Print the result.
|
|
RET ; Return to the caller.
|
|
|
|
; Expects A to contain a single BCD digit to print.
|
|
printDecimalDigit:
|
|
INIB 0x30 ; Load ASCII offset for numbers into B.
|
|
CCF ; Clear the Carry Flag.
|
|
ADD ; Add it to A.
|
|
OUTQ 0x00 ; Send it to the output.
|
|
RET ; Return from subroutine.
|
|
|
|
#Data
|
|
|
|
; This is where printDecimal stores its result.
|
|
DecimalValue:
|
|
0x00 ; The ones place.
|
|
0x00 ; The tens place.
|
|
0x00 ; The hundreds place.
|
|
|
|
; This library used to pad its data out to a whole page, so that anything including it
|
|
; started on a page boundary. That cost every program 253 bytes of zeroes to give one
|
|
; program a guarantee it could not ask for out loud. A program that needs a boundary now
|
|
; writes #Align in front of the thing that needs it.
|