College Online
0%

Unidade de Controle

Módulo 4 · Aula 3 ~18 min de leitura Nível: Intermediário

Vídeo da aula estará disponível em breve

O Papel da Unidade de Controle

Na aula 4.1, construímos o caminho de dados — os componentes que processam dados. Na aula 4.2, vimos o pipeline e seus hazards. Agora vamos entender o cérebro do processador: a unidade de controle, que diz a cada componente do datapath o que fazer a cada instrução.

A unidade de controle recebe o opcode (e, para instruções R-type, o campo funct) e gera os sinais de controle que configuram MUXes, habilitam escritas e selecionam a operação da ULA. Sem ela, o datapath seria apenas um monte de fios sem direção.

i
Controle Hardwired vs Microprogramado No controle hardwired, os sinais de controle são gerados por lógica combinacional (portas AND/OR/NOT) diretamente a partir do opcode. É rápido, mas difícil de modificar. No controle microprogramado, os sinais são armazenados em uma ROM (memória de microprograma) e lidos como uma "micro-instrução". É mais flexível (basta reprogramar a ROM), mas mais lento. O MIPS usa controle hardwired; o x86 historicamente usa microprogramação para instruções complexas (CISC).

Sinais de Controle

Cada sinal de controle habilita ou seleciona um comportamento específico no datapath. Aqui estão os 8 sinais principais do MIPS monociclo:

Sinais de Controle do MIPS
Sinal        Bits  Função
───────────  ────  ──────────────────────────────────────────────────
RegDst        1    Seleciona registrador de destino
                   0 → rt (bits [20:16]) — para lw, addi
                   1 → rd (bits [15:11]) — para R-type

ALUSrc        1    Seleciona segundo operando da ULA
                   0 → Read Data 2 (registrador) — R-type, beq
                   1 → Imediato estendido — lw, sw, addi

MemtoReg      1    Seleciona dado a escrever no registrador
                   0 → Resultado da ULA — R-type, addi
                   1 → Dado lido da memória — lw

RegWrite      1    Habilita escrita no banco de registradores
                   1 → R-type, lw, addi
                   0 → sw, beq (não escrevem em registrador)

MemRead       1    Habilita leitura da memória de dados
                   1 → lw
                   0 → todas as outras

MemWrite      1    Habilita escrita na memória de dados
                   1 → sw
                   0 → todas as outras

Branch        1    Indica instrução de branch
                   1 → beq (PCSrc = Branch AND Zero)
                   0 → todas as outras

ALUOp         2    Indica categoria de operação da ULA
                   00 → ADD (lw, sw: calcula endereço)
                   01 → SUB (beq: compara registradores)
                   10 → Depende do campo funct (R-type)

Tabela de Controle Principal

A tabela abaixo é a verdade (truth table) da unidade de controle. Dado o opcode, ela define todos os sinais de controle:

Tabela de Controle — por Instrução
Instrução  Opcode   RegDst ALUSrc MemtoReg RegWrite MemRead MemWrite Branch ALUOp
─────────  ───────  ────── ────── ──────── ──────── ─────── ──────── ────── ─────
R-type     000000     1      0       0        1        0       0       0     10
lw         100011     0      1       1        1        1       0       0     00
sw         101011     X      1       X        0        0       1       0     00
beq        000100     X      0       X        0        0       0       1     01
addi       001000     0      1       0        1        0       0       0     00

X = don't care (valor não importa porque o resultado não é usado)

Exemplo: lw $t0, 8($s1)
  RegDst=0:    destino é rt ($t0), não rd
  ALUSrc=1:    segundo operando da ULA é o imediato (8)
  MemtoReg=1:  dado escrito vem da memória, não da ULA
  RegWrite=1:  habilita escrita em $t0
  MemRead=1:   habilita leitura da memória
  MemWrite=0:  não escreve na memória
  Branch=0:    não é branch
  ALUOp=00:    ULA faz ADD ($s1 + 8 = endereço)

Controle da ULA (ALU Control)

O sinal ALUOp de 2 bits não é suficiente para especificar todas as operações da ULA. Para instruções R-type (ALUOp=10), a operação exata vem do campo funct da instrução. Um segundo nível de decodificação combina ALUOp + funct para gerar o sinal de controle da ULA:

