Page 1 of 1
16bit inc/dec indirectly
Posted: Mon Feb 18, 2008 10:22 pm
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
Posted: Tue Feb 19, 2008 12:48 am
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.

Re: 16bit inc/dec indirectly
Posted: Tue Feb 19, 2008 1:27 am
by bogax
All you're really doing is a hard coded 16 bit addition
or subtraction of 1
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'

Posted: Tue Feb 19, 2008 1:37 am
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.
Posted: Tue Feb 19, 2008 3:05 am
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)
Posted: Tue Feb 19, 2008 3:25 am
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.
Posted: Tue Feb 19, 2008 7:37 pm
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
Posted: Tue Feb 19, 2008 7:42 pm
by twh1st
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
Posted: Tue Apr 29, 2008 7:09 am
by cas
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
Posted: Wed Apr 30, 2008 11:08 pm
by tomaitheous
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.
Posted: Thu May 01, 2008 6:38 am
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.
Posted: Thu May 01, 2008 2:14 pm
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.
Posted: Thu May 01, 2008 8:53 pm
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.
Posted: Fri May 02, 2008 4:59 am
by kc5tja
In fact, internally to the CPU chip itself, that's all RDY does -- it simply gates the clock in phase-1!!