Looping over large chunk of memory

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

User avatar
battagline
Posts: 152
Joined: Wed Sep 05, 2018 11:13 am
Location: Colorado
Contact:

Looping over large chunk of memory

Post by battagline »

Hi everyone... wasn't sure if this should go here or in NESDev, but it's kind of a noob question so I figured I'd start here.


Let's say I have a label and a chunk of 500 bytes of data I want to loop over

Code: Select all

datachunk:
.byte $20,$21,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00, ... etc out to 500 bytes
So I want to start loading at data chunk and loop until I have done some sort of processing on all 500 bytes

Code: Select all

ldx #0
loop:
lda datachunk, x
inx
(do something with the data here)
cpx #500
bne loop
So obviously that won't work because x can only go up to 255, so the question is, what's the best way to loop over all 500 entries?

Thanks,
Rick
A few of my web games
https://www.embed.com
Or if you're bored at work
https://www.classicsolitaire.com
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Looping over large chunk of memory

Post by lidnariq »

Use indirect indexed addressing (e.g. LDA (zp),Y)
User avatar
pubby
Posts: 583
Joined: Thu Mar 31, 2016 11:15 am

Re: Looping over large chunk of memory

Post by pubby »

An easy way is to use the .repeat directive (CA65 syntax)

Code: Select all

.repeat 2, i
    ldx #0
:
  lda datachunk+250*i, x
  ; do stuff
  inx
  cpx #250
  bne :-
.endrepeat
If 'do stuff' is large, put it in a subroutine to save bytes.
User avatar
battagline
Posts: 152
Joined: Wed Sep 05, 2018 11:13 am
Location: Colorado
Contact:

Re: Looping over large chunk of memory

Post by battagline »

pubby wrote:An easy way is to use the .repeat directive (CA65 syntax)
Interesting. Out of curiosity, what would you do if you had a prime number of items?

Thanks
A few of my web games
https://www.embed.com
Or if you're bored at work
https://www.classicsolitaire.com
User avatar
nesrocks
Posts: 563
Joined: Thu Aug 13, 2015 4:40 pm
Location: Rio de Janeiro - Brazil
Contact:

Re: Looping over large chunk of memory

Post by nesrocks »

Repeat forever until you find an item that starts with #FF or something.
https://twitter.com/bitinkstudios <- Follow me on twitter! Thanks!
https://www.patreon.com/bitinkstudios <- Support me on Patreon!
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Looping over large chunk of memory

Post by rainwarrior »

Here's an excerpt from a recent project of mine:

Code: Select all

; copy RAM code from ramp.s
.import __RAMP_CODE_LOAD__
.import __RAMP_CODE_RUN__
.import __RAMP_CODE_SIZE__
__RAMP_CODE_END__ = __RAMP_CODE_RUN__ + __RAMP_CODE_SIZE__
@src = nmt_addr ; temporarily alias these pointer variables
@dst = ptr
lda #<__RAMP_CODE_LOAD__
sta @src+0
lda #>__RAMP_CODE_LOAD__
sta @src+1
lda #<__RAMP_CODE_RUN__
sta @dst+0
lda #>__RAMP_CODE_RUN__
sta @dst+1
ldy #0
@ramp_loop:
	lda (@src), Y
	sta (@dst), Y
	inc @src+0
	bne :+
		inc @src+1
	:
	inc @dst+0
	bne :+
		inc @dst+1
	:
	lda @dst+0
	cmp #<__RAMP_CODE_END__
	lda @dst+1
	sbc #>__RAMP_CODE_END__
	bcc @ramp_loop
1. The 16-bit address __RAMP_CODE_LOAD__ is loaded into "@src". (Source data to copy.)
2. The 16-bit address __RAMP_CODE_RUN__ is loaded into "@dst". (Destination.)
3. Use indirect addressing to copy from @src to @dst.
4. 16-bit increment of @src.
5. 16-bit increment of @dst.
6. 16-bit compare @dst against __RAMP_CODE_END__. If less than, repeat from 3.

__RAMP_CODE_END__ here is the address of the first byte past the end of the region to be copied to. Alternatively we could have had another 16-bit variable for the number of bytes to be copied and just decremented it each time and checked for zero. There are a bunch of other manipulations that could be done for optimization or other reasons, but this one basic expression of what it means to "use indirect indexed addressing" for this.
User avatar
pubby
Posts: 583
Joined: Thu Mar 31, 2016 11:15 am

Re: Looping over large chunk of memory

Post by pubby »

battagline wrote: Interesting. Out of curiosity, what would you do if you had a prime number of items?

Thanks
It's really uncommon, but I'd do as many 256 iteration loops as possible, then one extra loop at the end handling the remainder.

Code: Select all

  ldx #0
.repeat ((8191 + 255) / 256), i
  .if i = ((8191 + 255) / 256) - 1
    ldx #8191 .mod 256
  .endif
:
  lda datachunk+256*i, x
  jsr do_stuff
  inx
  bne :-
.endrepeat
Something like this. I haven't tested it though.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Looping over large chunk of memory

Post by tokumaru »

The canonical way is to use indirect indexed addressing, like lidnariq said. While lda ABS, x adds an 8-bit offset to a constant base address in order to find the final address to access, lda (ZP), y uses a 16-bit pointer in Zero Page as the base, meaning you're free to access the entire 16-bit address space of the 6502.

Indirect addressing is obviously slower, so in situations where you need speed, you can be creative and figure alternatives ways of accessing the data faster, usually involving rearranging the data in some way other than a linear array, but there's no generic fast solution for all cases.
User avatar
battagline
Posts: 152
Joined: Wed Sep 05, 2018 11:13 am
Location: Colorado
Contact:

Re: Looping over large chunk of memory

Post by battagline »

Thanks guys, this has been really helpful.

QQ for rainwarrior:
Does

Code: Select all

inc @dst+0
do the same thing as

Code: Select all

inc @dst
If so, why add the +0, and if not what is the difference?

Thanks
A few of my web games
https://www.embed.com
Or if you're bored at work
https://www.classicsolitaire.com
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Looping over large chunk of memory

Post by tepples »

They do the same thing. The +0 is there to remind the (human) reader of the source code that the variable is a multi-byte variable.
User avatar
battagline
Posts: 152
Joined: Wed Sep 05, 2018 11:13 am
Location: Colorado
Contact:

Re: Looping over large chunk of memory

Post by battagline »

tepples wrote:They do the same thing. The +0 is there to remind the (human) reader of the source code that the variable is a multi-byte variable.
Ahh... that makes sense.

Thanks
A few of my web games
https://www.embed.com
Or if you're bored at work
https://www.classicsolitaire.com
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Looping over large chunk of memory

Post by rainwarrior »

Yeah, that's just a convention I use for 16-bit (or wider) values in 6502 assembly.

I don't know if other people do this, but like tepples suggested the +0 helps remind me that I'm looking at an operation that's going to have more than one byte to it. It's more of an automatic habit at this point.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Looping over large chunk of memory

Post by tokumaru »

I've always used +0 when referencing the first byte of multi-byte variables, and sometimes people call me out for it, but I think it greatly improves readability.
User avatar
nesrocks
Posts: 563
Joined: Thu Aug 13, 2015 4:40 pm
Location: Rio de Janeiro - Brazil
Contact:

Re: Looping over large chunk of memory

Post by nesrocks »

Is what I said totally a bad idea? Or doesn't it apply? The advantage is that the list of objects can be any size. The disadvantage is that it can't have one specific byte value (or bit) at a certain point in the data array. You do need to check for that $FF byte on every item, but when using a counter you need to check against it, so I guess it's the same on that aspect, optimization-wise.
And in the OP case, I imagine it's one big object of 500 bytes? In that case you could reserve $FF to be the end of the data.
Last edited by nesrocks on Thu Sep 27, 2018 5:36 am, edited 1 time in total.
https://twitter.com/bitinkstudios <- Follow me on twitter! Thanks!
https://www.patreon.com/bitinkstudios <- Support me on Patreon!
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Looping over large chunk of memory

Post by rainwarrior »

nesrocks wrote:Is what I said totally a bad idea? Or doesn't it apply? The advantage is that the list of objects can be any size. The disadvantage is that it can't have one specific byte value (or bit) at a certain point in the data array. You do need to check for that #FF byte on every item, but when using a counter you need to check against it, so I guess it's the same on that aspect, optimization-wise.
And in the OP case, I imagine it's one big object of 500 bytes? In that case you could reserve #FF to be the end of the data.
Well, strings terminated with a 0 byte are incredibly common in the world, copying which is the same process as you're describing.

But yes I'd say not being able to represent one particular byte in your data is a problem in the generic case. The utility of strcpy vs memcpy. One is for a specific kind of data that indicates its own length, one is for any data but you have to supply the length.
Post Reply