assemblymemory-managementcpu-registersz80

Load value of register in 2 by 2 bytes to another register


I am learning Z80 assembly programming for the Amstrad CPC, and then I need to get the address from a list of two byte hex values, but for the moment I know how to get 1 by 1 byte (using 'A' register).

I have a "table" of addresses named 'map' that stores random video memory addresses.

for example:

map:
dw #C630, #C6E8, #C73D, #C78F

;;for C630 address is 4007
;;for C6e8 address is 4009
;;for C73D address is 400B
;;for C78F address is 400D

I could access It with index register instructions (ix or iy) but while I'm learning more, I undestand that index registers can pushed and popped or load 'A' register whith only 1 byte, not 2 bytes as I need.

My question is: there is some method to get the 2 bytes address (4007) and load the COMPLETE ADDRESS (4007) in a register and then load the COMPLETE VALUE (C630) of this address and not only 1 by 1 byte using 'A' register?

Something like if this Z80 instruction exists:

ld hl,(ix)

Solution

  • You urgently need to obtain a programmer's manual for the Z80 that includes a detailed chapter on its instructions. Use your web search skills to find one.

    There are instructions do implement this.

    For example you can read a 16 bit value from an absolute address:

        ld  hl,($4007)
    

    If you have the address in a register pair, unfortunately there is not single instruction to read a 16 bit value via this "pointer". But you can do it in a few instructions:

        ld  hl,$4007
        ; hl now has $4007
    
        ld  e,(hl)
        inc hl
        ld  d,(hl)
    
        ; optionally, if needed to restore the original address:
        dec hl
    
        ; alternatively, if needed to advance to the next address:
        inc hl
    

    BTW, experienced Z80 programmer try to avoid using IX and IY because of the worse performance compared to HL (1 more M1 cycle, 1 more M2 cycle, and some clocks for addition per load operation, as well as 2 more bytes per instruction). For example, you could write:

        ld  l,(ix)   ; actually "ld  l,(ix+0)" that is sometimes clearer
        ld  h,(ix+1)
    

    But this will "cost" 38 clocks and 6 bytes, while the former example needs 26 clocks and 4 bytes.

    If you need a real lot of loading and do not need the stack for processing, you can abuse the stack pointer. I found this trick in a Gameboy game. Its processor is quite similar to the Z80 but lacks the repeated load instructions like ldir.

        ; don't forget to save the SP somewhere else, if necessary...
        ld  sp,$4007
        pop hl
        ;...
        ; restore the SP