16bit inc/dec indirectly

Programming the 6502 microprocessor and its relatives in assembly and other languages.
Post Reply
twh1st
Posts: 8
Joined: 04 Oct 2006
Location: Munich | Germany

16bit inc/dec indirectly

Post by twh1st »

Hey *,

how would you solve this problem.

i like to 16bit-INC/DEC a value stored under address ptr1 (zp).

Code: Select all

        clc
        lda #1
        adc (ptr1),y
        sta (ptr1),y
        bne *+9
        ldy #1
        sec
        adc (ptr1),y
        sta (ptr1),y
While INC looks kind of ok (but still I'm sure there would a better way) I have so my doubts about the DEC routine I wrote:

Code: Select all

        lda (ptr1),y
        bne skip
        ldy #1
        lda (ptr1),y
        sta ptr2
        dec ptr2
        lda ptr2
        sta (ptr1),y
skip    ldy #0
        lda (ptr1),y
        sta ptr2
        dec ptr2
        lda ptr2
        sta (ptr1),y
Any suggestions to realize this more effectively?

grtx and thx,
\twh
kc5tja
Posts: 1706
Joined: 04 Jan 2003

Post by kc5tja »

Off the top of my head, this is what I could come up with.

Code: Select all

.proc inc_indirect
  ldy #0
  lda (ptr1),y
  tax
  inx
  txa
  sta (ptr1),y
  bne done
  iny
  ldy #0
  lda (ptr1),y
  tax
  inx
  txa
  sta (ptr1),y
done:
  rts
.endproc

.proc dec_indirect
  ldy #0
  lda (ptr1),y
  tax
  beq underflow
  dex
  txa
  sta (ptr1),y
  rts

underflow:
  dex
  txa
  sta (ptr1),y
  iny
  lda (ptr1),y
  tax
  dex
  txa
  sta (ptr1),y
  rts
.endproc
If there is any way you can cache values you use frequently in direct-page, though, do so. There's a huge performance improvement if you do. :)
bogax
Posts: 250
Joined: 18 Nov 2003

Re: 16bit inc/dec indirectly

Post by bogax »

All you're really doing is a hard coded 16 bit addition
or subtraction of 1
twh1st wrote:

Code: Select all

        clc
        lda #1
        adc (ptr1),y
        sta (ptr1),y
        bne *+9
        ldy #1
        sec
        adc (ptr1),y
        sta (ptr1),y
You don't explicitly set y to begin, but presumably y is 0
so you can iny instead of ldy #1 and save a byte

If you start with 1 in the accumulator, the only way to end up
with 0 in the accumulator after an adc is to add FF and that will
also result in the carry being set, so the sec is redundant.

Your code becomes:

Code: Select all

        clc
        lda #1
        adc (ptr1),y
        sta (ptr1),y
        bne *+7
        iny
        adc (ptr1),y
        sta (ptr1),y
personally, I'd code it like this:

Code: Select all

        clc
        lda (ptr1),y
        adc #1
        sta (ptr1),y
        bcc *+7
        iny
        adc (ptr1),y
        sta (ptr1),y
Just because it's a little easier (for me, any way)
to see what's going on.

Dec can be roughly the same.
0 is the only thing you can start with in the accumulator
and subtract 1 from and end up with a barrow, ie
with the carry clear, and that will leave FF in the
accumulator. Adding FF to something is the same
as subtracting 1 (as far as the resulting byte and
ignoring flags)

Code: Select all

        sec
        lda (ptr1),y
        sbc #1
        sta (ptr1),y
        bcs *+7
        iny
        adc (ptr1),y
        sta (ptr1),y
The last three instructions are the same so they
can probably be shared if that seems desriable,
but I'll leave that as an 'exercise for the reader' ;)
Last edited by bogax on Sun Dec 07, 2008 6:50 am, edited 1 time in total.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8775
Joined: 30 Aug 2002
Location: Southern California
Contact:

Post by GARTHWILSON »

twh1st, your increment needs an LDY #0 near the beginning. Then your LDY #1 can be shortened to INY (which requires re-adjusting your branch distance-- a good reason to use labels). Otherwise it looks ok.

Then you can modify the increment routine to make the decrement routine this way:

Code: Select all

        LDY #0
        LDA  (PTR1),Y
        DEA
        STA  (PTR1),Y
        CMP  #$FF
        BNE  done
        INY
        LDA  (PTR1),Y
        DEA
        STA  (PTR1),Y
done:
kc5tja's TAX INX/DEX TXA is necessary if you're using the old NMOS 6502. If you're not using a Commodore 64 or something where you're stuck with NMOS, I always recommend using the CMOS 6502 instead, partly for the added instructions.

If you're on a 65816 and have both the accumulator and index registers in 16-bit mode, I think you can do:

Code: Select all

        LDX  #PTR1     ; Edit: omit the # per discussion below.
        INC  0,X 
although I have been away from this stuff for awhile and might need some refresher time.

Edit: I see bogax posted while I was writing. Good post.
Last edited by GARTHWILSON on Tue Feb 19, 2008 3:58 am, edited 1 time in total.
kc5tja
Posts: 1706
Joined: 04 Jan 2003

Post by kc5tja »

Your INC 0,X isn't going to work, because PTR1 points to the variable to be in/decremented. You have to use (dp),Y for this, unless INC/DEC take (0,X) as an addressing mode (I can't recall off-hand if it does).

