Kweepa wrote: ↑Mon Oct 12, 2020 4:33 pm
You can often use a relative branch that relies on a condition you know to be true, or have set up true at the start of the loop, thus avoiding the 2 cycle overhead of a CLC/CLV.
My practice in assembly language is to comment almost every instruction, or at least comment every related group of instructions. This kind of optimization is okay as long as you comment it. Future You will be so grateful to Past You for this considerate act. Something like this for branches is what I'd consider a natural and elegant replacement for JMP:
Code: Select all
; Draw character specified at index X on screen if Carry is clear, or
; the previous character if Carry is set
Draw: bcc new ; Carry clear, so get a new character
lda previous ; otherwise, get the previous character
bcs finish ; (carry still set from call)
new: lda table,x ; Find the character in the table
finish: etc...
In the context of the code, the BCS is "unconditional," because the condition is known. It's really a form of "else". In other cases, if you're relying on a side effect of another operation, the trick might seem more tenuous. In these cases, consider indicating your awareness by commenting out an explicit flag operation:
Code: Select all
jsr init ; Initialize the hardware
;clc ; init subroutine always exits with Carry clear
bcc next
Then, if the underlying assumption of the side effect changes at some point (because you have to change the subroutine, for example) you'll at least know what was going on. You won't drive yourself mad looking for the reason for a failure to branch.
A similar potential for optimization is to look for necessary flag states for arithmetic. Here, commenting is just as important:
Code: Select all
-loop: lda #$00
sta CHARAC
ldy #$05 ; Each character encoded in five bits, shifted
shift_l: lda #$00 ; as a 24-bit register into CHARAC, which
asl MNEM+1 ; winds up as a ROT0 code (A=1 ... Z=26)
rol MNEM ; ,,
rol CHARAC ; ,,
dey
bne shift_l
lda CHARAC
;clc ; Carry is clear from the last ROL
adc #"@" ; Get the PETSCII character
jsr CharOut
I know that Carry is clear before ADC because there can never be enough iterations to cause ROL CHARAC to set Carry, and I rely on this when performing ADC. But because I do CLC before ADC as a matter of convention, I put it in my code and comment it out, and explain why I did that.
So, yes, by all means use side effects to make code smaller. Sometimes you
must have that byte in a VIC-20. But don't for a minute think that you'll understand why you did this a week later!