>I using the parallax simulator for a PIC16C84 part, and cant get
>the simulation to do a jump to an indirect address. A jump to 0
>redirects program flow to instruction 0 rather than the address
>in FSR. Anyone have a similar problem or am I missing something
You're missing something simple. To do an indirect jump, you must load
the destination address into the Program Counter, not the FSR.
Try something like this:
.... ;COMPUTE THE DESTINATION ADDRESS, AND
.... ;STORE IT IN "ADDRHI" AND "ADDRLO".
MOVF ADDRHI,W ;GRAB THE HI-BYTE OF THE ADDRESS.
MOVWF PCLATH ;STORE IT.
MOVF ADDRLO,W ;GRAB THE LO-BYTE OF THE ADDRESS.
MOVWF PCL ;STORE IT. PROGRAM EXECUTION CONTINUES AT
;THE ADDRESS IN "ADDRHI:ADDRLO".
Actually, I needed to do an indirect jump so I could write a
vector interrupt table without wasting any extra RAM. I'm trying
Setup for particular interrupt routine:
Assign routine # 1..255
In Vector Interrupt Table
GOTO ADDR1 (addr of subroutine 1)
GOTO ADDR2 (addr of subroutine 2)
It's a bit of a nonconventional use of FSR, and FSR can't be used
between the assignment to a subroutine and the interrupt.
Also only one type of interrupt can be used at a time.
Notice also that the routine # must be <=250 or PCL will
overflow. Lastly, flags must be cleared and ,if needed, status
must be saved in the body of the subroutine. All that aside, it
does allow for changing interrupts on the fly and saves those 2
bytes of RAM.
Anyone else have a favorite way of doing an interrupt table that
can by modified on the fly?
>Actually, I needed to do an indirect jump so I could write a
>vector interrupt table without wasting any extra RAM. I'm trying
>Setup for particular interrupt routine:
>Assign routine # 1..255
>In Vector Interrupt Table
>GOTO ADDR1 (addr of subroutine 1)
>GOTO ADDR2 (addr of subroutine 2)
The concept is OK, but the implementation is flawed. First, when getting
the *data* from an indirect location in RAM, you need to use INDF (register
0), which is a 'shadow' of the location pointed to by FSR. The MOVF FSR is
going to just get the constant routine number you loaded into it at first,
FSR is the *address pointer* for indirect data, not the data itself.
Secondly, the ADDWF PCL without specifying ,0 or ,w is going to leave the
result in PCL, i.e. execute the jump immediately. Thus, the MOVWF PCL is
not executed (unless 0 is added, then it causes real trouble), and the
entries in the table are one location off.
There is really no need to use a table of GOTOs, since you can vector
directly to routines by setting the vectors in RAM to the addresses of the
routines themselves (unless the routines are in the high part of the code
pages, but since you said this is an interrupt routine, a 14-bit PIC can
handle this OK by setting PCLATH accordingly).
So the vector part of the routine could be rewritten as:
Now, suppose that valid routines are located at addresses 030, 060 and 090
in program space. Further, a table in RAM beginning at address 18 contains
the addresses, 30, 60, and 90. If rtn# above is set to 19, then the routine
at address 60 will be executed. First FSR will be loaded with 19, which
makes INDF a 'shadow' of the RAM byte containing 60. Then the 60 is loaded
and transferred to PC. Later this same code can be made to execute another
routine by storing the address of that routine in RAM location 19.
Remember, when doing computed jumps of this nature, be sure the page select
bits or PCLATH register (depending on PIC type) are setup correctly, as the
computed part of the address is only the low 8 bits.
Believe it or not, I am using FSR just as an extra byte of RAM,
not as it is normally used to indirectly address memory. That's
why I said my code was an unconventional use of FSR. Secondly, I
wrote my own assembler that has some different defaults...sorry
if the lack of arguments confused some people. It does produce
correct machine code with my software...I swear!
There are a couple of problems with your approach for my
application. (1) As you mentioned, vectoring directly to routines
instead of using a table is simpler but cannot access program
locations in high memory. I'm using the PIC16c84, so that means
almost 3/4 of the 1k program space cannot be accessed. As Andy
pointed out, and you implied, you can use an extra byte of RAM to
store access the PC through PLATH. As I said in my previous
post, I can't afford to lose two bytes of RAM and therefore need
the table of goto statements.
(2)So it would follow that your idea of a table in RAM would not
work for me, even more so if it had to store two bytes for every
So I hope my use of FSR is clear here. I'm using it as a
temporary storage location for a routine # to be jumped to on
interrupt. The main interrupt routine uses the value to jump to a
table of goto statements in program memory. If you have plently
of RAM but program memory is at a premium, it might be wise to
used 2 bytes of ram as temp locations for the routine address.
Otherwise, a table of goto's can save those 2 bytes.