> >[1] On the 16Cxx chips, PCLATH is never modified except under program > > control. On reset, its value is undefined and you should make no > > assumptions about it. > > The PIC does reset the PCLATH register to 0 on a reset. But the > important point is that it never automatically changes (except on reset). > It is good practice though to not make any assumptions about reset other > than maybe the program will start at 0. If time allows, the program will > be more reliable setting PCLATH to the required value before each use. I always do a "clrf PCLATH" in any software that uses PCLATH at all (i.e. that runs on a larger-than-2K part, or that uses any table lookups or computed gotos). Unless I use large tables, I almost invariably simply put all of the computed gotos within the first page. > On the other hand, the PCL special function register always indicates the > low 8 bits of the next instruction to be executed. If the program > changes PCL, the PIC will (a) discard the prefetched next instruction, > causing the PCL change to take 2 cycles (b) set the program counter to > PCLATH:PCL and execute the instruction there. The assembler functions > "high" and "low" are useful to find the address of an instruction in > terms of the low 8 bits and the high bits. Actually, I usually hand place my tables in whatever page they belong; there is almost never IMHO any reason to split tables across page boundaries. For this reason, I never simply use the "low-byte" directive. In those rare occasions where I do need the address within a page, I subtract the base of the page from the address. This ensures that if things go off the end of the page the assembler will choke instead of producing bogus code. > The conventional method of reading a table of 256 or fewer entries: > > ... > movfw index ;Lookup table[index] > call gettbl ;Get table value into W > ... > > gettbl addwf PCL,f ;Index in W - vector to > one of the entries > table > retlw 5 ;table[0] > retlw 8 ;table[1] > retlw 2 ;table[2] > > only works if PCLATH is set properly. In order to be sure the program > works, set up PCLATH before going to the table: If all tables fit within a page, this becomes a non-issue. If they can all fit within two pages, just use BSF or BCF on PCLATH to set the page pointer. > But there is an additional problem, if the table crosses a 256-byte > boundary, then 2 different PCLATH values are needed to access it. I > strongly recommend using "org" directives to place tables at known > locations so this is certain not to happen. Don't run tables across page boundaries unless you have a good reason; it's easy enough to avoid, but allowing for it makes code bigger and slower. > If the table is exactly 256 locations, the addwf PCL needs to be placed > at xxFF so the add will never generate a carry (because the entire table > is in the same 256 byte "page"). However since it is known that W will > always be added to 0 then, a movwf PCL can be used with the same effect. For tables of exactly 256 bytes, there's no reason to prefer an "addwf" at the end of a page to a "movwf" located elsewhere. Much easier just to have a "movwf" somewhere within the same 2K part of the program as the table itself with a label, e.g., "springboard". Then the page-select bits can simply be set as needed before the call and everything will work nicely (6 cycle table lookup). > If you insist on placing tables anywhere, you'll have to compute and load > the proper PCLATH value at run-time. Here's an example of that: Certainly possible, but it takes 12 cycles to do a table lookup instead of six. If the "call" is replaced with a "goto" (in which case the table lookup routine should be called from the main program) that may save a couple cycles, but with proper arrangement of tables in memory such things should very seldom be needed. > >[2] On a reset, the PIC jumps to address 0 independent of PCLATH. > > PCLATH. > > > >[3] On an interrupt, the PIC jumps to address 4 independent of PCLATH. > > On a part with more than 2K program space in use, you have to be wary of > using goto or call instructions in an ISR since PCLATH may have been set > to go to a different 2K page. Probably the fastest way around this is to > place identical copies of parts of the ISR in the same place in all > pages. Or save and restore PCLATH in RAM before any gotos in an ISR. If > the ISR needs to use a table, and PCLATH is not constant throughout the > entire program, then PCLATH will need to be saved of course before > changing it in the ISR. Thanks for the reminder. The trick of cloning the ISR is a good one of course, though it's not nearly as convenient with current assemblers as one might like. > >Hopefully that will clarify things somewhat. I should warn you, > >though: > >the 17Cxx has very different rules for handling PCLATH, so code > >migration > >to that part is not so simple as it would seem. If you stick with > >16Cxx, > >though, you should do fine. > > And of course the 12-bit parts are also entirely different, having no > PCLATH register at all. The only 12-bit parts of any consequence now are > the 8-pin PIC12C50X. Actually, for high volume production the 16C5x is still the part of choice, at least in the mask-rom version. But for low-volume applications, the cost savings from the '5x are too small to worry about.