>
> > From: NEIL GANDLER <
.....V064MB9KKILLspam
.....UBVMS.CC.BUFFALO.EDU>
> >
> > I am having a problem with a 16c74 program. The program
> > length has now exceeded 2K in program length, so now I must
> > manipulate the PCLATH register when performing long calls.
> > The problem occurs after I place a long call and then try to
> > return back to page0 using the RETURN command. My program
> > locks up and goes nuts. Subroutines that are executed within
> > page1 work fine. The PIC manual does not explain the Long
> > Call procedure very well. They mention one sentence about
> > saving the PCLATH register during interrupts, but I have no
> > clue how this would help or how to do it. I do know that
> > interrupts are the cause of my problem. Can anyone offer and
> > advice? Thanks.
>
> I encountered this problem recently. One possible solution is to
> code up a macro to perform calls from <2K to >=2K boundary. I
> call this 'hicall'. Mercifully, only one bit of PCLATH needs to
> be manipulated. hicall:
>
> . disables interrupts
> . sets bit 3 of PCLATH
> . calls the nominated routine in the upper block
> . clears bit 3 of PCLATH
> . enables interrupts.
>
> Why do I disable interrupts? Well, if you don't, then your interrupt
> service routine must save and restore PCLATH. Since this requires
> about 5 cycles and an extra register I chose not to do it since every
> cycle counts in an interrupt handler. (However, if your int handler
> does not perform any calls or gotos then you can skip the save).
>
> The down side of this simple scheme is that all routines in the upper
> block must run disabled for interrupts. If the high routines need to
> call low routines, another macro (lowcall) should be coded. Such nested
> (low) routines may re-enable interrupts, but must disable interrupts
> before returning to the high caller.
>
> I found this division of code into a low (interruptable) and high
> (disabled) sections was quite satisfactory. As a bonus, the high
> routines can use as scratch registers the registers normally used by
> the interrupt handler for saving W and status.
>
> One trick that will allow the fastest possible int handler without
> the necessity of disabling the high routines or saving PCLATH is:
>
> . Code the entire int handler as a macro. It must not make
> any calls or jumps outside of itself. All labels should
> be LOCAL.
> . Expand the macro at ORG 4h and also at ORG 804h
>
> Although wasteful of code space, the interrupt routine will now be
> insensitive to the state of PCLATH.
>
> I have noticed that most of my code only modifies PCLATH to ensure that
> it is correct for computed gotos/table lookups, and also for calling over
> 2K boundaries. For a memory map which looks like the following:
>
> 0000 - Jump to hard reset routine
> 0004 - Interrupt service
> 00xx thru 06FF - Main code low block
> 0700 thru 07FF - Table lookups/computed gotos
> 0804 - Duplicate of interrupt service (optional)
> 08xx thru 0EFF - Main code high routines
> 0F00 thru 0FFF - High table lookups/computed gotos
>
> then PCLATH is manipulated in the following way:
>
> . On reset, it is initialised to 07h. This primes it for
> table lookups since all these are at 700-7FF (or F00-FFF).
> . BSF/BCF PCLATH,3 is used to switch pages prior to a cross-
> block call or goto.
>
> This minimises mucking around with this problematic register. Your
> table lookups/computed gotos can now assume that PCLATH is correct,
> thus opening up the possibility of using W directly as a parameter
> rather than the old-fashioned way of saving the lookup parameter in
> a register.
>
> As an aside, what does one do with the three 'wasted' instructions
> at locations 1, 2 and 3? Well, I use these to contain code identifier,
> version and release codes (stored as RETLWs). This has the advantage
> that any old PIC (programmed by me) can be read by the programmer to
> determine what was last programmed. Can be useful, since one '84 looks
> awfully similar to another from the outside.
>
> Regards,
> SJH
> Canberra, Australia