PIC Microcontroller Memory Method

Table lookups

Mike Keitz says:

...There are two situations where "paging" of the program memory is an issue. For CALL or GOTO, the pages are 800h instructions long [on the more advanced PIC processors]. Most short programs don't need to be concerned with them. [HOWEVER] For writing to PCL, the pages are only 100h instructions long. So [any] 256-value table definitely crosses one of those pages. And the program will crash when the index into the table gets large enough if your table-access code doesn't set up PCLATH properly.

[Here is some code that sets up PCLATH correctly]

   movlw  high   (TABLE_START)
   movwf  pclath
   movf   index,w
   addlw  TABLE_START
   skpnc
    incf  pclath,f
   movwf  pcl
TABLE_START
   retlw  ...

If the table is called such that W is the index:

   addlw  TABLE_START
   movwf  temp
   rlf    known_zero,w
   addlw  high(TABLE_START)
   movwf  pclath
   movf   temp,w
   movwf  pcl
TABLE_START
   retlw ...

Andrew Warren of Fast Forward Engineering - San Diego, California https://geocities.restorativland.org/SiliconValley/2499/ says:

...write table-lookup code [with] automatic page-crossing checks built in.

I generally do it like this:

        ADDWF   PCL

    TABLE1:

        DT      "Test"

        IF ((HIGH ($)) != (HIGH (TABLE1)))
            ERROR "TABLE1 CROSSES PAGE BOUNDARY!"
        ENDIF

P.S. By the way, another common way that a newly-inserted CALL can screw up previously-working code is if the called routine changes the PCLATH register... Or if your previously-working code expected the W register or STATUS flags to remain unchanged across the portion of the program where you inserted your CALL.

Rich Leggitt says:

...something like this should work for arbitrary table of any length located anywhere in the program space.
                ...
                movlw high string       ; point to a string
                movwf look_hi           ; in reality, a macro...
                movlw low string
                movwf look_lo
                call process            ; go process it
                ...

; subroutine to process string at look_hi/look_lo
process         call lookup             ; get a byte (this is the magic)

                ; here, do something with byte in W
                ; also, return if end of string
                ; otherwise...

                goto process            ; do it again

; Jump to address in look_hi/look_lo, which presumably is an RETLW.
; Note pointer post increment.
; Equivalent to: W=*look_ptr++
lookup          movf look_hi,w          ; set PCLATH
                movwf PCLATH
                movf look_lo,w          ; and get PCL
                incf look_lo,f          ; but post inc
                skpnz
                incf look_hi,f
                movwf PCL               ; ok, now jump


See Also:

Interested: