| |
oziphantom
Registered: Oct 2014 Posts: 490 |
LDA (ZP,x)
Has anybody ever used this opcode and if so what for? |
|
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Rare. But for pointers on ZP f.e. |
| |
Hein
Registered: Apr 2004 Posts: 954 |
I used it for my music editor to call functions in and outside IRQ, so that IRQ can call the same subroutine when it's allready running outside IRQ. Else the ZP values are trashed when IRQ is done and returning to the original function.
X=0 out IRQ, X=2 in IRQ
snippet:
lda zp_ed_scr_nybble_hi,x
sta (zp_ed_scr_to_lo,x)
inc zp_ed_scr_to_lo,x
bne +
inc zp_ed_scr_to_hi,x
+
lda zp_ed_scr_nybble_lo,x
sta (zp_ed_scr_to_lo,x)
inc zp_ed_scr_to_lo,x
bne +
inc zp_ed_scr_to_hi,x
+
...
|
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
never. |
| |
MagerValp
Registered: Dec 2001 Posts: 1078 |
It's one of those "seemed like a good idea at the time" opcodes. Everyone would have been happier if we got (ZP),x instead. |
| |
Peiselulli
Registered: Oct 2006 Posts: 81 |
(zp) is also missing |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
another opcode would have been more useful, fex sty abs,x stx abs,y. or the mentioned (),x |
| |
Jammer
Registered: Nov 2002 Posts: 1335 |
Or txy/tyx ;) |
| |
tlr
Registered: Sep 2003 Posts: 1790 |
It's useful for channelized implementations like a music player. If you have your voice structures in zp you can address your data pointers using the regular 0,7,14 index for instance. I've used this method in Breakage.
The fact that the 6502 instruction set is so asymmetric is a large part of making it fun to code for IMO. |
| |
cadaver
Registered: Feb 2002 Posts: 1160 |
tlr: That's a cool usage. Though you'll have the downside of having to manipulate the ZP pointer every time you want to access successive bytes (for example note, instrument, duration) from music data, instead of just incrementing Y. |
| |
Slammer
Registered: Feb 2004 Posts: 416 |
I really miss add. (adc without carry) |
| |
lft
Registered: Jul 2007 Posts: 369 |
I use it exactly like that in my latest playroutine.
Another use is when you'd really want to do (zp), but you need the y register for something else, and you have a known constant in x. Then you can do (zp-constant,x).
Finally, cmp (0,x) is a convenient 6-cycle 2-byte nop (although it clobbers the flags). |
| |
Bitbreaker
Registered: Oct 2002 Posts: 508 |
used it a few times as substitute for lda (zp) when x is fix and known lda (<(zp - x_),x) (lda (zp),y is cheaper however to do so)
Now also ponder about lax (zp,x) which could give some x = f(x) results :-D But it could also work as ldx (zp) with the above scenario whenever you can allow to clobber x. |
| |
lft
Registered: Jul 2007 Posts: 369 |
Another thing I've had in mind, but never actually implemented, is this: Suppose you're doing something like kefrens bars with open sideborders. You repeat the last line of a row of characters and modify the font on the fly. But in the borders, you repeat sprite data, let's say one sprite on either side. That means you have a single graphics buffer consisting of 46 bytes, but those bytes are distributed somewhat irregularly in RAM. So make a table in zp consisting of 46 pointers to them. Then use (zp,x) in the drawing operations. You can even access neighbouring cells with (zp-2,x) and (zp+2,x). |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
lft, ace idea ! :) |
| |
Slammer
Registered: Feb 2004 Posts: 416 |
I think the (zp,x) idea have already been used for kefrensbars. I don't remember which demo but I guess it was one from Booze. |
| |
Skate
Registered: Jul 2003 Posts: 494 |
I just checked my source codes directory. I've used it a few times.
In Snapshot / Glance demo's horizontal raycaster part uses something like;
lax DATAS,y
sta (MAP_POINTER,x)
lda tColor,x
ldx #$00
sta (COLOR_POINTER,x)
So, first one really uses x as an index and second one uses x as a zero, more likely a sta(ZP). Of course this is in a loop and y register should not be affected.
This is from one of my unreleased codes;
lax $c0 ; lda #0 : ldx #0
sta (copyTo,x)
Just put a zero to the address pointed at copyTo. $c0 already had a zero of course.
This one is from my recent sierpinski entry.
lax $02
sec
- ror
dey
bpl -
ora (plotAddress,x)
sta (plotAddress,x)
I think what is does is clear.
And last but not least, this is one of my stable raster routines to wait for 8 cycles at some point.
sre ($ff,x)
|
| |
ready.
Registered: Feb 2003 Posts: 441 |
Useful when you need to use zero page pointers but want to preserve y, for example:
ldy whatever
ldx #0
lda (ZP0),y
sta (ZP1,x)
I use this when moving data from one area to another one. |
| |
soci
Registered: Sep 2003 Posts: 480 |
It's more popular in some forth implementations where the data stack is on zero page and is not split. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
Quote: Useful when you need to use zero page pointers but want to preserve y, for example:
ldy whatever
ldx #0
lda (ZP0),y
sta (ZP1,x)
I use this when moving data from one area to another one.
god no! why? thats butt ugly and there are numerous ways round that preserve X instead of Y or selfmod.ű
moving data efficiently
ldx #0
ldy #numofpages
-
lda src,x
sta dst,x
dex
bne -
inc srcaddrhi
inc dstaddrhi
dey
bne - |
| |
Krill
Registered: Apr 2002 Posts: 2980 |
Quoting lftAnother thing I've had in mind, but never actually implemented, is this: Suppose you're doing something like kefrens bars with open sideborders. You repeat the last line of a row of characters and modify the font on the fly. But in the borders, you repeat sprite data, let's say one sprite on either side. That means you have a single graphics buffer consisting of 46 bytes, but those bytes are distributed somewhat irregularly in RAM. So make a table in zp consisting of 46 pointers to them. Then use (zp,x) in the drawing operations. You can even access neighbouring cells with (zp-2,x) and (zp+2,x). You can do this, but it wastes a lot of cycles. You'd only do it like this if you're under serious memory constraints... :)
Under normal demo conditions (almost all 64K available) you'd have as many chunks of unrolled optimised code as you have bar X positions. Then you'd execute one of those in each rasterline of the effect. |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: Quoting lftAnother thing I've had in mind, but never actually implemented, is this: Suppose you're doing something like kefrens bars with open sideborders. You repeat the last line of a row of characters and modify the font on the fly. But in the borders, you repeat sprite data, let's say one sprite on either side. That means you have a single graphics buffer consisting of 46 bytes, but those bytes are distributed somewhat irregularly in RAM. So make a table in zp consisting of 46 pointers to them. Then use (zp,x) in the drawing operations. You can even access neighbouring cells with (zp-2,x) and (zp+2,x). You can do this, but it wastes a lot of cycles. You'd only do it like this if you're under serious memory constraints... :)
Under normal demo conditions (almost all 64K available) you'd have as many chunks of unrolled optimised code as you have bar X positions. Then you'd execute one of those in each rasterline of the effect.
And chain them on the stack? for at least the first 100 lines, and do RTS,RTS,RTS,RTS....? :D |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
jmp ($xcoo*2) ?:) |
| |
JackAsser
Registered: Jun 2002 Posts: 2014 |
Quote: jmp ($xcoo*2) ?:)
Where to jump back? Nah.. chaining.. For every second line, 7-color bars that might just be feasible and perhaps will give you another char in width. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
jackie wins.. :) |
| |
Krill
Registered: Apr 2002 Posts: 2980 |
Quoting MagerValpIt's one of those "seemed like a good idea at the time" opcodes. Everyone would have been happier if we got (ZP),x instead. Indeed. But let's see what it could be useful for.
Assuming no self-modification is feasible (think of ROM code), i can think of accessing data buckets using this addressing mode.
In zeropage, there'd be an array of pointers. Find some (even) value of X which determines the bucket to use. Then either push something into it (STA (buckets,x):INC buckets,x:BNE *+4:inc buckets+1,x) or pull something from it (analogous, but decrease pointer first). |
| |
Krill
Registered: Apr 2002 Posts: 2980 |
Quoting JackAsserAnd chain them on the stack? for at least the first 100 lines, and do RTS,RTS,RTS,RTS....? :D Not quite. Check out my Kefrens bars in Singles Collection Volume 2 :D |
| |
Frantic
Registered: Mar 2003 Posts: 1648 |
I can't count the number of times I've consider this opcode and thought to myself that "hmm.. maybe I could use this one for this or that purpose", but *always* ended up finding some other better solution instead. :) Couldn't even find cases where it was equally good as some other solution, so I could use it just for the sake of using it. The solutions involving this opcode were always worse. :) |
| |
Bob
Registered: Nov 2002 Posts: 71 |
I use (zp,x) for scroll writes in the definer parts.
each row has its own izp addr.. and with variable X I can have the scroll text output starting on different rows.
or even change per frame if I want to.. |
| |
Krill
Registered: Apr 2002 Posts: 2980 |
Quoting BobI use (zp,x) for scroll writes in the definer parts.
each row has its own izp addr.. and with variable X I can have the scroll text output starting on different rows.
or even change per frame if I want to.. This pretty much sounds like a practical implementation of my buckets theory i mentioned above :D |
| |
Hypnosis
Registered: Mar 2015 Posts: 36 |
I have only used it to waste cycles I think. The major shortcoming is that it can only access one byte per pointer. lda (zp,x),y could be interesting. |
| |
lft
Registered: Jul 2007 Posts: 369 |
Here's another idea: In a sprite multiplexer, there are some things you need to update in registers that are spaced two bytes apart (x and y coords), and some things that are in consecutive locations (pointers in the vm, colour registers). If we keep the sprite number times two in x, we can access the coordinate registers using ordinary indexed addressing, and then we can have tables of addresses in zero-page for the colour registers, and for the sprite pointers of each vm, and update those values with the (zp,x) addressing mode. |
| |
Rastah Bar Account closed
Registered: Oct 2012 Posts: 336 |
Could the TAS opcode be useful for a multiplexer somehow too? For example, suppose you have a bunch of "objects" and have stored some properties (colors or positions, for instance) on the stack. You could access those by
lax #objectnum
tas $fe00,y
If you let y contain the actual spritenumber to which you want to assign the object with number #objectnum, then the store operation of TAS could be useful.
Sorry that this is not very concrete, but I don't have much experience with multiplexers. |
| |
Fresh
Registered: Jan 2005 Posts: 101 |
Quote:
Here's another idea: In a sprite multiplexer, there are some things you need to update in registers that are spaced two bytes apart (x and y coords), and some things that are in consecutive locations (pointers in the vm, colour registers). If we keep the sprite number times two in x, we can access the coordinate registers using ordinary indexed addressing, and then we can have tables of addresses in zero-page for the colour registers, and for the sprite pointers of each vm, and update those values with the (zp,x) addressing mode.
Smart idea, that's probably the most useable solution. |
| |
Krill
Registered: Apr 2002 Posts: 2980 |
Quoting lftand update those values with the (zp,x) addressing mode. I have a hunch that under normal demo conditions (TM), self-modifying and unrolled code will gain more. Also, one half of the "hot" sprite registers are in consecutive locations (colours, pointers) while the other half are not (x and y co-ordinates) - so 50% of those accesses when updating the "physical" sprites will be slower due to the extra indirection via ZP pointers. |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
usually a plexer writes sprites in a fixed order, thus it can be unrolled. one excetion I know of cadaver's BOFH which assigns priority to virtual sprites and tries to pick a HW sprite based on that. |
| |
Fresh
Registered: Jan 2005 Posts: 101 |
Yes, the multiplexer can surely be speedcoded with better performance.
Yet, among the proposed solutions, this use of (zp,x) is imho one of the most sensible. This and (zp)-like, when X is known. |
| |
Skate
Registered: Jul 2003 Posts: 494 |
Not directly ZP,x related but recently i moved one of my effect loops to zeropage. When you run your code at zeropage, you have interesting cycle saving method alternatives. For instance if we need to do something like;
ora $xxxx
sta $xxxx
using
lda #<xxxx
sta lo1
sta lo2
lda #>xxxx
sta hi1
sta hi2
is a big waste. Instead we prefer;
lda #<xxxx
sta zp
lda #>xxxx
sta zp+1
ora (zp),y
sta (zp),y
right? If index is not required;
...
ora (zp,x)
sta (zp,x)
would be fine as well. But if your code itself is running on ZP;
lda #<xxxx
sta addr
lda #>xxxx
sta addr+1
ora $xxxx,y : addr = *-2
sta (addr),y ; or sta (addr,x) if suitable
is a nice method to save some cycles. |
| |
Monte Carlos
Registered: Jun 2004 Posts: 359 |
It can be used for text scrollers with varying y-pos to fill in the rightmost char if addresses are prepared in zp |
| |
oziphantom
Registered: Oct 2014 Posts: 490 |
If they just could have saved the metal on putting it on the LDA, STA, ORA, CMP etc ZP instructions put put it on
JMP( XXXX,x ) instead.
Or yes LDA ( ZP,x ),y would also be very handy.
What does TAS do? |
| |
Rastah Bar Account closed
Registered: Oct 2012 Posts: 336 |
Quoting oziphantomIf they just could have saved the metal on putting it on the LDA, STA, ORA, CMP etc ZP instructions put put it on
JMP( XXXX,x ) instead.
Or yes LDA ( ZP,x ),y would also be very handy.
What does TAS do?
A complete description of TAS and other undocumented opcodes can be found here
No More Secrets v0.9 |
| |
oziphantom
Registered: Oct 2014 Posts: 490 |
Ah that doc in a round about way defines what H is. I've seen it on other sites but nothing defined H. Although it seems to be a typo and it should be H+1. Thanks |
| |
HCL
Registered: Feb 2003 Posts: 728 |
Quoting lftAnother thing I've had in mind, but never actually implemented, is this: Suppose you're doing something like kefrens bars with open sideborders. You repeat the last line of a row of characters and modify the font on the fly. But in the borders, you repeat sprite data, let's say one sprite on either side. That means you have a single graphics buffer consisting of 46 bytes, but those bytes are distributed somewhat irregularly in RAM. So make a table in zp consisting of 46 pointers to them. Then use (zp,x) in the drawing operations. You can even access neighbouring cells with (zp-2,x) and (zp+2,x).
Yepp, Slammer is right.. That's what i did in Royal Arte :), but without border :P. Totally forgot about that, and i never thought i ever used (zp,x) :). |
| |
Wisdom
Registered: Dec 2001 Posts: 90 |
Used it in Thread Over and in Matrix 16. Might be useful in some size-coding cases. |