; 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	W+PC
		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 ===
