Arrays: Difference between revisions

Content added Content deleted
m (→‎Array Alignment: this was meant to be a subsection of z80 assembly)
Line 85: Line 85:
YREGS
YREGS
END ARRAYS</lang>
END ARRAYS</lang>
=={{header|6502 Assembly}}==

===One-Dimensional Arrays===
An array is little more than just a contiguous section of memory. Whether or not an array is mutable depends solely on whether it is defined in ROM or RAM. The syntax will be discussed in further detail in the Two-Dimensional Arrays section.

<lang 6502asm>Array:
db 5,10,15,20,25,30,35,40,45,50</lang>


Side note: Some systems, such as the Nintendo Entertainment System or other ROM cartridge-based computers, cannot use the above declaration to initialize an array in RAM at assemble time; only in ROM. While the label "Array" can be given to an arbitrary RAM location on any system, you won't be able to define a data block in RAM the same way you would on an assembly program meant to run on the Apple II or Commodore 64 for example. The examples below will still work on any system, you just won't be able to "see" the array before running the program, if that makes sense. Clearing the system ram will suffice to initialize the array to zero.

Looking up a value in an array is fairly straightforward. The best addressing modes for doing so are <code>LDA $????,x</code>,<code>LDA $????,y</code>, and <code>LDA ($??),y</code>. In this case, x or y represents the index into the array. To put it in terms of C:

<lang c> char foo()
{
char array[5] = {3,6,9,12,15};
return array[2];
}</lang>

would (theoretically) compile to the following in 6502 Assembly:
<lang 6502asm>
foo:
LDX #2 ;load the desired index
LDA array,x ;load the second (zero-indexed) entry in array, i.e. 9
RTS ;return. The return value is stored in A.

array: ;this is the array we're reading from.
db 3,6,9,12,15</lang>
===Arrays in the Zero Page - A Word of Warning===
One important thing to note is a hardware bug involving <code>LDA $??,x</code>. If the sum of $?? and x would exceed 255, instead of continuing past $100, the CPU will actually wrap around back to $00. This does not happen with absolute addressing modes or indexed indirect with Y. Here's an example:

<lang 6502asm>LDX #$80
LDA $80,x ;evaluates to LDA $00
LDA $0480,x ;evaluates to LDA $0500</lang>

If you really want to read from an array in the zero page like this (and chances are you won't since that array also starts to overlap with the hardware stack), you can use an absolute addressing mode in the zero page. Beware - some assemblers will forcibly optimize <code>LDA $00??</code> into <code>LDA $??<code> so you may have to inline the bytecode for it directly. If you stick to arrays outsize the zero page you don't need to worry about index wraparound.
===Arrays of 16-Bit Data===
You can have arrays of 16-bit data as well as 8-bit ones. There are a few ways to do this, and we'll go over the "naive" way first:
<lang 6502>wordArray:
dw $ABCD,$BEEF,$CAFE,$DADA</lang>

The 6502 is little-endian, so the above would be exactly the same as the following:
<lang 6502>wordArray:
db $CD,$AB,$EF,$BE,$FE,$CA,$DA,$DA</lang>

To properly index a 16-bit array that's formatted as in the above example, you'll need to double your index. In this example, we'll be loading the offset of <code>$BEEF</code>:
<lang 6502>LDX #2 ;load the 1st (zero-indexed) WORD from the array (which is why this is 2 not 1)
LDA wordArray,X ;evaluates to LDA #$EF
STA $00 ;store in a zero page temporary variable
INX ;point X to the high byte
LDA wordArray,X ;evaluates to LDA #$BE
STA $01 ;store in a different zero page temporary variable. If your word data is a pointer you want to dereference,
;you'll need to store the low byte in $nn and the high byte in $nn+1 like I did here.</lang>

There are a few downsides in 6502 assembly to storing word data in this format. A minor one is the need to double your index. This isn't a big deal, it doesn't take long to do that. The bigger problem is that the 6502 has a soft array length cap of 256 bytes. If your code is running in ROM and you're not able to use self-modifying code to adjust the base address, or you're not willing to use the slower <code>LDA ($??),y</code>, you're mostly limited to 256 bytes or 128 words.

However, if you split the word table into two byte tables, you can actually get more bang for your buck, and it takes the same amount of memory no matter which way you store the data.
<lang 6502asm>wordArray_Lo:
db $CD,$EF,$FE,$DA

wordArray_Hi:
db $AB,$BE,$CA,$DA ;both this version and the above versions are 8 bytes of memory.</lang>

If both wordArray_Lo and wordArray_Hi were 256 bytes each, you'd be able to index both of them no problem, where you wouldn't be able to do that if it were one array. Let's try loading <code>$BEEF</code> again:

<lang 6502>LDX #1 ;with split arrays we DON'T need to double our index.
LDA wordArray_Lo,x ;evaluates to LDA #$EF
STA $00
LDA wordArray_Hi,x ;evaluates to LDA #$BE
STA $01</lang>

Both tables share the same index, which means you can do the lookup without destroying your index (not that it was that difficult to retrieve the original index to begin with), but on 8-bit computers you want to be as efficient as possible, using the hardware's strengths to your advantage. Splitting your "wider" arrays into multiple 8-bit tables is often the best approach.

===Two-Dimensional Arrays===
I'll let you in on a little secret: two-dimensional arrays don't exist. This is just as true for modern computers as it is the 6502.
In the first section I had this example of an array:
<lang 6502asm>Array:
db 5,10,15,20,25,30,35,40,45,50</lang>

In the eyes of the CPU, this is the same as ANY of the following:
<lang 6502asm>Array:
db 5
db 10
db 15
db 20
db 25
db 30
db 35
db 40
db 45
db 50</lang>

<lang 6502asm>Array:
db 5,10
db 15,20
db 25,30
db 35,40
db 45,50</lang>

or any other way to write it you can imagine. All that matters is the order of the bytes in the array - as long as that is the same you can write it however you want. It's best to write it in the way it's meant to be interpreted, however. But in order to explain that to the computer you'll need a little bit of finesse. Let's pretend that the "correct" interpretation is this 5 by 2 array:

<lang 6502asm>Array:
db 5,10
db 15,20
db 25,30
db 35,40
db 45,50</lang>

For this example, we want row 3 and column 1 (zero-indexed for both) which means we want to load 40.
<lang 6502>
LDA #3 ;desired row
ASL A ;Times 2 bytes per row (if the array's row size wasn't a multiple of 2 we'd need to actually do multiplication)
;which the 6502 doesn't have in hardware but can be simulated by repeated adding.
CLC
ADC #1 ;desired column (since it's 1 byte per column, we can skip the part where we multiply desired column by bytes per column)
TAX ;move A to X so we can use it as the index

LDA Array,x ;evaluates to LDA #40</lang>

You may be wondering, why not just treat the array as though it were one-dimensional? Reason is, you won't always know in advance what you want from your array, it may depend on 2 variables in your program (such as X/Y coordinates, etc.), so you might need to use this method rather than just treating it as linear data.


=={{header|68000 Assembly}}==
=={{header|68000 Assembly}}==
Creating an array is as simple as declaring its base address. Note that all bounds checking must be done by the programmer and is not built in by default.
Creating an array is as simple as declaring its base address. Note that all bounds checking must be done by the programmer and is not built in by default.