Unidade de Controle
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.
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:
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:
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:
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:
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:
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.
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:
# 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.
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
- 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? - A forwarding unit detecta a seguinte sequência como um hazard?
Justifique. Qual tipo de forwarding é aplicado (EX/MEM ou MEM/WB)?Assembly MIPS
add $t0, $s0, $s1 nop sub $t2, $t0, $t3 - 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.
- 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
- A unidade de controle gera 8 sinais (RegDst, ALUSrc, MemtoReg, RegWrite, MemRead, MemWrite, Branch, ALUOp) a partir do opcode
- Dois níveis de decodificação: controle principal (opcode → sinais gerais) e ALU control (ALUOp + funct → operação exata)
- No pipeline, sinais são propagados pelos registradores IF/ID, ID/EX, EX/MEM, MEM/WB
- Forwarding unit: compara registradores de destino e fonte para detectar e resolver data hazards
- Hazard detection unit: detecta load-use hazards e insere stalls quando forwarding não é suficiente
- Controle hardwired (RISC): lógica combinacional, rápido, inflexível; microprogramado (CISC): ROM, flexível, mais lento
Verifique seu entendimento
Para a instrução sw $t0, 4($s1), quais sinais de controle estão ativos (=1)?