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.
130 lines
2.9 KiB
NASM
130 lines
2.9 KiB
NASM
; The six instructions added after the first sixty four, and what each is for.
|
|
;
|
|
; Two of them are a call that puts nothing back, and four move a Data Pointer by a value
|
|
; worked out while the program is running rather than one written into it.
|
|
;
|
|
; WHY A SECOND KIND OF CALL. CALL puts A, B and Data Pointers 0 through 2 back the way it
|
|
; found them, which costs ten bytes of Stack and means a subroutine can only hand anything
|
|
; back through Q, DP3 or memory. That is the right default and it is what almost everything
|
|
; here uses. RCAL costs two bytes and puts nothing back at all, which is what a short leaf
|
|
; routine wants - and it is unsafe in exactly the way its name says, because everything the
|
|
; callee touches, the caller has lost.
|
|
;
|
|
; The two frames are different sizes, so RCAL must be returned from with RRET and CALL with
|
|
; RET. Crossing them walks the Stack to somewhere that was never a return address.
|
|
;
|
|
; WHY OFFSET BY A REGISTER. DPUP and DPDN take a byte written into the program, so moving a
|
|
; pointer by something just worked out meant storing it and loading it back. DPUA and DPDA
|
|
; take A; DPUW and DPDW take A and B together, which is how every sixteen bit value on this
|
|
; machine is carried between registers.
|
|
;
|
|
; Written by Anachronaut
|
|
|
|
#Program
|
|
|
|
start:
|
|
; ---- Offsetting by a byte, up and then back down ----
|
|
SETD.0 Text
|
|
INIA 0d7
|
|
DPUA.0
|
|
LDA.0
|
|
OUTA 0x00 ; the eighth character
|
|
INIA 0d4
|
|
DPDA.0
|
|
LDA.0
|
|
OUTA 0x00 ; and four before it
|
|
|
|
; ---- Offsetting by a whole sixteen bit value ----
|
|
SETD.1 Text
|
|
RSTA
|
|
INIB 0d13
|
|
DPUW.1
|
|
LDA.1
|
|
OUTA 0x00
|
|
RSTA
|
|
INIB 0d13
|
|
DPDW.1
|
|
LDA.1
|
|
OUTA 0x00 ; back where it started
|
|
|
|
; ---- What each kind of call puts back ----
|
|
;
|
|
; The same callee is reached both ways and sets A to something else. After the raw call
|
|
; that is what A holds; after the safe one it is not.
|
|
INIA 0x41
|
|
RCAL wrecker
|
|
OUTA 0x00 ; Z - the callee's
|
|
INIA 0x41
|
|
CALL polite
|
|
OUTA 0x00 ; A - put back
|
|
|
|
; ---- And what each costs ----
|
|
;
|
|
; Printed as a digit added to '0', so two bytes reads as "2" and ten reads as the
|
|
; character ten along from it.
|
|
MVSD.0
|
|
PSHD.0
|
|
POPB
|
|
POPA
|
|
SETD.2 Before
|
|
STB.2
|
|
|
|
RCAL rawCost
|
|
CALL safeCost
|
|
|
|
INIA 0x0A
|
|
OUTA 0x00
|
|
HALT
|
|
|
|
wrecker:
|
|
INIA 0x5A
|
|
RRET
|
|
|
|
polite:
|
|
INIA 0x5A
|
|
RET
|
|
|
|
; WRITTEN OUT TWICE RATHER THAN CALLED, because a call would put its own frame down on
|
|
; top of the one being measured and each of these would report ten bytes more than it
|
|
; costs. The first version of this did exactly that and printed twelve and twenty.
|
|
rawCost:
|
|
MVSD.1
|
|
PSHD.1
|
|
POPB
|
|
POPA
|
|
SETD.2 Before
|
|
LDA.2
|
|
CCF
|
|
SUB
|
|
MVQA
|
|
INIB 0x30
|
|
CCF
|
|
ADD
|
|
MVQA
|
|
OUTA 0x00
|
|
RRET
|
|
|
|
safeCost:
|
|
MVSD.1
|
|
PSHD.1
|
|
POPB
|
|
POPA
|
|
SETD.2 Before
|
|
LDA.2
|
|
CCF
|
|
SUB
|
|
MVQA
|
|
INIB 0x30
|
|
CCF
|
|
ADD
|
|
MVQA
|
|
OUTA 0x00
|
|
RET
|
|
|
|
#Data
|
|
|
|
Text:
|
|
"0123456789abcdefg"
|
|
Before:
|
|
0x00
|