Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
You are not logged in 
CSDb User Forums


Forums > C64 Coding > LDA (ZP,x)
2016-05-16 14:31
oziphantom

Registered: Oct 2014
Posts: 248
LDA (ZP,x)

Has anybody ever used this opcode and if so what for?
2016-05-16 15:13
JackAsser

Registered: Jun 2002
Posts: 1483
Rare. But for pointers on ZP f.e.
2016-05-16 15:44
Hein

Registered: Apr 2004
Posts: 836
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
+
...
2016-05-16 16:21
Oswald

Registered: Apr 2002
Posts: 4365
never.
2016-05-16 16:28
MagerValp

Registered: Dec 2001
Posts: 952
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.
2016-05-16 17:10
Peiselulli

Registered: Oct 2006
Posts: 71
(zp) is also missing
2016-05-16 17:19
Oswald

Registered: Apr 2002
Posts: 4365
another opcode would have been more useful, fex sty abs,x stx abs,y. or the mentioned (),x
2016-05-16 17:31
Jammer

Registered: Nov 2002
Posts: 812
Or txy/tyx ;)
2016-05-16 18:43
tlr

Registered: Sep 2003
Posts: 1204
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.
2016-05-16 18:46
cadaver

Registered: Feb 2002
Posts: 1078
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.
2016-05-16 18:54
Slammer
Account closed

Registered: Feb 2004
Posts: 401
I really miss add. (adc without carry)
2016-05-16 18:59
lft

Registered: Jul 2007
Posts: 356
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).
2016-05-16 19:15
Bitbreaker

Registered: Oct 2002
Posts: 445
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.
2016-05-16 19:17
lft

Registered: Jul 2007
Posts: 356
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).
2016-05-16 19:31
Oswald

Registered: Apr 2002
Posts: 4365
lft, ace idea ! :)
2016-05-16 19:59
Slammer
Account closed

Registered: Feb 2004
Posts: 401
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.
2016-05-17 04:30
Skate

Registered: Jul 2003
Posts: 473
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)
2016-05-17 07:27
ready.

Registered: Feb 2003
Posts: 426
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.
2016-05-17 08:07
soci

Registered: Sep 2003
Posts: 418
It's more popular in some forth implementations where the data stack is on zero page and is not split.
2016-05-17 08:25
Oswald

Registered: Apr 2002
Posts: 4365
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 -
2016-05-17 11:06
Krill

Registered: Apr 2002
Posts: 1106
Quoting lft
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).
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.
2016-05-17 11:10
JackAsser

Registered: Jun 2002
Posts: 1483
Quote: Quoting lft
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).
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
2016-05-17 11:11
Oswald

Registered: Apr 2002
Posts: 4365
jmp ($xcoo*2) ?:)
2016-05-17 11:12
JackAsser

Registered: Jun 2002
Posts: 1483
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.
2016-05-17 11:12
Oswald

Registered: Apr 2002
Posts: 4365
jackie wins.. :)
2016-05-17 11:14
Krill

Registered: Apr 2002
Posts: 1106
Quoting MagerValp
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.
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).
2016-05-17 11:34
Krill

Registered: Apr 2002
Posts: 1106
Quoting JackAsser
And 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
2016-05-17 11:48
Frantic

Registered: Mar 2003
Posts: 1369
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. :)
2016-05-17 13:36
Bob

Registered: Nov 2002
Posts: 66
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..
2016-05-17 15:18
Krill

Registered: Apr 2002
Posts: 1106
Quoting Bob
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..
This pretty much sounds like a practical implementation of my buckets theory i mentioned above :D
2016-05-17 16:28
Hypnosis

Registered: Mar 2015
Posts: 25
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.
2016-05-17 19:08
lft

Registered: Jul 2007
Posts: 356
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.
2016-05-17 19:39
Rastah Bar

Registered: Oct 2012
Posts: 165
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.
2016-05-18 07:50
Fresh

Registered: Jan 2005
Posts: 84
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.
2016-05-18 12:31
Krill

Registered: Apr 2002
Posts: 1106
Quoting lft
and 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.
2016-05-18 12:48
Oswald

Registered: Apr 2002
Posts: 4365
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.
2016-05-18 14:12
Fresh

Registered: Jan 2005
Posts: 84
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.
2016-05-18 19:18
Skate

Registered: Jul 2003
Posts: 473
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.
2016-05-18 20:46
Monte Carlos

Registered: Jun 2004
Posts: 266
It can be used for text scrollers with varying y-pos to fill in the rightmost char if addresses are prepared in zp
2016-05-19 08:50
oziphantom

Registered: Oct 2014
Posts: 248
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?
2016-05-19 14:14
Rastah Bar

Registered: Oct 2012
Posts: 165
Quoting oziphantom
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?


A complete description of TAS and other undocumented opcodes can be found here
No More Secrets v0.9
2016-05-20 16:30
oziphantom

Registered: Oct 2014
Posts: 248
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
2016-05-20 22:13
HCL

Registered: Feb 2003
Posts: 679
Quoting lft
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).

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) :).
2016-05-21 08:56
Wisdom

Registered: Dec 2001
Posts: 88
Used it in Thread Over and in Matrix 16. Might be useful in some size-coding cases.
RefreshSubscribe to this thread:

You need to be logged in to post in the forum.

Search the forum:
Search   for   in  
All times are CET.
Search CSDb
Advanced
Users Online
Hobbit/Laser Inc.
ZeSmasher/F4CG
grip
CA$H/TRiAD
Guests online: 43
Top Demos
1 Unboxed  (9.7)
2 Uncensored  (9.7)
3 Comaland 100%  (9.7)
4 Edge of Disgrace  (9.7)
5 Coma Light 13  (9.6)
6 The Shores of Reflec..  (9.6)
7 Lunatico  (9.6)
8 Wonderland XII  (9.6)
9 C=Bit 18  (9.6)
10 X Marks the Spot  (9.5)
Top onefile Demos
1 Smile to the Sky  (9.6)
2 Daah, Those Acid Pil..  (9.5)
3 Dawnfall V1.1  (9.4)
4 FMX Music Demo  (9.4)
5 Crystal Gazer  (9.4)
6 Rewind  (9.4)
7 Pandemoniac Part 2 o..  (9.4)
8 Official X2018 Report  (9.4)
9 Arok 20 Invitation  (9.4)
10 Party Horse  (9.3)
Top Groups
1 PriorArt  (9.7)
2 Performers  (9.5)
3 Oxyron  (9.5)
4 Booze Design  (9.4)
5 Censor Design  (9.3)
Top Original Suppliers
1 hedning  (9.8)
2 Derbyshire Ram  (9.4)
3 Irata  (9.2)
4 Fungus  (9.1)
5 Jazzcat  (9.1)

Home - Disclaimer
Copyright © No Name 2001-2019
Page generated in: 0.091 sec.