Hola.
Este tema se ha tratado varias veces en el foro y hay un tutorial de Leon_PIC en donde tratamos este tema.
El datasheet de tu micro lo dice en la sección 2.3:
All PIC16F87XA devices are capable of addressing a continuous 8K word block of program memory. The CALL and GOTO instructions provide only 11 bits of address to allow branching within any 2K program memory page. When doing a CALL or GOTO instruction, the upper 2 bits of the address are provided by PCLATH<4:3>. When doing a CALL or GOTO instruction, the user must ensure that the page select bits are programmed so that the desired program memory page is addressed. If a return from a CALL instruction (or interrupt) is executed, the entire 13-bit PC is popped off the stack. Therefore, manipulation of the PCLATH<4:3> bits is not required for the RETURN instructions (which POPs the address from the stack).
Cada página tiene un tamaño de 2048 (0x800) instrucciones. Si estás programando en BASIC, debería ser el compilador quien se encargue de generar el código correcto para que no tengas problemas.
Para que quede claro, GOTO k permite 11 bits para cargar la dirección destino. Los otros 2 bits restantes provienen de los bits PCLATH<4:3>. No tienen nada que ver los bits de selección de página del registro STATUS. No confundamos. El PCLATH está relacionado a la memoria de programa(FLASH), mientras que los bits STATUS<RP1:RP0> están relacionados a la memoria RAM.
La memoria de programa está paginada cada 2KWords (2048 instrucciones de programa).
La dirección final (13 bits) que se carga al hacer un CALL o GOTO provienen de:
los 2 bits de mayor peso provienen del valor actual de los bits PCLATH<4:3> y los 11 de menor peso se cargan desde la instrucción GOTO/CALL.
Y qué pasa con el RETURN/RETFIE/RETLW también tengo que tener respecial cuidado antes de retornar de una subrutina?NO. El STACK de estos micros es de 8 niveles y cada uno de 13 bits. Es decir que cuando haces un CALL, se guardan TODOS los 13 bits donde debe retornar el PC cuando se ejecute el RETURN/RETFIE/RETLW.
Ahora, en cuanto a la memoria RAM:
Está seccionada en BANCOS, cada uno de 0x80 registros (128 Bytes).
La posición de memoria sobre la cual se trabaja (9 bits) provienen de:
los 2 bits de mayor peso provienen de STATUS<RP1:RP0> y los 7 de menor peso se cargan desde el valor de la instrucción mísma.
Si por ejemplo, hago:
BCF STATUS,RP1
BSF STATUS,RP0
MOVF 0x20,W
estaré leyendo la dirección 0xA0 y copiando su valor a W.
La fórmula para calcular la dirección final de memoria a afectar es:
((RP1 * 2) + RP0) * 0x80 + dirección cargada en la instrucción.
En el ejemplo anterior sería entonces:
((0 * 2) + 1) * 0x80 + 0x20 = 0xA0
Eso es para direccionamiento DIRECTO.
Para direccionamiento indirecto, mediante los registros INDF y FSR:
Como el registro FSR es quien contiene la posición de memoria a leer/escribir indirectamente, y los registros del uC son de 8 bits, en este caso el FSR puede contener un valor entre 0 y 255 (un total de acceso de 256 bytes). Nuevamente estos micros poseen más de 256 bytes de RAM, por lo que aparece un registro de apoyo como bit de mayor peso ( bit 8 ) para poder direccionar entre los bancos de memoria. Dicho bit es el STATUS,IRP.
Entonces la posición de memoria a acceder indirectamente proviene de:
el bit de mayor peso proviene del valor del bit STATUS,IRP y los 8 bits de menor peso del valor de FSR.
Ejemplo:
bcf STATUS,IRP
movlw 0x20
movwf FSR
movf INDF,W
W contendrá el valor de la posición de memoria 0x20.
Ahora, si hiciese:
bsf STATUS,IRP
movlw 0x20
movwf FSR
movf INDF,W
W en este caso contendrá el valor de la posición de memoria 0x120.
Saludos!