Tabela — ALU Control
ALUOp  Funct (bits 5:0)  Operação ULA  ALU Control (4 bits)
─────  ─────────────────  ────────────  ────────────────────
  00   XXXXXX             ADD           0010
  01   XXXXXX             SUB           0110
  10   100000 (add)       ADD           0010
  10   100010 (sub)       SUB           0110
  10   100100 (and)       AND           0000
  10   100101 (or)        OR            0001
  10   101010 (slt)       SLT           0111

Fluxo de decodificação:
  Opcode → Controle Principal → ALUOp (2 bits)
  ALUOp + Funct → ALU Control → operação exata da ULA (4 bits)

Dois níveis de decodificação:
  1. Controle principal: opcode → sinais gerais + ALUOp
  2. ALU control: ALUOp + funct → operação específica da ULA

Isso simplifica o controle principal (só precisa distinguir
3 categorias: ADD, SUB, R-type) e delega o detalhe para
o ALU control (que só olha o funct quando necessário).

Controle no Pipeline

No processador com pipeline, os sinais de controle são gerados no estágio ID e precisam ser propagados pelos registradores de pipeline até o estágio que os utiliza:

Diagrama — Sinais de Controle no Pipeline
Estágio:     IF       ID           EX            MEM          WB
            ────     ────         ────          ────         ────
                   Controle    ┌─ ALUSrc     ┌─ Branch    ┌─ MemtoReg
                   Principal   ├─ ALUOp      ├─ MemRead   └─ RegWrite
                   gera        └─ RegDst     └─ MemWrite
                   TODOS
                   os sinais

Registradores de pipeline transportam sinais:
  IF/ID: instrução completa
  ID/EX: sinais EX + MEM + WB  (ALUSrc, ALUOp, RegDst, Branch, MemR/W, MemtoReg, RegWrite)
  EX/MEM: sinais MEM + WB       (Branch, MemRead, MemWrite, MemtoReg, RegWrite)
  MEM/WB: sinais WB              (MemtoReg, RegWrite)

Cada registrador de pipeline "descarta" os sinais que já foram
usados e propaga apenas os que serão necessários adiante.

Detecção de Hazards e Forwarding Unit

Além do controle principal, o pipeline precisa de duas unidades adicionais que detectam e resolvem hazards em tempo real:

Unidades de Controle do Pipeline
1. FORWARDING UNIT (resolve data hazards)
   ─────────────────────────────────────────
   Entradas:
     - EX/MEM.RegisterRd  (destino da instrução que acabou de executar)
     - MEM/WB.RegisterRd  (destino da instrução anterior a essa)
     - ID/EX.RegisterRs   (fonte 1 da instrução atual)
     - ID/EX.RegisterRt   (fonte 2 da instrução atual)

   Lógica:
     Se EX/MEM.RegWrite=1 AND EX/MEM.Rd ≠ 0 AND EX/MEM.Rd == ID/EX.Rs:
       ForwardA = 10  (forward do estágio EX/MEM)
     Se MEM/WB.RegWrite=1 AND MEM/WB.Rd ≠ 0 AND MEM/WB.Rd == ID/EX.Rs:
       ForwardA = 01  (forward do estágio MEM/WB)
     Senão:
       ForwardA = 00  (sem forwarding, valor do banco)

   (Mesma lógica para ForwardB com RegisterRt)

2. HAZARD DETECTION UNIT (detecta load-use hazard)
   ──────────────────────────────────────────────────
   Entradas:
     - ID/EX.MemRead       (instrução anterior é lw?)
     - ID/EX.RegisterRt    (destino do lw)
     - IF/ID.RegisterRs    (fonte 1 da instrução atual)
     - IF/ID.RegisterRt    (fonte 2 da instrução atual)

   Lógica:
     Se ID/EX.MemRead=1 AND (ID/EX.Rt == IF/ID.Rs OR ID/EX.Rt == IF/ID.Rt):
       → Inserir STALL (bubble):
         - PCWrite = 0 (PC não avança)
         - IF/ID.Write = 0 (instrução não avança)
         - Sinais de controle no ID/EX = 0 (nop)

3. BRANCH CONTROL (resolve control hazards)
   ─────────────────────────────────────────
   Compara registradores no estágio ID (em vez de EX) para
   reduzir penalidade de branch de 2 ciclos para 1.
   Com branch prediction: flush se predição errada.
