Subject:
Re: [gnupic] function pointers?
with gplink)
From:
Bill Freeman ####@####.####
Date:
21 May 2005 13:41:48 +0100
Message-Id: <17039.11408.807667.742461@localhost.localdomain>
Iain Dooley writes:
> Peter Onion wrote:
> > On Sat, 2005-05-21 at 12:54 +0000, Iain Dooley wrote:
> >
> >
> >>loop:
> >> ;load the value of the function table into fsr
> >> lfsr FSR0,function_table
> >> ;load the count into WREG
> >> movf count,W
> >> ;execute the function using PLUSW0
> >> movff PLUSW0,PCL ;??????? THIS IS THE STEP THAT I'M NOT SURE OF!!!
> >> ;have we executed all our functions?
> >> decfsz count
> >> ;nope, go and do it again
> >> bra loop
> >>;yep, finish the program
> >>end
Let me preface this by confessing that I, too, have only used
12 and 14 bit devices. However, assuming that I understand what you
are trying to do, there are a few bugs here.
Assuming that all your other ducks are in a row, if theses are
truely functions, that is, they come back with a return instruction,
then the main problem is that writing PCL is like a goto, it is NOT
like a call. (If these functions are only "called" from here, an
alternate fix would be to put a lable on the decfsz and have the
"functions" branch there instead of doing a return.) Try something
like:
; We presume that count is already set to the table size
; Count ranges from N to 1, need N-1 to 0, thus:
lfsr FSR0,function_table - 1
loop:
movf count, W
call dispatcher
decfsz count, F
bra loop
; All functions have been called
goto next_code ; or maybe return
; This dispatcher code can go anywhere since the 16 bit PIC call
; instruction can call anywhere.
dispatcher:
movff PLUSW0, PCL
This will call the functions in the table in reverse order.
Calling dispatcher saves the address of the decfsz on the stack, so
that when the function returns, that's where it goes. The movff does
indeed behave as a jump to the function.
It's slightly faster to call the functions if forward order
by using the POSTINC0 address. Even if this means having to set
FSR0 to function_table again, that occurs outside the loop, while
the movf count,W occurs inside:
lfsr FSR0,function_table
loop:
call dispatcher
decfsz count, F
bra loop
; All functions have been called
goto next_code ; or maybe return
dispatcher:
movff POSTINC0, PCL
The other assumptions that I mentioned include that all
functions are on the same page (their addresses differ only in the low
8 bits) and that PCLATU and PCLATH have been set correctly for them
outside of this code. You could include bytes for them in the table,
and put two or three movff instructions at dispatcher instead of 1 to
load them before the final one writes PCL if you want to avoid this
restriction.
The big assumption that is unusual is that the table must
be located in RAM (gpfrs). If that's what you want, well and good.
But if you meant for the table to be in program space (ROM), then
you want to follow the MicroChip dispatch table examples (at least
they have them for mid and low range devices):
loop:
; If I understand correctly, the 181x has 2 byte addresses
; per instruction word, so we need to double count. (The
; 12 and 14 bit PICs only advance the PC by 1 per instruction
; word.) Doubled count must fit in the 8 bit W register.
clrc
rlf count, W
call function_table_dispatcher
decfsz count, F
bra loop
; All functions have been called
goto next_code ; or maybe return
function_table_dispatcher:
addwf PCL
nop ; Never called with 0
bra funcNminus1
bra funcNminus2
bra funcNminus3
...
bra func1
bra func0
In this case the functions themselves can be anywhere
that a bra can reach. The set of bra instructions in the table,
however, must all be in the same page (this, too, is fixable
if necessary). The table is accessed in reverse order in this
example.
Bill