Page 1 of 1

Word Double-decrement

Posted: Fri Sep 24, 2021 4:59 am
by cjs
I recently had a need to decrement words (addresses) by two, which is not quite so simple as decrementing them by one. There's an obvious choice between using SUB or using DEC twice, so I coded up both to see which worked better. (Spoiler: SUB won by a mile.) You can look at the full code and test files if you like but here's the summary:

Code: Select all

;   The byte and cycle counts assume zero page addressing. The first cycle
;   column is for the case where the MSB is not decremented, and the second
;   for the case when it is.
;
                            ; byte and cycle counts assume ZP addressing
                            ; first cycle column is for branch taken

decw_sub:   lda val         ;  2b  2c
            sec             ;  1b  2c
            sbc #2          ;  2b  2c
            sta val         ;  2b  3c
            bcs .done       ;  2b  3c  2c
            dec val+1       ;  2b      5c
.done                       ; ────────────
            rts             ;  9b 12c 16c   TOTALS

decw_dec:   lda val         ;  2b  2c
            bne .nz1        ;  2b  3c 2c        { at least one
            dec val+1       ;         5c          of these two
.nz1        dec val         ;  2b  5c             branches must
            bne .nz2        ;  2b  3c 2c        { be taken
            dec val+1       ;         5c
.nz2        dec val         ;  2b  5c
                            ; ───────────
            rts             ; 10b 18c 22c   TOTALS
The test values (input, output) I used are:

Code: Select all

(0xFFFF, 0xFFFD), (0x8001, 0x7FFF), (0x7000, 0x6FFE), (0x0000, 0xFFFE)
Did I miss any test values that could expose a mistake, incorrect cycle counts, tricks for even faster (or smaller) ways of doing this, or anything else?

I also noticed that we don't seem to have anything in the 6502.org Source Code Repository related to incrementing and decrementing. Maybe it's worth linking from there to the Wikidot page (which I find pretty useful). If someone wants to add any of the above to either, I'm fine with that.

Re: Word Double-decrement

Posted: Fri Sep 24, 2021 6:17 am
by barrym95838
LDA val takes three cycles, not two. Your decw_sub is 11 bytes, not nine.

Your decw_dec is 14 bytes, not 10. Here's an untested variation, but I still see no significant reason to choose it over SBC:

Code: Select all

decw_dec:   ldy val         ;  2b  3c
            cpy #2          ;  2b  2c
            dey             ;  1b  2c
            dey             ;  1b  2c
            bcs .nz2        ;  2b  3c  2c
            dec val+1       ;  2b      5c
.nz2:       sty val         ;  2b  3c  3c
                            ; ───────────
            rts             ; 12b 15c 19c   TOTALS
Maybe if you were in decimal mode or wanted to preserve the V flag?

Re: Word Double-decrement

Posted: Fri Sep 24, 2021 9:11 am
by cjs
barrym95838 wrote:
LDA val takes three cycles, not two.
Ah, of course it does. I'd put a stupid error into the opcode reference I was using. That led me to fix two things, so thanks.
Quote:
Your decw_sub is 11 bytes, not nine.... Your decw_dec is 14 bytes, not 10.
Yeah. Not sure how I decided I could just leave out the byte counts of a couple of instructions.
Quote:
Here's an untested variation....
It's tested now (and works). I dropped it into my code as `decw_dey`. It's a nice optimization, and a good reminder that it's worth remembering registers other than A can also work for small additions and subtractions.
Quote:
Maybe if you were in decimal mode or wanted to preserve the V flag?
Yup. Or if you might be in decimal mode, or you just find it helps a broader optimization to preserve A rather than Y (or X) at that point.

Re: Word Double-decrement

Posted: Thu Nov 11, 2021 6:03 am
by barrym95838
cjs wrote:
Maybe it's worth linking from there to the Wikidot page (which I find pretty useful). If someone wants to add any of the above to either, I'm fine with that.
Done. Well, not exactly. I added our snippets to the wikidot page, where I have editing authority.