i
A checagem Rd ≠ 0 é importante O registrador $0 no MIPS é hardwired em zero e não pode ser escrito. Se uma instrução tem rd=$0, não há dependência real (o valor é sempre zero). Sem essa checagem, o forwarding unit detectaria "dependências fantasma" em instruções que escrevem em $0 (como sll $0, $0, 0 — que é o nop do MIPS).

Implementação em Lógica Combinacional

O controle principal pode ser implementado com portas lógicas básicas. Cada sinal de controle é uma função booleana do opcode:

Equações Booleanas — Controle Principal
# Definindo sinais auxiliares a partir do opcode [31:26]:
R-type  = (op == 000000)
lw      = (op == 100011)
sw      = (op == 101011)
beq     = (op == 000100)

# Sinais de controle como funções do opcode:
RegDst   = R-type
ALUSrc   = lw OR sw
MemtoReg = lw
RegWrite = R-type OR lw
MemRead  = lw
MemWrite = sw
Branch   = beq
ALUOp[1] = R-type
ALUOp[0] = beq

# Cada equação pode ser implementada com 1-3 portas lógicas.
# Para o MIPS completo (mais instruções), as equações ficam maiores
# mas o princípio é o mesmo: lógica combinacional pura, sem estado.

# Latência do controle hardwired:
#   1-2 níveis de portas lógicas ≈ 1-2 ns
#   Muito mais rápido que microprogramação (acesso à ROM)

# Para adicionar uma nova instrução:
#   1. Definir o opcode
#   2. Definir os sinais de controle na tabela
#   3. Atualizar as equações booleanas
#   4. Ressintetizar o circuito

No harness.os

A unidade de controle decide o que cada parte do processador faz com base na instrução — exatamente como as rules no harness.os controlam o comportamento de cada agente com base no contexto.

Mapeamento: Controle → harness.os
Unidade de Controle              harness.os
─────────────────────────────    ──────────────────────────────────────
Opcode (identifica instrução)    Contexto da tarefa (tipo de request)

Sinais de controle               Rules + workflows
  RegWrite, MemRead, etc.          "quando QA: rodar testes antes de deploy"
                                   "quando bug: criar branch, fix, PR"

Tabela de controle               Rules database
  opcode → sinais                  contexto → regras ativas

ALU Control (2° nível)           Concern-specific rules
  ALUOp + funct → operação         Tipo geral + detalhe → ação específica
                                   Ex: governance + deploy → approval flow

Forwarding Unit                  Handoff mechanism
  Detecta dependências               Detecta que sessão B precisa do
  entre instruções                    resultado da sessão A

Hazard Detection                 Blocker detection
  Identifica conflitos               Identifica dependências não
  e insere stalls                     resolvidas e pausa a sessão

Controle hardwired               Rules as code
  Lógica fixa, rápida               Rules no banco, consultadas por
  mas inflexível                     get_rules(), atualizáveis em runtime

Controle microprogramado         Rules as prompts
  Flexível, reprogramável           System prompts, atualizáveis sem
  mas mais lento                     rebuild do agente

Homework

  1. Preencha a tabela de controle para a instrução ori $t0, $s1, 0xFF (OR imediato, opcode=001101). Quais sinais de controle estão ativos? Qual é o ALUOp? O que o ALU Control gera?
  2. A forwarding unit detecta a seguinte sequência como um hazard?
    Assembly MIPS
    add $t0, $s0, $s1
    nop
    sub $t2, $t0, $t3
    Justifique. Qual tipo de forwarding é aplicado (EX/MEM ou MEM/WB)?
  3. Explique por que o controle hardwired é preferido em processadores RISC e o microprogramado em CISC. Relacione com o tamanho e complexidade do conjunto de instruções.
  4. No harness.os, as rules funcionam como controle hardwired (fixas, rápidas) ou microprogramado (flexíveis, reprogramáveis)? Justifique com base em como elas são armazenadas e acessadas.

Resumo

Verifique seu entendimento

Para a instrução sw $t0, 4($s1), quais sinais de controle estão ativos (=1)?

  • RegWrite=1, MemRead=1, ALUSrc=1
  • MemWrite=1, RegWrite=1, Branch=1
  • RegDst=1, ALUSrc=0, MemtoReg=1
  • ALUSrc=1, MemWrite=1 (RegWrite=0, MemRead=0, Branch=0)