Karoshi MSX Community

Desarrollo MSX => Rutinas - Snipets => Mensaje iniciado por: theNestruo en 22 de Junio de 2012, 09:34:38 pm



Título: ON a GOTO / ON a GOSUB in ASM
Publicado por: theNestruo en 22 de Junio de 2012, 09:34:38 pm
Hi!

This ASM code works like ON a GOTO (BASIC) or switch..case (C):
Código:
   ld a, nn ; param a: unsigned 8bit value

   ld hl, @@JUMP_TABLE
; a *= 2
   add a, a
; hl += a
   add a, l
   ld l, a
   adc a, h
   sub l
   ld h, a
; hl = [hl]
   ld a, [hl]
   inc hl
   ld h, [hl]
   ld l, a
   jp [hl]
@@JUMP_TABLE:
   dw label_if_0
   dw label_if_1
   dw label_if_2
   ; ...

label_if_0:
   ; ...

label_if_1:
   ; ...

label_if_2:
   ; ...

Please note that:
  • a is 0-based, not 1-based (like in ON a GOTO).
  • there is no range checking, so be careful to not use values of a greater than the size of the jump table

Suggestions and improvements are welcome :)


Título: Re: ON a GOTO / ON a GOSUB in ASM
Publicado por: theNestruo en 26 de Marzo de 2013, 08:33:49 pm
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):
Código:
; ...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:
Código:
; ...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:
Código:
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!