I am storing my Scores like this:

Code:
Scores:
    .db $00,$00
    .db $00,$01
    .db $00,$02
    .db $00,$03
    .db $00,$04
    .db $00,$05
    .db $00,$06
    .db $00,$07
Let's say this is my code before those 5 lines:

Code:
ld hl,Scores  ;load address of Scores into HL register
ld e,(hl)                  ;load 8 bits of Scores data
ld d,(hl)                  ;load the other 8 bits of Scores data
                              ;do something with value in de


My understanding of the code:

Code:
inc hl                      ;increment address of Scores by 1
inc hl                      ;increment address of Scores by 1
ld e,(hl)                  ;load 8 bits of Scores data
ld d,(hl)                  ;load the other 8 bits of Scores data


I'm confused.

Code:
ld e,(hl)                  ;load 8 bits of Scores data
ld d,(hl)                  ;load the other 8 bits of Scores data
This is where you're wrong.

Consider what happens here:
  • Load an address into HL. Let's say it's 0x8000.
  • Get the byte at (HL) and store it into E. (0x8000) -> E.
  • Get the byte at (HL) and store it into D. (0x8000) -> D.
See the problem yet?

Will work correctly:

Code:
ld hl, Scores
ld e, (hl)
inc hl
ld d, (hl)


This is incidentally something the index registers are handy for (though cases where it's actually more efficient to do so are rare).

Code:
ld ix, Scores
ld e, (ix)
ld d, (ix + 1)
(A bit off-topic, but i thought i'd share in anycase)

In this instance it's not very efficient to use the index registers, but if you've got a lot of data per pointer, for example a list of enemies with an x and y location, x and y velocity, id, animation frame, action id, etc. putting the address into ix can be really handy, particularly since you rarely touch them so you don't generally have to worry about it getting changed. I often use ix for handling bullets and enemies. Here's something from one of my games:

Code:
;enemy constants
MAX_ENEMIES   = 25
ENEMY_SIZE   = 9
EID         = 0
EX         = 1
EY         = 3
EPAT      = 5
EFRAME      = 6
EHP         = 7
ESHOOT      = 8

;bullet constants
MAX_BULLETS   = 50
BULLET_SIZE   = 7
BID         = 0
BX         = 1
BY         = 3
BFRAME      = 5
BDMG      = 6
If i'm messing with enemies, i do something like ld ix,enemy_array. If i want to read the x or y values, i can just do ld a,(ix+EX) or ld a,(ix+EY). If hit the enemy, i can do dec (ix+EHP). If the enemy is dead, i can ld (ix+EID),$FF. The best part is that i don't have to keep track how far i am in hl and when i've reached the end of the necessary stuff for that enemy i can just add ix,ENEMY_SIZE,

Back on topic, in some assembly languages (like ARM) you can have the register automatically increase when you read from it. The z80 doesn't, so if you want to read the next byte, you have to increase every time.

If you wanted to display the list of scores, for example, you would have something like this:

Code:
    ld hl,Scores
    ld b,8
score_loop:
    ld e,(hl)
    inc hl
    ld d,(hl)
    inc hl
    call disp_score
    djnz score_loop
...though you'd probably need to put hl and bc on the stack since disp_score will most likely change their values.
@chickendude
I tried using your code and modified the code to load Scores into ix instead and load the data from the ix address to h and l instead. It keeps loading the first value each time. I don't understand what is going on here.

Code:

    ld h,(ix)
    inc ix
    ld l,(ix)
    inc ix
I fixed the problem. I'm getting an Overflow error though when trying to display a number that is $00,$00 aka 0.

I'm using:

Code:

conv_to_float_16:
    BCALL(_SetXXXXOP2) ;set OP2 = HL
    BCALL(_OP2ToOP1)   ;copy 11 bytes from OP2 to OP1
    ret

display_scores_strings:
    ld ix,Scores
display_loop:
    ld h,(ix)
    inc ix
    ld l,(ix)
    inc ix
    push bc
    push ix
    call conv_to_float_16
    bcall(_DispOP1A)
    ld a,50
    ld (penCol),a
    ld a,(penRow)
    add a,7
    ld (penRow),a
    pop ix
    pop bc
    djnz display_loop
    ret
Fixed it. I'm an idiot and didn't load the # of digits to display into A before BCALL(_DispOP1A).
One thing you should keep in mind is that the z80 is little-endian, this means that the right part of the number gets stored first. Let's look at your scores:

Code:
Scores:
    .db $00,$00
    .db $00,$01
    .db $00,$02
    .db $00,$03
    .db $00,$04
    .db $00,$05
    .db $00,$06
    .db $00,$07
The first score is of course zero, the second score is actually 256. This is because $00 is actually the LSB (least significant byte), $01 is the MSB (most significant byte). The number is read as $0100, which is 256 in hex. The next score is $0200, or 512 in hex.

This probably works ok in your program because you actually load the data backwards, in hl, l holds the small byte ($00-$FF) and h holds the large byte ($0100-$FF00). You load the small byte into h, then the large byte into l. Normally you do it this way:

Code:
ld l,(ix)
inc ix
ld h,(ix)
If you did "ld hl,(Scores+2)", you would find that the values are mixed up. It's mentioned briefly in 28 days here:
http://tutorials.eeems.ca/ASMin28Days/lesson/day05.html#ram[/code]
@chickendude

I just learned about big and little endian. I just changed my code and loaded l before h and it seems to be working fine now. Thanks.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 2 of 2
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement