Kmila
Todas las lecciones
Experto Proyecto ~120 min

Proyecto: CPU de 8 bits monociclo

Este es el capstone. Vas a ensamblar todo lo aprendido — una ROM, un registro, una ALU, una FSM-como-control — en una máquina pequeña que de verdad ejecuta programas.

La máquina

flowchart TD
    RST(["reset = 0000"]) -.-> PC["PC (4 bits)"]
    PC -- addr --> ROM["ROM<br/>16 × 8 bytes<br/>(precargada al sintetizar)"]
    ROM -- "instr (8 bits)" --> SPLIT{{"opcode = instr(7..4)<br/>imm4 = instr(3..0)"}}
    SPLIT --> DECEXE["decode / execute"]
    SPLIT --> PCNXT["lógica siguiente PC"]
    DECEXE --> R0["R0 (8 bits)"]
    PCNXT --> PCN["PC_next"]

Qué te da el andamiaje

Un CPU completo y funcional. Lee con atención:

process(clk, reset)
begin
  if reset = '1' then
    pc   <= (others => '0');
    r0   <= (others => '0');
    halt <= '0';
  elsif rising_edge(clk) then
    if halt = '0' then
      case instr(7 downto 4) is
        when "0000" => r0 <= resize(unsigned(instr(3 downto 0)), 8); pc <= pc + 1;
        when "0001" => r0 <= r0 + resize(unsigned(instr(3 downto 0)), 8); pc <= pc + 1;
        when "0010" => pc <= unsigned(instr(3 downto 0));
        when "1111" => halt <= '1';
        when others => pc <= pc + 1;
      end case;
    end if;
  end if;
end process;

Ya implementa:

  • LOAD (0000)
  • ADD (0001)
  • JUMP (0010)
  • HALT (1111)

La ROM preinicializada ejecuta R0 = 3; R0 += 4; R0 += 2; HALT.

Tu trabajo

Ejecútalo tal cual primero. Simula 200 µs con el reloj y reset incluidos. En la pestaña de formas de onda verás r0_out pasando por 3 → 7 → 9, y luego halted quedando en alto.

Cuando la base funcione, extiende la ISA:

Tarea 1: SUB

Opcode 0011. R0 <= R0 - imm4. Cambio de una línea.

Tarea 2: Jump condicional

Opcode 0100: JZ addr — salta a addr si R0 = 0, si no solo pc <= pc + 1.

Escribe un programa que cuente atrás desde un valor y salte cuando llegue a 0. Usa JZ como salida del bucle.

Tarea 3: Un segundo registro

Agrega r1 como segundo registro de 8 bits. Define LOAD R1, #i como opcode 0101 y ADD R0, R1 (sin inmediato) como opcode 0110. Tendrás que extender el case y agregar un puerto de salida para visibilidad.

Tarea 4: Memoria de datos externa

Conecta el módulo de RAM del track de Memorias a este CPU. Añade LOAD R0, [addr] y STORE R0, [addr]. Cuidado: un diseño monociclo requiere que el puerto de lectura tenga su salida válida en el mismo ciclo que emites la dirección — usa lectura combinacional para la ROM y lectura registrada para la RAM de datos, y planea el pipeline con cuidado.

Por qué hacer esto

Porque la primera vez que veas tu CPU avanzar por un programa que tú escribiste (en bytes que tú pusiste en una ROM), algo hace clic. Toda abstracción por encima — ensamblador, compilador, sistema operativo — se apoya en este mecanismo. Y cada una, hasta el navegador ejecutando el JavaScript que escribiste la semana pasada, es el mismo truco repetido a escala.

Más lejos

  • Implementa el pipeline clásico de cinco etapas sobre esta ISA. Agrega detección de hazards y una unidad de forwarding. Ya tienes una versión microescala de lo que enseñan los libros de RISC-V.
  • Cambia la ROM: en lugar de constantes, cárgala desde un archivo en simulación, y luego construye un ensamblador que convierta texto a bytes.
  • Conéctale el TX de UART del proyecto anterior y haz que el CPU imprima 'HI' en la forma de onda. Felicidades — tienes un SoC.
Ocurrió un error no controlado. Recargar 🗙