David VanHorn asks: > Can an 84 expert tell me, what the PCLATH is good for on the '84? > It seemed to get in my way a bit, and looking at it, it didn't seem > to perform a useful function. My assumption is that it's an "appendix" > left over from some other flavour of device that has more ram or > something. More program memory, not more RAM. PCLATH is used for two things: (1) GOTO and CALL only supply eleven bits of address information. If your PIC has more than 2K of program memory, the high-order bits of PCLATH are used to construct the complete destination address. You're correct that this function of PCLATH is not useful on the 16C84, since it has only 1K of program memory. (2) You can also change your location in the code by writing directly to PCL. PCL is only eight bits wide; the high-order bits of the destination address are supplied by PCLATH. Concrete examples: CLRF PCLATH MOVLW H'80' MOVWF PCL ; next instruction executed will be at address 0x080 MOVLW H'02' MOVWF PCLATH MOVLW H'05' MOVWF PCL ; next instruction executed will be at address 0x205 Since the 16C84 *does* have more than 256 bytes of program memory, this aspect of PCLATH is useful. You may ask why would anyone write the above code, when they can be replaced by "GOTO H'80'" and "GOTO H'205'"? Usually when you are writing to PCL, you are not writing a constant. If you want to jump to one of several locations based on the value of a register, and that value is inside a small range, the naive way to do it is: MOVLW 0 XORWF REG, W ; or SUBWF REG, W BTFSC STATUS, ZERO GOTO REG_EQUALS_0 MOVLW 1 XORWF REG, W BTFSC STATUS, ZERO GOTO REG_EQUALS_1 MOVLW 2 XORWF REG, W BTFSC STATUS, ZERO GOTO REG_EQUALS_2 This works, but it takes a lot of space. The next trick most PICers learn is that XOR has the nice property that a^b^(b^c) == a^(b^b)^c == a^0^c == a^c, so we can eliminate some of the constant loads: MOVLW 0 XORWF REG, W ; W = REG^0 BTFSC STATUS, ZERO GOTO REG_EQUALS_0 XORLW 0^1 ; W = REG^0^(0^1) = REG^1 BTFSC STATUS, ZERO GOTO REG_EQUALS_1 XORLW 1^2 ; W = REG^1^(1^2) = REG^2 BTFSC STATUS, ZERO GOTO REG_EQUALS_2 This is probably the right method to use if the values you're checking against have widely scattered values. But since the values we are interested in all happen to fall into a small range, we can use the PCL trick to shorten this even further: MOVF REG, W ADDWF PCL, F GOTO REG_EQUALS_0 GOTO REG_EQUALS_1 GOTO REG_EQUALS_2 If you never touch PCLATH, and put all of these "jump tables" in the first 256 bytes of memory, it works fine as-is. No messing around with PCLATH required. Otherwise, you have to make sure that PCLATH is properly set before you write to PCL: MOVLW ((($+3) & H'300') >> 8) ; high bits of ADDWF's PC MOVWF PCLATH MOVF REG, W ADDWF PCL, F GOTO REG_EQUALS_0 ; etc. You need to be careful with this method that your jump table doesn't cross a 256-byte boundary. If the code falls on: 0FD MOVF REG, W 0FE ADDWF PCL, F 0FF GOTO REG_EQUALS_0 100 GOTO REG_EQUALS_1 101 GOTO REG_EQUALS_2 Then if REG's contents are 2, the write to PCL will result in a jump to 001, rather than 101. Remember, PCL is just an eight-bit register, so FF+2 == 01. A few well-written macros can help out here. You also need to ensure that REG is in range -- if REG's contents are 3, you jump past the end of the jump table, and start executing who-knows-what code. If REG's contents are 0xFF, the "ADDWF" sends you right back to the same instruction, and you're in an infinite loop. Jump table lengths that are powers of two are easiest, you can replace the "MOVF REG, W" with "MOVLW (TABLESIZE-1); ANDWF REG, W". "Add to PCL" usually takes less code space than sequential compares, it usually executes faster (even with the overhead of setting up PCLATH), and it always executes in the same amount of time, an amount of time that is easy to calculate. Brian