Tables and Arrays
z80 » Intermediate
A lot of times you want to access info in a table or a list. Remember the index registers?
ld iy,table_start ld a,(iy+4)You would be referencing the fourth item from the beginning of the list with the address of
iy's value. You still retain the address for the beginning of the table.
That's good for accessing specific elements in the list. If you
want to take a list and check each thing against a value, the best
thing is to use a recursive loop. Here's a simple routine to check
a in comparison to every item in the table. If there's
a match, the place value of that match is put into
b; if there's no
b is loaded with 0:
check: ld b,end_of_table-table ld hl,table check_loop: cp (hl) ret z inc hl djnz check_loop ret table: .db $34,$a3,$eb,$56,4,1,$20,$ff,220,$0a end_of_table:
Here's some different code that does the same thing but is shorter
and uses a new instruction (
cpir) which does the following: compares
(hl), if it's equal then exit, if not decrease
and repeat until either
bc is zero or
is the same routine from above, but instead it uses
check: ld bc,end_of_table-table ld hl,table cpir ret table: .db $34,$a3,$eb,$56,4,1,$20,$ff,220,$0a end_of_table:
The second routine is two bytes shorter. Two bytes doesn't seem like anything really but it adds up and everything. Sometimes the only difference between two versions of a game is a five or six byte change!
Let's say you wanted to make an array (list) with
each element 1 byte in length to hold the
letters of the alphabet. Let's also
say the array can be trashed once your program is
done. We'll use a safe memory
area at the end of our program at, say, address
$f200. Let's start loading the array with
letter values, incrementing the array length counter
array_size at address $f200). We already
know that we only have 26 letters but we're using
a counter to demonstrate the principle of having
some counter to tell you the size of the array. The
actual array's element data will start
at address $f201. You can just
download the source
code if you want to assemble it to see
Keep in mind, this is a really cumbersome method of referencing elements. I'm only trying to show you the fundamentals. It would be much faster to do it as shown in Array2.asm with Simulated 16 bit Addition.
a_size =$f200 ;array size array_start =$f201 ;start of element data e_size =1 ;element size in bytes #define array(element) array_start+((element-1)*e_size) ;each element is two bytes ;when we want the 2nd element, we usually ; put 'array(2)' but since 0 is the first ; element, we subtract 1 from what we ; requested #include "ti86asm.inc" .org _asm_exec_ram ;let's start loading the array with ; values ld hl,array(1) ;return the address of the ; first element in de ld ix,a_size ;size/length counter address ld (ix),$00 ;initialize counter to $00 ; because we haven't stored ; anything in it yet ;ix register pair can be used ; just like hl ld de,e_size ;load de with the size ; of each element so we ; can move from one element ; to the next ld b,26 ;there are 26 characters ; in the alphabet...i hope ld a,'a' ;letter to start with initialize_loop: ld (hl),a ;load element inc a ;increment letter value inc (ix) ;increment counter value add hl,de ;add where we are to ; the length of each element ; to get the next element's ; address djnz initialize_loop call _clrScrn ;clear the screen call _homeup ;put cursor at top left ;now let's print the word "stupid" letter by letter ld hl,array(19) ;'s' call print_element ld hl,array(20) ;'t' call print_element ld hl,array(21) ;'u' call print_element ld hl,array(16) ;'p' call print_element ld hl,array(9) ;'i' call print_element ld hl,array(4) ;'d' call print_element call _getkey ;wait for keypress jp _clrScrn ;clear screen and return ;print_element prints the character in the ; array at address held by hl print_element: ld a,(hl) ;get that element's value jp _putc ;print character and return .end
To get a little more complicated,
let's check out tables. Here's a look up
routine for a table with 3 columns.
You input into
d the desired row,
e the desired column, and have
hold the address of the queried table. You
can see this routine in action used
It also uses Simulated 16
ld de,1*256+2 ;row 1, col 2 ld hl,table call get_cell . . . . . . ;input: d=row ; e=col ; hl=address of 3x3 table ;output:a=value get_cell: dec e ;decrease columns ; since $00 is 1st ; column dec d ;decrease rows ; since $00 is 1st ; column sub a ;initialize to $00 ld b,d ;get row # jr z,no_row_mult row_multiply_loop: add a,table_width ;width of table (3) djnz row_multiply_loop no_row_mult: add a,e ;add in col # ;now we get into simulated 16 bit addition ; of adding an 8 bit register (a) to a 16 bit one (hl) add a,l ld l,a adc a,h sub l ld h,a ld a,(hl) ret table: .db 'a','b','c' .db 'd','e','f' .db 'g','h','i'
This is still only an introduction, designed just to teach you the basics. There are so many other ways to use tables and arrays that you will have to discover on your own and tailor to your programs.
More from z80 » Intermediate
All the Flags // Debugging // Down-Left Bug // _GetKey Codes // Logical Operators // Memory, ROM, RAM, and Safe Areas // Miscellaneous Instructions // PC and SP // Random Numbers // TI's ROM Calls // Restart Commands // Simulated 16-bit Addition // The Stack // Tables and Arrays // Text Display // Variables