Contador de programa explicado: el marcador de la CPU
Cómo un contador de programa identifica la siguiente instrucción, avanza por código secuencial y es redirigido por bifurcaciones, saltos, excepciones y reset.
En resumen: El contador de programa (PC), también llamado puntero de instrucción en algunas arquitecturas, identifica la siguiente instrucción que se debe buscar. La ejecución secuencial lo avanza según la longitud decodificada de la instrucción; las bifurcaciones, los saltos, las excepciones, las interrupciones y el reset seleccionan otro valor para el siguiente PC.
El contador de programa es un elemento de estado arquitectónico de propósito especial situado en el centro de la búsqueda de instrucciones. En una CPU didáctica puede ser un registro literal que controla una dirección de memoria de instrucciones. En un procesador moderno, la predicción, las colas, las cachés, la traducción de direcciones y la búsqueda especulativa hacen que la implementación esté más distribuida, pero la arquitectura sigue definiendo una dirección de la siguiente instrucción.
Esta publicación explica qué almacena el PC, cómo se incrementa, cómo las bifurcaciones y los saltos lo redirigen, y cómo cablear uno a partir de un registro, un sumador y un multiplexor. Cada componente enlaza con un circuito funcional que puedes explorar en la plantilla Ejecutor secuencial de instrucciones.
¿Qué es el contador de programa?
El contador de programa es un registro dedicado a una tarea: apuntar a la siguiente instrucción en memoria. No es un registro de propósito general que el código de usuario lea y escriba libremente. Es un registro de propósito especial controlado por la lógica de control de la CPU.
En la máquina más simple, su anchura y la unidad direccionable de la memoria limitan el espacio de direcciones de código:
- Un PC de 8 bits puede seleccionar ubicaciones direccionables.
- Un PC de 16 bits puede seleccionar ubicaciones.
- Un PC de 32 bits tiene patrones de bits posibles.
- Un PC de 64 bits tiene patrones de bits posibles.
Esas ubicaciones son bytes solo en una arquitectura direccionada por bytes. Los procesadores reales pueden implementar menos bits de dirección que la anchura nominal del registro, traducir direcciones virtuales de instrucciones a memoria física e imponer reglas de alineación o de direcciones canónicas.
El componente PROGRAM_COUNTER_8BIT de DigiSim implementa el caso de 8 bits, suficientemente grande para ejecutar programas reales en el simulador y a la vez lo bastante pequeño para inspeccionarlo bit a bit.
El PC está al inicio de la etapa de búsqueda
La etapa de búsqueda del ciclo búsqueda-decodificación-ejecución lee cuatro señales en secuencia:
- El PC coloca su valor actual en el bus de direcciones.
- La memoria devuelve la palabra de instrucción en esa dirección.
- La palabra de instrucción se retiene en el registro de instrucciones.
- El PC se actualiza para que la siguiente búsqueda lea la siguiente instrucción.
Los pasos 1–3 se tratan en la cobertura más amplia de búsqueda. El paso 4 es el tema de esta publicación.
¿Por qué debe incrementarse el PC automáticamente?
Si el PC permaneciera quieto, la CPU buscaría la misma instrucción para siempre. Por eso, el hardware cablea un incremento automático en el PC, de modo que, de forma predeterminada, cada ciclo de búsqueda va seguido de un paso hacia adelante.
El incremento se calcula mediante un sumador dedicado —normalmente un pequeño sumador de acarreo en cascada como el detallado en Dominar la suma binaria— cuyas entradas son el PC actual y un desplazamiento constante. La salida de ese sumador vuelve a la entrada de datos del PC, y el PC la retiene en el siguiente flanco de reloj.
PC + 1 frente a PC + 4: por qué importa la anchura de instrucción
La constante sumada al PC es la anchura de una instrucción en unidades direccionables, no siempre el valor literal 1.
| Arquitectura | Anchura de instrucción | Incremento | Motivo |
|---|---|---|---|
| CPU didáctica DigiSim de 8 bits | 1 byte (1 palabra) | PC + 1 | Cada dirección contiene una instrucción completa |
| MIPS; RISC-V sin instrucciones comprimidas | 4 bytes | PC + 4 | La memoria se direcciona por bytes; estas codificaciones ocupan 4 bytes |
| ARM (A32) | 4 bytes | PC + 4 | El mismo motivo |
| RISC-V con extensión C; Arm Thumb/Thumb-2 | 2 o 4 bytes | PC + longitud decodificada | Ambos incluyen codificaciones de 16 bits; también pueden aparecer codificaciones de 32 bits |
| x86 | 1–15 bytes | PC + (longitud decodificada) | Instrucciones de longitud variable; el decodificador informa la longitud |
El principio arquitectónico es el mismo: la dirección secuencial siguiente sigue la codificación de la instrucción actual. Una ISA de ancho fijo puede usar un incremento constante. Una ISA de longitud variable debe determinar la longitud de la instrucción actual, incluso si un front end de alto rendimiento predice y busca más allá de ese límite antes de que termine la decodificación.
Descripción booleana
Para una arquitectura con anchura de instrucción fija , el valor predeterminado para el siguiente PC es:
En el caso DigiSim de 8 bits, , por lo que el incremento es simplemente un sumador +1.
¿Cómo anulan las bifurcaciones y los saltos el PC?
La ejecución secuencial es el caso aburrido. Los programas reales necesitan bucles, condicionales, llamadas a funciones y retornos, todo lo cual exige que el PC salte a algún lugar distinto de la siguiente dirección secuencial.
Dos clases comunes de transferencia de control ilustran el cambio:
- Salto (incondicional): sustituye el PC por una dirección objetivo sin importar ninguna condición.
- Bifurcación (condicional): selecciona un objetivo solo si la condición definida por la ISA es verdadera; de lo contrario selecciona la dirección secuencial. Algunas ISA prueban indicadores de estado como cero, acarreo, signo o desbordamiento. Otras, incluida RISC-V base, comparan registros directamente y no tienen registro de códigos de condición aritméticos. La guía de flags de CPU explica el diseño basado en flags.
Ambas operaciones se reducen a escribir un valor no secuencial en el PC.
¿De dónde procede la dirección objetivo?
El objetivo se codifica de una de estas tres formas:
- Inmediato (relativo al PC): la palabra de instrucción contiene un desplazamiento. El siguiente PC es
PC + offset. RISC-VBEQ, ARMBy los saltos cortos x86 usan esta forma. La ventaja es el código independiente de la posición. - Directo o relativo a región: la instrucción aporta bits de objetivo que pueden combinarse con una base fija o bits altos del PC actual. El clásico MIPS
Jes un ejemplo conocido. Una dirección absoluta completa rara vez cabe en una instrucción normal de ancho fijo. - Indirecto por registro: el objetivo reside en un registro de propósito general o en la salida de la ALU. RISC-V
JALR, ARMBXy x86JMP raxson ejemplos. Esta forma admite punteros a función, despacho virtual ygotocalculado.
En una ruta de datos pequeña de un solo ciclo, esos candidatos pueden alimentar un multiplexor. Las implementaciones más avanzadas pueden calcular, predecir y encolar objetivos en varias unidades antes de que la ruta arquitectónica elegida se retire.
Implementación: registro + incremento + mux
La estructura de hardware del PC es una de las rutas de datos más limpias de una CPU:
┌──────────────┐
PC current ─────▶│ Adder (+W) │──── PC + W ──┐
└──────────────┘ │
▼
┌───────────────┐
│ MUX (2:1) │
target_addr ─────────────────▶│ sel = take? │──── next_PC
└───────────────┘
│
▼
┌───────────────┐
clock ─────────────────────▶│ PC register │──── current_PC
└───────────────┘
Tres piezas:
- Un registro para guardar la dirección actual. En la ruta de datos didáctica, es un registro de 8 bits, construido con almacenamiento disparado por flanco y ensanchado para coincidir con el bus de direcciones.
- Un sumador cableado con una entrada como PC y la otra como la anchura constante .
- Un multiplexor 2:1 con una entrada procedente del sumador (ruta secuencial predeterminada) y otra del objetivo de bifurcación (ruta de bifurcación tomada). La línea de selección la controla la unidad de control y se activa cuando la instrucción actual es un salto o una bifurcación cuya condición se evalúa como verdadera. Los multiplexores son el tema de El controlador del tráfico de datos.
En cada flanco de reloj, el PC retiene lo que el mux esté seleccionando en ese momento. Ese único almacenamiento es todo el mecanismo que distingue «avanzar» de «bifurcarse».
Entradas opcionales al mux
Los diseños reales añaden más fuentes al mismo mux:
| Fuente | Cuándo se selecciona |
|---|---|
| PC + W | Predeterminado — ejecución secuencial |
| PC + offset (relativo al PC) | Bifurcaciones condicionales, saltos cortos |
| Objetivo directo / vector | Saltos directos, reset o transferencias de control definidas por la arquitectura |
| Registro / salida de ALU | Saltos indirectos, retornos de función, despacho de switch |
| Vector de reset / arranque | Tras el encendido o reset externo |
| Vector de excepción / interrupción | Tras una trampa |
La línea de selección se ensancha de 1 bit a 3 bits, pero la idea estructural no cambia.
Comportamiento de reset: ¿dónde empieza el PC?
Cuando la CPU se enciende o se reinicia, el PC debe contener una dirección conocida; de lo contrario, la ejecución comienza al azar.
Hay dos convenciones comunes:
- PC = 0: la ejecución comienza en la dirección
0x0000…0. La CPU didáctica DigiSim usa esta convención simple, con la primera instrucción en la ubicación cero. - Vector de arranque: una dirección fija distinta de cero. x86 se reinicia en frío en la dirección física
0xFFFFFFF0(la parte superior del espacio de 4 GB, cerca de la ROM BIOS). Los núcleos ARM Cortex-M leen el PC inicial de un vector de reset almacenado en la dirección0x00000004. Algunos chips de la familia 6502 leen el vector de reset de0xFFFC/0xFFFD.
En hardware, «reset» es un cable hacia la entrada de borrado asíncrono (o carga síncrona) del PC. Cuando se activa, el PC se fuerza al valor de arranque independientemente del mux.
Ejemplo resuelto: un bucle de cinco instrucciones
Considera el siguiente seudoprograma en una CPU de 8 bits con :
0x00: LDI R0, 5 ; load 5 into R0
0x01: LDI R1, 0 ; load 0 into R1
0x02: ADD R1, R0 ; R1 = R1 + R0
0x03: DEC R0 ; R0 = R0 - 1, sets Z flag if R0 hits 0
0x04: BNZ 0x02 ; if Z == 0, branch back to 0x02
0x05: HLT
Recorramos los valores del PC:
| Ciclo | PC en búsqueda | Instrucción | Tras la búsqueda | ¿Bifurcación tomada? | Siguiente PC |
|---|---|---|---|---|---|
| 1 | 0x00 | LDI R0, 5 | PC + 1 = 0x01 | no aplica | 0x01 |
| 2 | 0x01 | LDI R1, 0 | PC + 1 = 0x02 | no aplica | 0x02 |
| 3 | 0x02 | ADD R1, R0 | PC + 1 = 0x03 | no aplica | 0x03 |
| 4 | 0x03 | DEC R0 (R0=4, Z=0) | PC + 1 = 0x04 | no aplica | 0x04 |
| 5 | 0x04 | BNZ 0x02 | PC + 1 = 0x05; target = 0x02 | sí (Z=0) | 0x02 |
| 6 | 0x02 | ADD R1, R0 | … | … | … |
En el ciclo 5, la ruta de datos didáctica selecciona el objetivo de bifurcación (0x02) en lugar de la siguiente dirección secuencial (0x05) porque el flag Z está borrado. La maquinaria de flujo de control real es más elaborada, pero el resultado arquitectónico sigue siendo una elección entre la ruta de continuación y un objetivo de transferencia de control.
Errores habituales
- Error de una unidad en PC + W. Un error común de simulador es usar
PC + 1para una arquitectura cuyas instrucciones tienen 4 bytes de ancho. La CPU buscará el segundo byte de cada instrucción como inicio de la siguiente y se comportará como si cada programa fuese datos aleatorios. - Actualizar el PC antes de que la búsqueda lea la memoria. El PC debe mantener la dirección actual mientras se lee la memoria. Actualízalo en el flanco de reloj, no combinacionalmente.
- Olvidar el reset. Un PC sin cable de reset arranca con cualquier valor al que los biestables se aleatoricen al encenderse. Conecta siempre el reset.
- Bifurcar a una alineación no válida. La alineación requerida de instrucciones depende de la ISA y de la extensión. Una máquina con solo instrucciones alineadas de 32 bits rechaza un objetivo como
0x1003; una ISA con codificaciones de 16 bits puede permitir más objetivos. Aplica la regla de la arquitectura en lugar de cablear una suposición universal.
Construirlo en DigiSim
Abre la plantilla Ejecutor secuencial de instrucciones. Verás:
- Un bloque
PROGRAM_COUNTER_8BITen la parte superior de la ruta de búsqueda. - Un sumador cableado para añadir
1en cada ciclo de reloj. - Un mux que selecciona entre
PC + 1y una dirección objetivo impulsada por la unidad de control. - Un interruptor de reset que fuerza el PC a
0x00.
Avanza el reloj manualmente y observa cómo el PC progresa. Después carga un programa que contenga una instrucción de bifurcación y observa el momento en que el mux cambia de «secuencial» a «objetivo»: ese único bit es el flujo de control en su forma más pura.
Dónde se sitúa el PC en el panorama general
El contador de programa es un nodo dentro del flujo de datos mayor de la CPU. La instrucción que identifica se captura para el procesamiento de registro de instrucciones y decodificación. Los resultados aritméticos pueden actualizar los flags de CPU que consulta un diseño de bifurcación basado en flags.
Lee el caso de estudio de búsqueda-decodificación-ejecución para ver el bucle completo, carga después la plantilla Ejecutor secuencial de instrucciones y avanza una instrucción de bifurcación paso a paso. Ver al PC saltar de manera no secuencial por primera vez es el momento en que la abstracción deja de ser un diagrama y se convierte en un circuito.



