Caminho de Dados
Vídeo da aula estará disponível em breve
O que é o Caminho de Dados
O caminho de dados (datapath) é o circuito que executa as operações sobre os dados dentro do processador. Ele contém os componentes funcionais — registradores, ULA, memórias, multiplexadores — e as conexões entre eles. Junto com a unidade de controle, o datapath forma o núcleo do processador.
Nesta aula, vamos construir o datapath do MIPS monociclo: um processador que executa cada instrução em exatamente um ciclo de clock. É simples o suficiente para entender como tudo se conecta, mas poderoso o suficiente para executar um subconjunto real do MIPS.
lw). O processador multiciclo divide a execução em etapas, permitindo ciclos mais curtos — mas é mais complexo. Nesta aula focamos no monociclo.
Componentes do Datapath
O datapath do MIPS monociclo usa os seguintes componentes:
Componente Função
──────────────────────── ─────────────────────────────────────────────
PC (Program Counter) Armazena o endereço da instrução atual.
Atualizado a cada ciclo: PC ← PC + 4 ou
endereço do branch.
Memória de Instruções Recebe o endereço (PC), retorna a instrução
de 32 bits. Somente leitura durante execução.
Banco de Registradores 32 registradores de 32 bits ($0 a $31).
2 portas de leitura (Read Register 1/2)
1 porta de escrita (Write Register + Write Data)
$0 é hardwired em zero.
ULA (ALU) Executa operações aritméticas e lógicas:
ADD, SUB, AND, OR, SLT, etc.
Saída: resultado + flag Zero (para branches).
Memória de Dados Lê ou escreve dados (lw/sw).
Entradas: endereço (calculado pela ULA),
dado a escrever. Saída: dado lido.
Extensão de Sinal Estende o imediato de 16 bits para 32 bits
(preservando o sinal para operações corretas).
MUXes (Multiplexadores) Selecionam entre duas entradas com base em
um sinal de controle. Fundamentais para
reutilizar o datapath entre instruções.
Somadores (Adders) PC+4 (próxima instrução sequencial) e
cálculo do endereço de branch (PC + offset).
O Datapath Completo
O diagrama abaixo mostra como os componentes se conectam. Cada instrução segue um caminho diferente pelo datapath, controlado pelos sinais de controle (que veremos na aula 4.3).
+4
|
┌──────┴──────┐
│ Somador │
└──────┬──────┘
│ ┌─────────────┐
┌───┐ ┌──────┴──────┐ │ Extensão │
│PC │───►│ Memória de │ │ de Sinal │
│ │ │ Instruções │ │ 16→32 bits │
└─┬─┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ ┌──────┴──────────────────┐ │ ┌───────────┐
│ │ Instrução (32 bits) │ │ │ Somador │
│ │ [25:21] [20:16] [15:0] │ │ │ (branch) │
│ └──┬────┬────┬────┬───────┘ │ └─────┬─────┘
│ │ │ │ │ │ │
│ ┌────┴────┴────┴────┐ │ │
│ │ Banco de │ MUX ◄──┘ MUX ◄┘
│ │ Registradores │ │ │
│ │ Read1 Read2 │ ┌────┴────┐ │
│ │ Write WData │ │ ULA │ │
│ └────┬────┬─────────┘ │ ADD/SUB │ │
│ │ │ │ AND/OR │ │
│ dado1│ │dado2 │ SLT │ │
│ │ │ └────┬────┘ │
│ │ │ │ Zero │
│ └────┤ ┌─────┴─────┐ │
│ │ │ Memória │ │
│ └──►MUX───────►│ de Dados │ │
│ │ R / W │ │
│ └─────┬─────┘ │
│ │ │
│ MUX ◄┘ │
│ │ │
└───────────────────────────────┘ │
▲ │
MUX (PCSrc)◄───────────────────────┘
Sinais de controle (vindos da Unidade de Controle):
RegDst, ALUSrc, MemtoReg, RegWrite, MemRead, MemWrite, Branch, ALUOp
Execução de Instruções no Datapath
Vamos rastrear três tipos de instrução pelo datapath, passo a passo.
Instrução R-type: add $t0, $s1, $s2
# add $t0, $s1, $s2 → $t0 = $s1 + $s2
# Formato R: [op=0 | rs=$s1 | rt=$s2 | rd=$t0 | shamt=0 | funct=0x20]
Passo 1: PC fornece endereço → Memória de Instruções retorna instrução
Passo 2: Campos rs ($s1) e rt ($s2) → portas Read1 e Read2 do banco
Campo rd ($t0) → porta Write Register (via MUX RegDst=1)
Passo 3: Valores de $s1 e $s2 → entradas da ULA
ALUSrc=0 (segundo operando vem do registrador, não do imediato)
ALUOp sinaliza ADD
Passo 4: Resultado da ULA → porta Write Data do banco de registradores
MemtoReg=0 (dado vem da ULA, não da memória)
RegWrite=1 (escrita habilitada)
Passo 5: PC ← PC + 4 (Branch=0, sem desvio)
Instrução Load Word: lw $t0, 8($s1)
# lw $t0, 8($s1) → $t0 = Mem[$s1 + 8]
# Formato I: [op=0x23 | rs=$s1 | rt=$t0 | imm=8]
Passo 1: PC → Memória de Instruções → instrução
Passo 2: Campo rs ($s1) → Read1 do banco
Campo rt ($t0) → Write Register (RegDst=0: rt é destino em lw)
Imediato (8) → Extensão de Sinal → 0x00000008
Passo 3: $s1 + 8 na ULA (ALUSrc=1: segundo operando é o imediato estendido)
Passo 4: Resultado da ULA (endereço) → Memória de Dados (MemRead=1)
Passo 5: Dado lido da memória → Write Data do banco
MemtoReg=1 (dado vem da memória, não da ULA)
RegWrite=1
Passo 6: PC ← PC + 4
Instrução Branch: beq $s1, $s2, offset
# beq $s1, $s2, L1 → se $s1 == $s2, desvia para L1
# Formato I: [op=0x04 | rs=$s1 | rt=$s2 | imm=offset]
Passo 1: PC → Memória de Instruções → instrução
Passo 2: $s1 → Read1, $s2 → Read2 do banco
Imediato (offset) → Extensão de Sinal → shift left 2
Passo 3: ULA calcula $s1 - $s2 (ALUOp=SUB)
Se resultado = 0, flag Zero = 1 (são iguais)
Somador de branch: PC + 4 + (offset × 4)
Passo 4: Se Branch=1 AND Zero=1:
PC ← endereço do branch (PCSrc=1)
Senão:
PC ← PC + 4 (PCSrc=0)
RegWrite=0, MemWrite=0 (beq não escreve em registrador nem memória)
Tempo de Ciclo e Caminho Crítico
No processador monociclo, o ciclo de clock deve ser longo o suficiente para que a instrução mais demorada complete toda a execução. O caminho crítico é o caminho mais longo que um sinal percorre no datapath.
Tempos típicos (simplificados):
Memória de Instruções: 200 ps
Banco de Registradores: 100 ps (leitura), 100 ps (escrita)
ULA: 200 ps
Memória de Dados: 200 ps
MUX / Extensão / Somador: desprezíveis (~0 ps para simplificar)
Instrução Caminho Tempo
─────────── ───────────────────────────────────────────── ─────
R-type MemInst → RegRead → ULA → RegWrite 600 ps
lw MemInst → RegRead → ULA → MemDados → RegWrite 800 ps ←
sw MemInst → RegRead → ULA → MemDados 700 ps
beq MemInst → RegRead → ULA 500 ps
Caminho crítico = lw = 800 ps
Ciclo de clock ≥ 800 ps → Frequência ≤ 1/800ps = 1.25 GHz
Problema: TODAS as instruções demoram 800 ps, mesmo as que
precisariam de apenas 500 ps. O processador monociclo
desperdiça tempo nas instruções rápidas.
Solução: pipeline (aula 4.2) — divide a execução em estágios,
permitindo que diferentes instruções usem diferentes partes
do datapath ao mesmo tempo.
Store Word e o Papel dos MUXes
A instrução sw $t0, 12($s1) usa o datapath de forma diferente: o dado lido da porta Read2 do banco ($t0) vai para a entrada de escrita da Memória de Dados, enquanto a ULA calcula o endereço ($s1 + 12).
MUX RegDst: Seleciona o registrador de destino
0 → rt (usado por lw, instruções I-type)
1 → rd (usado por R-type)
MUX ALUSrc: Seleciona o segundo operando da ULA
0 → Read Data 2 (registrador, R-type e beq)
1 → Imediato estendido (lw, sw, addi)
MUX MemtoReg: Seleciona o que será escrito no registrador
0 → Resultado da ULA (R-type)
1 → Dado lido da memória (lw)
MUX PCSrc: Seleciona o próximo PC
0 → PC + 4 (sequencial)
1 → PC + 4 + offset×4 (branch taken)
Sem os MUXes, precisaríamos de datapaths separados para cada
tipo de instrução. Os MUXes permitem reutilizar os mesmos
componentes para todas as instruções.
No harness.os
O caminho de dados é como uma pipeline de processamento — a instrução flui por componentes especializados, assim como uma requisição no harness.os flui por validação, execução e logging.
Datapath MIPS harness.os
───────────────────────────── ─────────────────────────────────────
PC (aponta para instrução) Session ID (identifica a operação atual)
Memória de Instruções Prompt / Tool definition
(busca a instrução a executar) (busca a instrução para o agente)
Banco de Registradores Contexto da sessão
(armazena dados temporários) (handoff, rules, project state)
ULA (executa a operação) Tool execution
(executa a ferramenta chamada)
Memória de Dados (lê/escreve) Database (Neon Postgres)
(persiste decisões, learnings, events)
MUXes (selecionam caminhos) Rules / Conditions
(decidem qual workflow seguir)
Sinais de Controle Governance concern
(controla quem pode fazer o quê)
Cada requisição no harness flui por:
1. Fetch: carregar contexto (start_session → handoff)
2. Decode: interpretar o pedido (analisar a tarefa)
3. Execute: executar a ação (tool calls, file edits)
4. Store: persistir resultado (log_decision, log_learning)
5. Update: avançar para próxima tarefa (end_session → handoff)
Homework
- Desenhe (no papel ou digitalmente) o caminho que a instrução
addi $t1, $t2, 100segue pelo datapath. Quais sinais de controle precisam estar ativos? - Se a memória de instruções demora 250ps, o banco de registradores 150ps (leitura e escrita), a ULA 200ps e a memória de dados 250ps, qual é o ciclo de clock mínimo do processador monociclo? Qual instrução define o caminho crítico?
- Explique por que o MUX ALUSrc é essencial: o que aconteceria se a ULA sempre recebesse o valor do registrador rt como segundo operando?
- No harness.os, identifique o equivalente do "caminho crítico": qual operação na pipeline de uma sessão é a mais demorada e determina o tempo total?
Resumo
- O datapath do MIPS monociclo contém: PC, memória de instruções, banco de registradores, ULA, memória de dados, MUXes e extensão de sinal
- Instruções R-type usam dois registradores como entrada da ULA e escrevem o resultado em rd
- A instrução lw percorre o caminho mais longo: MemInst → RegRead → ULA → MemDados → RegWrite
- O beq usa a ULA para comparar registradores e o somador de branch para calcular o endereço destino
- O ciclo de clock é determinado pelo caminho crítico (instrução mais lenta = lw)
- MUXes permitem reutilizar o mesmo datapath para todos os tipos de instrução
Verifique seu entendimento
No processador MIPS monociclo, qual instrução define o caminho crítico (maior tempo de execução)?