If using the 65816 in 16-bit mode, though, I'd use this:

Code: Select all

lda (ptr1) ; Yes, no ,Y suffix -- the 65816 assumes a zero-offset.
ina ; or dea
sta (ptr1)
User avatar
GARTHWILSON
Forum Moderator
Posts: 8775
Joined: 30 Aug 2002
Location: Southern California
Contact:

Post by GARTHWILSON »

Ah yes, just take the # out of the LDX #. Now you'll get the final address in X, having loaded it from the pointer variable. So if PTR1 at address 0061-0062 for example contained 3FE6, now you'll increment the 16-bit number contained at 3FE6-3FE7.
twh1st
Posts: 8
Joined: 04 Oct 2006
Location: Munich | Germany

Post by twh1st »

excellent!!! thank you guys!

btw, I forgot to copy'n'paste the "ldy #0" .. it was not meant to be set implicitly. :-)

grtx,
\twh
twh1st
Posts: 8
Joined: 04 Oct 2006
Location: Munich | Germany

Post by twh1st »

GARTHWILSON wrote:
kc5tja's TAX INX/DEX TXA is necessary if you're using the old NMOS 6502. If you're not using a Commodore 64 or something where you're stuck with NMOS, I always recommend using the CMOS 6502 instead, partly for the added instructions.
I'm coding with an Atari 8bit. I never heard of different 6502 implementations like CMOS or NMOS. So I guess I have a NMOS 6502 because I never saw opcodes like "DEA" or "INA".

thanks anyway!!

grtx,
\twh
cas
Posts: 27
Joined: 21 May 2003
Location: Germany
Contact:

Post by cas »

twh1st wrote:
GARTHWILSON wrote:
kc5tja's TAX INX/DEX TXA is necessary if you're using the old NMOS 6502. If you're not using a Commodore 64 or something where you're stuck with NMOS, I always recommend using the CMOS 6502 instead, partly for the added instructions.
I'm coding with an Atari 8bit. I never heard of different 6502 implementations like CMOS or NMOS. So I guess I have a NMOS 6502 because I never saw opcodes like "DEA" or "INA".

thanks anyway!!

grtx,
\twh
Hi twh,

the Atari 8bit has a NMOS CPU, you might have a CMOS Type in your floppy when you have a Speed Enhancement in there (The Compyshop Speedy is using a 65C02). Unfortunately, in the Atari XL/XE line, there is now easy way to replace the NMOS 6502 for a CMOS one, because the Atari 6502 has this special "halt" signal for sharing the bus with Antic. I've read that it is possible to exchange the CPU in old Atari 800 machines, as they use a stock 6502 NMOS (and not the special Atari one).

Carsten
tomaitheous
Posts: 24
Joined: 22 Sep 2007

Post by tomaitheous »

Quote:
Unfortunately, in the Atari XL/XE line, there is now easy way to replace the NMOS 6502 for a CMOS one, because the Atari 6502 has this special "halt" signal for sharing the bus with Antic.
Shouldn't /RDY be a replacement to halt? You can pause the CPU as long as you need with /RDY if I recall correctly.
kc5tja
Posts: 1706
Joined: 04 Jan 2003

Post by kc5tja »

RDY is active-high -- no overbar for the signal name. So, if RDY goes low it will halt the processor. However, it will not release the bus. For this, a separate signal (BE for the 65816 at least; not sure if BE also exists on 65C02 as well) is used. If BE doesn't exist on the 65C02, external, three-statable bus buffering is required.
tomaitheous
Posts: 24
Joined: 22 Sep 2007

Post by tomaitheous »

And I take it the 65c02 or 65cs02 do not have buffers on the processor side to protect from another device trying to drive the same address bus? (not necessarily tri-state)

Like if the processor is halted via /RDY and the address bus has a random (but static while paused) value asserted by the CPU - you could have a logic device that would sort of invert the state of the address lines for another device to drive the address bus. Lines that are driven high by the original processor could be pulled to low and vice versa when needed by the another processor. I'm not sure if this would damage the original CPU or not.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8775
Joined: 30 Aug 2002
Location: Southern California
Contact:

Post by GARTHWILSON »

WDC's 65c02 does have BE (active-high bus enable) on pin 36 of the DIP, 40 of the PLCC, and 34 of the PQFP. (It's the same pin on the PLCC and PQFP, but they're numbered differently, the PLCC starting with pin 1 in the middle of the top and the PQFP starting on the corner.) They also have a ML\ (active-low memory lock) output (pin 5 of the DIP) and an VP\ (active-low vector pull) output (pin 1 of the DIP where other manufacturers had ground). Pin 21 of the DIP is still ground. WDC's 65c02 also lets you stop the clock indefinitely in either phase.
kc5tja
Posts: 1706
Joined: 04 Jan 2003

Post by kc5tja »

In fact, internally to the CPU chip itself, that's all RDY does -- it simply gates the clock in phase-1!!
Post Reply