; Jump/Call Examples for PIC16C5x ; Copyright (c) 1992, Parallax Inc. ; ; With the PIC16C54 & PIC16C55, a programmer need only worry about the ; problem of being able to call and/or indirectly jump (via W) to the lower ; 256 words of the 512 word program space. The PIC16C56 & PIC16C57 have ; larger program spaces (1K & 2K respectively) and thus require the program ; to deal with the tricky subject of paging. ; ; Each model of the PIC16C5x has either 1, 2, or 4 pages of program space. ; Each page is divide into 2 256 word segements. The lower 256 words may be ; called and jumped to freely from anywhere with the 512 word page. The ; upper 256 words of the page may only be jumped to directly. Unfortunately, ; any attempt to either call to and/or jump indirectly (via W) to the upper ; 256 words will be thwarted by the PIC which automatically clears bit 8 ; of the PC when such attempts are made. ; ; Jumping from one page to another requires the additional step of setting ; the PA1 and PA0 bits of the Status Word Register F3 (STATUS). Unlike ; other paging systems where changing a page bit automatically changes ; pages, PA1 and PA0 only have an effect when a JMP or CALL is made. This ; allows you to set the bits well in advance of a jump or a call. Parallax ; has made this even easier via the LCALL and LJUMP instructions. These ; automatically set PA1 and PA0 prior to the branch. This convenience, ; however, creates a common problem. PA1 and PA0 are not reset automatically ; on return. Thus, any future jump or call will also be directed to the ; page indicated by PA1 and PA0. This, however, can be remedied by the ; use of the LSET $ command (see the example below). ; ; It should be noted that although jumps and calls require manipulation ; of the PA1 and PA0 bits, returns do not. Whenever a calls is made, ; the entire return address is stored. PA1 and PA0 do not affect the ; return address. Similarly, the RETLW instruction does not affect the ; PA1 and PA0 bits. ; ; Below are some examples showing the more common problems programmers have ; dealing with the PICs unique code space. Note that this file does not ; assemble and is intended only for educational purposes. ; ;============================================================================= ; Example 1 : Long & Calling Jumping ; ; org 000h ; Page 0 - Callable Addresses page0_a ret ; Normal Return : Will Return to ; page 1 OK, but PA1 & PA0 will ; still be set for page 0 org 100h ; Page 0 - Non Callable Addresses page0_b ljump page1_b ; Jump is Long : PA1 & PA0 will be ; Correct at page1_b org 200h ; Page 1 - Callable Addresses loop lcall page0_a ; Long Call to Page 0 ; PA1 & PA0 still set for Page 0 ; Any Call or Jump Goes to Page 0 call page0_b ; Jump to Page 0 page1_b ; Takes Advantage of Previous LCALL ; LJUMP in Page 0 Set PA1&0 Here lcall page0_a ; Long Call to Page 0 Again ; Long call is necessary since ; page0_b set PA1&0 to Page 1 lset $ ; Set PA1&0 to Current Page ; PA1&0 must be set before local ; jump can be made jmp loop ; Repeat Process ;============================================================================= ; Example 2 : Table Indexing ; ; Tables of constant data are implemented in the PIC by using a combination ; of CALLs, RETLWs, and indirect jumps. Following is the simplest example ; of a table lookup. Since lookup is a CALL target and the RETWs are the ; targets of an indirect jump (JMP W+PC), the entire LOOKUP routine must ; reside in callable memory (i.e. the lower 256 words of any page). The ; example call could be anywhere within the 512 word page. Furthermore, ; the example call could be anywhere in memory provide an LCALL was used. org 000h ; LOOKUP : Return Wth Member of Data Table ; ; INPUT : ; W = Index into Table (Bit Number) ; OUTPUT : ; W = Table Entry (Bit Mask) lookup jmp PC+W retw 01h,02h,04h,08h retw 10h,20h,40h,80h ; Example Calls org 100h ; Same Page Call mov W,#03h ; W = Bit 3 call lookup ; W = Mask for Bit 3 org 300h ; Call from Other Page mov W,#04h ; W = Bit 4 lcall lookup ; W = Mask for Bit 4 lset $ ; Restore PA1|PA0 (See Example 1) ;============================================================================= ; Example 3 : Full Page Table Indexing ; ; Sometimes it is necessary to have a full 256 byte lookup table. This, ; however, seems impossible since at least one address must be called ; for table lookup, leaving only 255 words for lookup data. There are ; two solutions to such a problem. ; ; First solution is to hardwire one of the indexes. Both 0 and 0FFh are ; simple to test. A routine to do such indexing might be as follows. ; It uses a table lookup similar to, but larger than, that of example 2. iorlw 00h ; Test W for Zero btfss 3,1 ; If Zero, Handle Special goto zero call lookup ; If Non Zero, Do Lookup skip zero movlw 087h ; Special Value for Zero ; A second solution is available on the PIC16C56 & PIC16C57, where multiple ; pages are available. Here, the call target can be in one page while the ; RETLWs can be in another. This method is slighlty cleaner because all ; lookups have uniform speed and the calling method is almost indentical ; to the table constructed in example 2. Of course, the PA1 & PA0 bits ; must be restored after lookup since the indirect jump is long. org 000h ; Page 0 - Callable Addresses lookup lset table ; Set PA1&0 for Long Indirect Jump jmp W ; Jump into Table org 100h ; Page 0 - Non Callable Address ; Sample Call mov W,#000h ; W = Index Value (0..255) call lookup ; W = Data[Index] lset $ ; Restore PA1&0 org 200h ; Page 1 - Callable Address ; Entire Page is Data Table table retw 012h retw 024h ... ;============================================================================= ; Helpful Guidelines ; ; The PICs attractiveness comes at the price of some programming complexity. ; Most of this complexity has been placed on the use of the PA1&0 bits ; in the PIC16C56 & PIC16C57. Here are some guidelines for using the ; large code spaces : ; ; 1. Group routines logically so routines that have a lot of interplay ; (i.e. many calls & returns) reside in the same page. This obviously ; eliminates most LCALLs & LJUMPs, improving code size & speed. ; 2. Whenever possible, use the upper portion of each page for the main ; flow of the program, reserving the lower portion of each page code ; subroutines and data tables. ; 3. Be very careful using the SKIP group of instructions if you're using ; the Parallax instructions set. SKIP only skips one word, but a single ; Parallax instruction can generate several words. Using a skip prior ; to an LJUMP or LCALL can be particularly disasterous since you will ; skip the adjustment PA1 or PA0, but then execute the jump. ; NEVER SKIP BEFORE A LONG CALL OR JUMP!!! ; 4. For safety sake, it is good practice to always follow an LCALL with ; an LSET $. This will assure that PA1 & PA0 are set properly for ; any local jump. This is usually not necessary for LJUMPs and their ; targets, since to jump to a page the PA1 & PA0 bits must first ; be set properly. It is RETLW that allows alteration of the PC ; without using the PA1 & PA0 bits. ; Beware the Evil RETLW Instruction!!!! ; ; === END OF FILE ===