News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_erikarn

jumptable examples?

Started by erikarn, 04:20, 06 September 10

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

erikarn

Hi,

I'm writing a little Forth-ish stack VM in Z80 assembler for the CPC and I've hit a stupid, trivial snag. I'd like to use a jumptable of calls based on the opcode but I couldn't figure out a nice way of doing it.

What I'm currently doing just to get around it (from memory):

PUSH IX
PUSH BC
LD IX, jumptable
LD BC, 0
LD C, A    ; A has the jumpcode op in it
ADD IX, BC
ADD IX, BC  ; jumptable is two bytes per entry
LD C, (IX+0)
LD B, (IX+1)
LD IX, call_offset
LD (IX+1), C
LD (IX+2), B
POP BC
POP IX
call_offset: CALL &0
RET

Now - this is fine for RAM code but I'd like to eventually put this VM in a ROM, rather than in RAM. I can always just use scratch RAM for that rather than self-modifying in-line code.

Does anyone have any suggestions on better (tighter, faster) ways of doing this? Besides the obvious "two 16-bit ADDs? are you crazy?" :-)

Thanks!


andycadley

#1
If you just want to eliminate the self modifying code, you can do the equivalent of CALL IX with:

CALL call_ix
RET
call_ix: JP (IX)

EDIT: Although, having re-read it again I think you need CALL BC, which should be something like:

CALL call_bc
RET
call_bc: PUSH BC
RET

arnoldemu

Quote from: erikarn on 04:20, 06 September 10
Hi,

I'm writing a little Forth-ish stack VM in Z80 assembler for the CPC and I've hit a stupid, trivial snag. I'd like to use a jumptable of calls based on the opcode but I couldn't figure out a nice way of doing it.

What I'm currently doing just to get around it (from memory):

PUSH IX
PUSH BC
LD IX, jumptable
LD BC, 0
LD C, A    ; A has the jumpcode op in it
ADD IX, BC
ADD IX, BC  ; jumptable is two bytes per entry
LD C, (IX+0)
LD B, (IX+1)
LD IX, call_offset
LD (IX+1), C
LD (IX+2), B
POP BC
POP IX
call_offset: CALL &0
RET

Now - this is fine for RAM code but I'd like to eventually put this VM in a ROM, rather than in RAM. I can always just use scratch RAM for that rather than self-modifying in-line code.

Does anyone have any suggestions on better (tighter, faster) ways of doing this? Besides the obvious "two 16-bit ADDs? are you crazy?" :-)

Thanks!

You can either have the addresses for each opcode in the table:
e.g.

defw opcode0
defw opcode1

and have code like this:

ld l,a
ld h,0
add hl,hl
ld de,jumptable
add hl,de
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
jp (hl)

or you could have the jumps themselves

jp opcode0
nop
jp opcode1
nop

etc

and have this

ld l,a
ld h,0
add hl,hl
add hl,hl
ld de,opcode_table
add hl,de
jp (hl)

all of these work without self modifying code and may be quicker...

(the nops are added between the jp, to make them each on a 4-byte boundary, and making the code to jump to them a bit smaller and faster, but this option means more ram used for the jumptable)

if there are less opcodes than 255 you can do other tricks to make it faster.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Axelay

Just thinking about doing it with registers preserved, a slight variation of the one given by arnoldemu:

push hl
push de
ld l,a
ld h,0
add hl,hl
ld de,jumptable
add hl,de
ld a,(hl)
inc hl
ld h,(hl)
ld l,a
pop de
ex (sp),hl
ret

might work? 

Powered by SMFPacks Menu Editor Mod