home  general  lard  emul8or  ArdweeNET  MAXX  the QUUB  Gecko  SiiMAN
        embedded systems  PC software

The AVR instruction set doesn't seem to have an indirect call option, ie. I've got an address pointer in memory (or in a register) and I want to call that address. A common thing to do if for example you have a lookup table.

How to get around this problem? It does have an indirect jump instruction, so I came up with this.

callback_addresses:
.dw tmr_0_callback
.dw tmr_1_callback
.dw tmr_2_callback
.dw tmr_3_callback
.dw tmr_4_callback

;
;
; make Y point to array of function addresses
;
ldi YH,HIGH(callback_addresses<<1)
ldi YL,LOW(callback_addresses<<1)

; now get our function's address from memory table
; let's get func #3 which will be offset 4
ldd ZL,y+4
ldd ZH,y+5

; put the return address on the stack
ldi r24,LOW(callback_returns_here)
push r24
ldi r24,HIGH(callback_returns_here)
push r24

; and jump to function,
; function must "ret" at the end of course
ijmp

some other code:
;
;

callback_returns_here:
; called function returns here but could be anywhere

There may be a better way, after all I've only been programming with AVR assembly language for about a day at this point, but this works a treat. Naturally you would have defined some .EQUs instead of hard coded numbers for offsets etc. and you wouldn't do all this for a single call, you do this sort of thing as part of a larger routine, say a software timer function that wants to call a timer's callback function when the timer expires.


Some time later. Guess who just found the ICALL instruction? We can still use the same example as a method of using a jump table, there's just less faffing around.

callback_addresses:
.dw tmr_0_callback
.dw tmr_1_callback
.dw tmr_2_callback
.dw tmr_3_callback
.dw tmr_4_callback

;
;
; make Y point to array of function addresses
;
ldi YH,HIGH(callback_addresses<<1)
ldi YL,LOW(callback_addresses<<1)

; now get our function's address from memory table
; let's get func #3 which will be offset 4
ldd ZL,y+4
ldd ZH,y+5

; and call to function,
; function must "ret" at the end of course
icall

That's less work because we don't have to explicitly push the return address, but there's probably little difference in time because the address still gets pushed by the processor when it does the ICALL (although that will be quicker).

One advantage to using IJMP is that you can return anywhere you like, not just to to following instruction. You could even not bother pushing a return address at all so when the IJMPed routine returns it really does a return from this routine. Dodgy but a time saver if you need a few extra cycles.

 


Copyright © 1973-2013 Rob Gray, All rights reserved.
PO Box 450, Gin Gin, QLD, Australia.
www.robgray.com