Page 1 of 1

Z80 jump table

Posted: Sun Mar 18, 2018 11:55 pm
by Sik
Just noticed you can do this to get a jump table on the Z80 (probably an old trick and I'm being a newbie, but whatever):

Code: Select all

; a = index (0..42)
; b = spare

    ld      b, a            ; Multiply index by 3
    add     a, b
    add     a, b
    ld      ($+4), a        ; Overwrite the jump destination
    jr      $               ; Jump to the table
    
    jp      Routine1
    jp      Routine2
    jp      Routine3
    ...
This relies on self-modifying code (it overwrites a jump), so you need to run this off RAM, but that's usually the case on the Mega Drive so no biggie. Also the index is quite limited due to overflow (maximum that works is 42), but it still should be large enough for most purposes. Beats having to do 16-bit arithmetic on an address when you can't ensure a table will be within a 256 byte boundary.

I'm multiplying the index by 3 since that's how long a JP instruction is (I'm assuming that the targets may be anywhere). If you can really ensure that all target addresses are close enough (within around 127 bytes*) then it'd look more like this:

Code: Select all

; a = index (0..63)

    add     a, a            ; Multiply index by 2
    ld      ($+4), a        ; Overwrite the jump destination
    jr      $               ; Jump to the table
    
    jr      Routine1
    jr      Routine2
    jr      Routine3
    ...
By the way, the $ in that jump is just a placeholder (it'll be overwritten), I just picked something that would be within the allowed range so it can assemble.

*I say "around" since it needs to be 127 bytes away from the specific jump, so the actual maximum distance from the start of the code depends on which entry is being jumped to. Still should give a good idea of how far away it can afford to be.

Re: Z80 jump table

Posted: Mon Mar 19, 2018 6:35 am
by HardWareMan
Z80 have jp (hl). Just a hint.

Re: Z80 jump table

Posted: Mon Mar 19, 2018 9:09 am
by Stef
What i'm doing in my XGM driver :

Code: Select all

    LD    A, (DE)             ; A = command           ' 7     |
    LD    (.ld_hl_xx + 1), A  ; set jump address      ' 13    |

.ld_hl_xx
    LD    HL, (JUMP_TABLE)    ; LD HL, (jt)           ' 16    |
    JP   (HL)                    ;             ' 4 |
Note that compiled XGM always encode command shifted by one (<<= 1) to save some cycles here but that reduce number of entries to 0x80.

Re: Z80 jump table

Posted: Tue Mar 20, 2018 5:15 am
by Sik
HardWareMan wrote:
Mon Mar 19, 2018 6:35 am
Z80 have jr (hl). Just a hint.
You mean JP :v

But anyway, using that would then require 16-bit operations to calculate the address which is like the whole thing I was trying to avoid (as it starts getting cumbersome). Either that or ensuring the table never crosses a 256 byte boundary (which is not always worth it, as you need to do lots of juggling regarding where you put those tables in the code, so better leave that for stuff you may need to access a lot or the like).
Stef wrote:
Mon Mar 19, 2018 9:09 am
Note that compiled XGM always encode command shifted by one (<<= 1) to save some cycles here but that reduce number of entries to 0x80.
Yeah, for speed critical stuff it may be better to store the index multiplied by the entry size already.

Re: Z80 jump table

Posted: Tue Mar 20, 2018 7:25 am
by HardWareMan
Sik wrote:
Tue Mar 20, 2018 5:15 am
HardWareMan wrote:
Mon Mar 19, 2018 6:35 am
Z80 have jr (hl). Just a hint.
You mean JP :v
I mean PCHL since I don't like Z80 mnemonics.