Hi again!
I have improved this a bit, making it a subroutine. Now, it can behave like ON a GOTO (using jp) or like ON a GOSUB (using call):
; ...code here...
ld hl, @@JUMP_TABLE
ld a, [var]
call JP_TABLE ; could be jp JP_TABLE
; ...more code here...
@@JUMP_TABLE:
dw label_if_0
dw label_if_1
dw label_if_2
; Uses a jump table
; param hl: address of the jump table
; param a: 0-based unsigned index to use
; modifies a, hl
JP_TABLE:
add a ; a *= 2
add l ; hl += a
ld l, a
adc h
sub l
ld h, a
ld a, [hl] ; hl = [hl]
inc hl
ld h, [hl]
ld l, a
jp [hl]
; bytes: 13, time: 63
Another approach is to load hl from the stack. This forces the jump table to be just below the call, and limites usage to work like ON a GOTO only, but saves 3 bytes in the caller code:
; ...code here...
ld a, [var]
call JP_TABLE ; notice is a call, but that will behave like jp
dw label_if_0
dw label_if_1
dw label_if_2
; Uses the jump table. Its direction will be pop from the stack
; param a: 0-based unsigned index to use
; modifies a, hl
JP_TABLE:
add a ; a *= 2
pop hl ; retrieves hl
add l ; hl += a
ld l, a
adc h
sub l
ld h, a
ld a, [hl] ; hl = [hl]
inc hl
ld h, [hl]
ld l, a
jp [hl]
; bytes: 14, time: 74
Another example of this technique can be found in Mr. Chin, by HAL Laboratory. Their code is 1 byte smaller but destroys the value of de register:
JP_TABLE:
9434: add a, a ; a *= 2
9435: ld e, a
9436: ld d, #00 ; de = a
9438: pop hl ; retrieves hl
9439: add hl, de ; hl += de
943A: ld e, (hl)
943B: inc hl
943C: ld d, (hl) ; de = (hl)
943D: ex de,hl ; hl = de
943E: jp (hl)
; bytes: 13, time: 74
Have fun!