> 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.

Neil,

When you are running on page 0 and calling a routine on page 1, you set
PCLATH to point to page 1, after returning from page 1, PCLATH is still
pointing into page 1, but, you are running in Page 0, so, for each next
call or goto command, the PIC will try to jump to a location in Page 1.

So, when you use PCLATH, you need to update it before any call that either
jump to another page or jump to a location within the same page but after
returning from the other page.

> On Sat, 26 Oct 1996, NEIL GANDLER wrote:
>
> > 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.
>
> Neil,
>
> When you are running on page 0 and calling a routine on page 1, you set
> PCLATH to point to page 1, after returning from page 1, PCLATH is still
> pointing into page 1, but, you are running in Page 0, so, for each next
> call or goto command, the PIC will try to jump to a location in Page 1.
>
> So, when you use PCLATH, you need to update it before any call that either
> jump to another page or jump to a location within the same page but after
> returning from the other page.
>
> chaipi
>

Thanks for the advice, Do I need to store and restore PCLATH before and
after interrupts?

> From: NEIL GANDLER <spam_OUTV064MB9KTakeThisOuTUBVMS.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:

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:

. 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.

<< 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. >>

If, for instance, your interrupt service routine modifies PCLATH - perhaps
because it uses a page 1 subroutine - then PCLATH remains modified even after
you interrupt return, which may be to page 0.
So...in the same way that you store W and STATUS in temporary locations
when you start your interrupt service routine, store PCLATH also. At the end
of your service routine, just before restoring W and STATUS and doing your
RETFIE, also restore PCLATH.

NEIL GANDLER wrote:
>
> 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.
>
> Neil Gandler

If you're not sure where the heck you are in the pages, you can do this
after a "return"

My_label
movlw ((Mylabel>>8)&&0xFF)
movwf PCLATH

Not very efficient in ROM terms, but effective in where-the-heck-am-i
terms.
--
Friendly Regards

sounds like you understand how addresses are derived by combining
PCLATH and PCL... but don't forget that PCLATH isn't automatically
maintained by the PIC: when you manipulate PCLATH for the long
call into page1, the return will work fine as the full return
address is pushed onto the stack (and hence the correct address
can be returned to) - PCLATH, however, was *written to* by the long
call procedure but *not restored* by the return - further call (or goto)
instructions will still use the long-call-modified PCLATH and
hence still work like a long call - you need to restore PCLATH
yourself after the return.

In your ISR, it's a pretty safe bet that you'll need to perform
some local gotos, so you need to ensure that PCLATH is
configured for this.
When saving the context in your ISR, save PCLATH as well and make
sure that PCLATH is then loaded with a value that will jump into
the correct page during your ISR. Restore PCLATH when you restore
context and RETFIE, and it should be ok.

There's a good explanation of this (answer #36) on Andy Warren's
answers page, plus some example code. Good onya, Andy!

At 3:28 PM 10/26/96, NEIL GANDLER wrote:
> 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.
>
> Neil Gandler

I had the exact same problem! make sure you have the correct probe selected.

>
> > 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

A simple solution is to use a MPASM address for a label. Right shift it
8 times, and load it into PCLATH. You can even make a macro out of it :