flowchart TB
subgraph CONC["Fundamentos conceituais"]
AO["Arquitetura × Organização"]
HIST["5 gerações<br/>RISC × CISC"]
VN["Von Neumann"]
HV["Harvard / Harvard mod."]
end
subgraph CASO["Estudo de caso e métricas"]
PIC["PIC18F4550<br/>(blocos, ciclo, pipeline)"]
MET["Métricas:<br/>T = N·CPI·Tcy<br/>IPC, MIPS, Amdahl, Gustafson"]
end
subgraph PRAT["Prática (Projeto Integrador)"]
T1["Tarefa 1<br/>Ambiente + LED"]
T2["Tarefa 2<br/>Quadro Arq/Org<br/>Harvard mod no .map"]
T3["Tarefa 3<br/>Medição de tempo<br/>no osciloscópio"]
end
CONC --> CASO --> PRAT
PRAT --> M2["Módulo 02:<br/>Representação de Dados"]
Módulo 1: Fundamentos de Arquitetura e Organização de Computadores
Bem-vindo ao primeiro módulo. Escrevi este material como se estivéssemos os dois na frente do quadro, com o kit ACEPIC PRO V8.2 sobre a mesa. Para mais profundidade, abra o livro do módulo. Aqui, vou direto ao ponto.
A Pergunta que Abre o Semestre
Provocação inicial. Imagine dois processadores Intel lado a lado. Você compila o mesmo binário x86 e roda nos dois. Um termina em 1 segundo, o outro leva 5. Mesmo programa, mesma entrada. Como pode?
Se você ficou coçando a cabeça, ótimo. A resposta exige separar duas palavras que a literatura técnica trata como sinônimos: arquitetura e organização. Não são. E quando você entender por que, vai responder essa pergunta com a precisão de quem está dentro do silício.
Esse é o objetivo do módulo, junto com apresentar o personagem que vai te acompanhar nas próximas quinze semanas: o microcontrolador PIC18F4550, instalado no KIT ACEPIC PRO V8.2. Você vai gravá-lo, depurar nele, medir tempos com osciloscópio nas pernas dele.
O caminho é o seguinte. Primeiro, separo arquitetura de organização. Depois, uma passagem rápida pela história — cinco gerações e a briga RISC versus CISC. Aí entram os modelos Von Neumann e Harvard, com a variante modificada do PIC. Em seguida, desmonto o PIC18F4550. Por fim, construo o vocabulário quantitativo de desempenho — tempo, CPI, IPC, Amdahl, Gustafson — e amarro nas três tarefas do Projeto Integrador. Olha o mapa.
Arquitetura e Organização
Vou direto. Quando você fala “arquitetura”, está se referindo ao que o programador enxerga do hardware: conjunto de instruções, registradores nomeáveis no código, modelo e modos de endereçamento de memória, mecanismos de exceção, tipos primitivos, modelo de E/S. Pense na arquitetura como um contrato: o fabricante diz “estas instruções existem e fazem isso”; o programador escreve código contando com esse contrato.
E “organização”? É tudo do outro lado do contrato. Como o fabricante implementou o cardápio: caminho de dados interno, profundidade de pipeline, hierarquia de cache, frequência, largura física dos barramentos, tecnologia das memórias. O ponto importante: duas organizações completamente diferentes podem implementar a mesma arquitetura. O programa funciona igual nas duas, mas tempo, consumo e custo podem ser bem diferentes.
flowchart TB
P["Programador<br/>(código C, ASM)"]
A["Arquitetura<br/>ISA, registradores, modelo de memória,<br/>modos de endereçamento, exceções"]
O["Organização<br/>Pipeline, caches, ULA, barramentos,<br/>frequência, tecnologia de memória"]
H["Silício<br/>Transistores, geometria, materiais"]
P -->|"escreve programa"| A
A -.->|"contrato visível"| P
A --> O
O --> H
H -.->|"desempenho percebido"| P
Essa separação tem origem industrial concreta. Em 1964, a IBM lançou a família System/360 e fez uma jogada genial: definiu uma única arquitetura e construiu várias máquinas com organizações deliberadamente diferentes para implementá-la. Tinha o modelo barato para pequenos escritórios e o caríssimo para bancos. O mesmo programa rodava em todos. Foi ali que nasceu a noção moderna de compatibilidade de família.
Agora, o critério prático. Eu chamo de prova do programador: se mudar um detalhe altera o resultado lógico de algum programa correto, esse detalhe é arquitetura; se só afeta tempo, consumo ou custo, é organização. Simples assim.
Exemplo real. Pegue o Intel Core i9-13900K e o Intel Core i3-13100. Ambos implementam x86-64 com SSE, AVX e AVX2; o mesmo binário roda nos dois. Arquiteturalmente, equivalentes. Por dentro, o i9 tem núcleos de desempenho e eficiência, três níveis de cache somando dezenas de megabytes, clock acima de 5 GHz, pipeline com mais de quinze estágios. O i3 tem menos de tudo. Organizações radicalmente diferentes, e o mesmo benchmark roda muitas vezes mais rápido no i9 sem que uma linha de código mude. Aí está a resposta da provocação inicial: arquitetura explica a compatibilidade; organização explica a diferença de desempenho.
Antes de seguir, faça este teste: se eu trocasse a SRAM de 2 KB do PIC18F4550 por uma de 8 KB sem mexer no mapa de endereçamento visível ao programador, isso seria mudança de arquitetura ou de organização? Aplique a prova do programador.
Tem uma terceira palavra que mora dentro da organização e aparecerá nos Módulos 04 e 05: microarquitetura. Descreve como o processador implementa internamente a arquitetura — pipeline, execução fora de ordem, unidade de controle — sem descer aos transistores. Cuidado com o marketing: “arquitetura Intel Skylake” e “arquitetura Apple M2” são, no rigor que adotamos, microarquiteturas dentro das famílias x86-64 e ARMv8-A.
Cinco Gerações de Computadores
Por que estudar história numa disciplina técnica? Porque cada inovação arquitetural nasceu como resposta a uma limitação tecnológica concreta, e entender a limitação é a única forma de entender por que a decisão foi tomada daquele jeito.
timeline
title Cinco gerações de computadores
1940-1955 : 1ª geração<br/>Válvulas termiônicas<br/>ENIAC, EDVAC<br/>programa armazenado
1955-1965 : 2ª geração<br/>Transistor discreto<br/>IBM 7090, PDP-1<br/>FORTRAN, COBOL
1965-1971 : 3ª geração<br/>CI SSI e MSI<br/>IBM System/360<br/>família arquitetural
1971-1980 : 4ª geração<br/>Microprocessador<br/>Intel 4004, 8086<br/>computador pessoal
1980-hoje : 5ª geração<br/>VLSI, computação ubíqua<br/>x86, ARM, PIC18<br/>RISC × CISC
A pré-história começa no século XIX, com a Máquina Analítica de Babbage e as notas de Ada Lovelace, descrevendo o primeiro algoritmo. A primeira geração (1940–1955) é a das válvulas: o ENIAC, com dezessete mil tubos, era programado por reconexão manual. Foi nessa geração, em 1945, que von Neumann redigiu o relatório do EDVAC e formalizou o programa armazenado. A segunda trocou válvulas por transistores; FORTRAN e COBOL separaram o programador da máquina. A terceira (1960–1970) trouxe circuitos integrados, o IBM System/360 e a microprogramação. A quarta começou em 1971 com o Intel 4004 — primeiro microprocessador em pastilha única — e viabilizou o computador pessoal.
A quinta geração, dos anos 1980 em diante, é a do VLSI e da computação ubíqua: smartphone, sensor inteligente, microcontrolador embarcado. O PIC18F4550 — projetado pela Microchip por volta de 2007, uns 30 000 transistores, 32 KB de Flash, 2 KB de RAM — é representante típico. Cada geração não substituiu as anteriores, apenas adicionou uma camada. O chip que você vai gravar executa internamente um modelo de Von Neumann modificado formulado em 1945. A história do nosso campo é cumulativa.
Uma controvérsia das décadas de 1980 a 2000 merece destaque: RISC versus CISC. Os processadores CISC (VAX-11, x86) adotavam conjuntos enormes de instruções, esperando reduzir o trabalho do compilador. Patterson em Berkeley e Hennessy em Stanford perceberam que os compiladores só usavam um subconjunto pequeno delas. Propuseram o oposto: poucas instruções simples, mesmo tamanho, um ciclo cada, com memória só via load/store. O PIC18F4550 é híbrido: tamanho fixo de 16 bits (RISC), mas 75 instruções combinando memória com aritmética como ADDWF (CISC). O desfecho foi pragmático: x86 modernos traduzem internamente para micro-operações RISC; ARM e RISC-V acumularam extensões e ficaram mais densos.
O Modelo de Von Neumann
A invenção que justifica nomear um modelo inteiro em homenagem ao John von Neumann foi a do programa armazenado. Antes do EDVAC, programar significava religar cabos por horas. A proposta dele era radical na simplicidade: instruções são números, ficam na mesma memória dos dados, lidas do mesmo jeito.
Três consequências disso. Primeira: o programa pode ser modificado tão facilmente quanto qualquer dado, o que viabiliza compiladores e sistemas operacionais. Segunda: o hardware para acessar instruções é o mesmo para acessar dados, economia de circuitos enorme. Terceira: abre a porta para programas que se modificam a si mesmos — hoje desencorajado por segurança, mas usado à exaustão nas primeiras décadas.
flowchart LR
subgraph CPU["CPU"]
UC["Unidade<br/>de Controle"]
ULA["ULA"]
REG["Registradores<br/>PC, IR, ACC"]
end
MEM["Memória Principal<br/>instruções + dados<br/>(mesma)"]
IO["Subsistema<br/>de E/S"]
CPU <-->|"barramento único<br/>endereço/dado/controle"| MEM
CPU <--> IO
O modelo tem cinco subsistemas: unidade de controle, unidade lógica e aritmética, registradores de trabalho, memória principal e subsistema de E/S. A execução segue o ciclo de busca-decodificação-execução: o contador de programa (PC) guarda o endereço da próxima instrução; a unidade de controle joga esse endereço no barramento; a memória responde com a instrução; ela vai para o registrador de instrução (IR); o IR é decodificado e os sinais corretos coordenam a execução; no fim, o PC é incrementado (ou alterado por desvio) e o ciclo recomeça. É o coração de praticamente todo processador que já existiu.
Bonito, mas tem uma fragilidade. Como instruções e dados compartilham o mesmo barramento, a CPU não consegue buscar uma instrução e ler um dado no mesmo instante. As duas operações se serializam. John Backus, no Turing de 1977, batizou esse fenômeno de gargalo de Von Neumann. Se o tempo interno da CPU por instrução for \tau_p e o tempo de acesso à memória for \tau_m, o tempo efetivo por instrução satisfaz
\tau \geq \tau_p + 2\,\tau_m,
porque cada instrução exige a busca da instrução em si e um acesso ao dado. Quando \tau_m é muito maior que \tau_p — situação que virou regra —, a CPU passa a maior parte do tempo esperando memória. Esse fenômeno tem nome: o famoso memory wall. A solução clássica nos processadores de propósito geral foi a hierarquia de caches, que você vai estudar no Módulo 09. A solução dos microcontroladores foi diferente, e me leva para a próxima seção.
Harvard e a Harvard Modificada do PIC
O nome “Harvard” vem do computador Mark I, construído por Howard Aiken em parceria entre IBM e Universidade de Harvard, operacional em 1944. Usava fitas de papel perfurado para instruções e contadores eletromecânicos para dados, em sistemas fisicamente separados. Décadas depois, esse esquema forneceu o nome para a classe de processadores que mantém instruções e dados em memórias fisicamente distintas com barramentos independentes.
flowchart LR
MI["Memória de<br/>Instruções<br/>(Flash 32 KB)"]
CPU["CPU"]
MD["Memória de<br/>Dados<br/>(SRAM 2 KB)"]
EE["EEPROM<br/>256 bytes"]
MI -->|"barramento de<br/>instruções 16 bits"| CPU
CPU <-->|"barramento de<br/>dados 8 bits"| MD
MI -.->|"TBLRD via TBLPTR<br/>(Harvard modificada)"| CPU
CPU <-.->|"EECON1/EECON2<br/>(protocolo)"| EE
A ideia é direta: instruções e dados em espaços de endereçamento separados, com barramentos físicos próprios. Num mesmo ciclo, o processador busca uma instrução e ao mesmo tempo lê ou escreve um dado. Sem concorrência pelo barramento. As larguras podem ser diferentes — no PIC18, instruções têm 16 bits, dados têm 8 — e até as tecnologias podem ser distintas: Flash não volátil para instruções, SRAM rápida para dados. A vantagem é o paralelismo de acesso: processadores Harvard atingem, em condições favoráveis, uma instrução por ciclo de relógio sem precisar de cache sofisticada.
Tem um porém na Harvard pura. Constantes e tabelas grandes — strings, tabelas de senos, vetores de calibração — não cabem confortavelmente na memória de dados, que costuma ser pequena. Numa Harvard pura, esses dados ocupariam a RAM mesmo sendo imutáveis. Desastre num sistema embarcado.
A solução do PIC18, e da maioria dos microcontroladores modernos, é a Harvard modificada. Mantém a separação de memórias e barramentos, mas a ISA inclui instruções específicas que permitem ler bytes da memória de instruções como se fossem dados, com latência ligeiramente maior. No PIC18 são TBLRD*, TBLRD*+, TBLRD*- e TBLRD+*, operando com o ponteiro TBLPTR; o byte lido aparece em TABLAT. Na prática, ao declarar static const uint8_t tabela[] = { ... } em C, o XC8 aloca a tabela em Flash e, ao acessar tabela[i], emite automaticamente a sequência MOVLW/ADDWF/TBLRD*. Para você, parece acesso ordinário a vetor; para o hardware, é uma travessia de fronteira entre espaços que, na Harvard pura, seria proibida. Esse “modificada” é a chave de tudo.
Há ainda um terceiro espaço no PIC18: a EEPROM de 256 bytes, para dados que precisam sobreviver ao desligamento — calibrações, contadores não voláteis, identificadores únicos. O acesso é mediado pelos registradores EECON1 e EECON2, num protocolo de bytes mágicos que evita escritas acidentais. A EEPROM tolera centenas de milhares de ciclos de escrita por célula, contra dezenas de milhares da Flash.
Três modelos lado a lado
| Aspecto | Von Neumann | Harvard pura | Harvard modificada (PIC18) |
|---|---|---|---|
| Espaços de endereçamento | Um único | Dois disjuntos | Dois (mais EEPROM), com acesso cruzado limitado |
| Barramentos físicos | Um | Dois independentes | Dois (instruções 16 bits, dados 8 bits) |
| Acesso paralelo busca/dado | Não | Sim | Sim |
| Constantes literais grandes | Vivem na RAM | Vivem na RAM (limitação) | Vivem em Flash, lidas via TBLRD |
| Programas auto-modificáveis | Possíveis | Impossíveis na ISA pura | Possíveis via escrita controlada na Flash |
| Representantes típicos | x86 (arquitetural), CPUs de propósito geral | DSPs clássicos | PIC, AVR, ARM Cortex-M, MSP430 |
E uma curiosidade que costuma quebrar a cabeça: o x86 moderno, do ponto de vista do programador, é uma arquitetura de Von Neumann — uma única memória vista pelo programa. Mas internamente as caches L1 são separadas em cache de instruções e cache de dados, materializando uma organização de inspiração harvardiana. A arquitetura é Von Neumann; a organização é mista. Esse exemplo, sozinho, mostra a potência da distinção que construímos no começo.
O PIC18F4550 como Estudo de Caso
Por que escolhi esse chip? Quatro motivos. Regularidade ortogonal: 75 instruções, quase todas de um ciclo, codificação fixa de 16 bits em poucas famílias bem definidas — dá para estudar a ISA inteira num módulo. Acesso direto aos periféricos: ADC, USB, UART, SPI, I²C, comparadores, timers, tudo integrado, tudo num único datasheet. Previsibilidade de timing: sem caches, sem execução fora de ordem, o tempo de execução é exatamente calculável. Custo e robustez: o KIT ACEPIC PRO V8.2 cabe na mochila e tolera os erros típicos de quem está aprendendo.
flowchart TB
subgraph Nucleo["Núcleo do PIC18F4550"]
UC["Unidade<br/>de Controle"]
ULA["ULA 8 bits"]
W["WREG"]
ST["STATUS<br/>C, DC, Z, OV, N"]
end
Flash["Flash 32 KB<br/>(16 K palavras<br/>de 16 bits)"]
SRAM["SRAM 2 KB<br/>(16 bancos +<br/>Access Bank)"]
EE["EEPROM<br/>256 bytes"]
subgraph Perif["Periféricos integrados"]
USB["USB 2.0"]
UART["EUSART"]
MSSP["MSSP<br/>(I²C/SPI)"]
ADC["ADC 10 bits<br/>13 canais"]
TIM["Timers<br/>+ CCP/PWM"]
IO["35 pinos I/O<br/>PORTA..PORTE"]
end
CK["Oscilador externo<br/>8 MHz → ÷4 → Fcy = 2 MHz<br/>+ PLL para USB"]
Flash --> Nucleo
Nucleo <--> SRAM
Nucleo <-.-> EE
Nucleo <--> Perif
CK --> Nucleo
A CPU abriga a unidade de controle, a ULA de 8 bits, o registrador de trabalho WREG (também chamado W) e o STATUS, com os cinco flags fundamentais — Carry, Digit Carry, Zero, Overflow e Negative. A Flash de 32 KB armazena 16 mil palavras de 16 bits, reprogramável in-circuit. A SRAM de 2 KB se organiza em dezesseis bancos de 256 bytes selecionados pelo BSR, com o Access Bank combinando os primeiros 96 bytes da RAM com os 160 bytes superiores onde residem os SFRs. Os periféricos são fartos: dois MSSP (I²C/SPI), uma EUSART, USB 2.0 full-speed, ADC de 10 bits, três comparadores, quatro timers, dois CCP e 35 pinos de I/O.
Agora aplique comigo a prova do programador — é a base direta da Tarefa 2 do Projeto Integrador. As 75 instruções, o WREG, os flags do STATUS, os três espaços de memória, os SFRs como TRISx, LATx e ADCONx — tudo isso é arquitetura, porque o seu código depende deles diretamente. Já o pipeline de dois estágios, o Access Bank, a largura física do barramento de dados de 8 bits, o cristal externo, a divisão por quatro, a PLL do USB, a tecnologia das células — tudo isso é organização. Se eu trocasse a SRAM por uma mais rápida, nenhum programa correto deixaria de funcionar. O tempo mudaria; o resultado lógico, não.
O ciclo de instrução do PIC18 tem uma característica elegante. Conceitualmente, são cinco fases: busca, decodificação, execução, acesso à memória e escrita do resultado. Mas o PIC18 compacta tudo em dois estágios físicos: fetch e execute. Isso só é possível porque a arquitetura Harvard permite à CPU buscar a próxima instrução pelo barramento de instruções enquanto a atual está sendo executada via barramento de dados. Os dois trabalhos acontecem em paralelo.
flowchart LR
subgraph C1["Ciclo 1"]
F1["Fetch I1"]
end
subgraph C2["Ciclo 2"]
E1["Execute I1"]
F2["Fetch I2"]
end
subgraph C3["Ciclo 3"]
E2["Execute I2"]
F3["Fetch I3"]
end
subgraph C4["Ciclo 4"]
E3["Execute I3"]
F4["Fetch I4"]
end
F1 --> E1
F2 --> E2
F3 --> E3
F4 --> E4["Execute I4"]
Depois de uma latência inicial de um ciclo (o pipeline precisa encher), o processador conclui uma instrução por ciclo de máquina. A exceção fica por conta das instruções que alteram o PC — todas as variantes de GOTO, CALL, BRA quando tomadas, RETURN, RETFIE, e os condicionais BTFSS/BTFSC que causam skip. Nessas, o prefetch já trouxe a instrução errada (a sequencial). Ela é descartada e o ciclo seguinte é gasto buscando a instrução de destino. Em outras palavras, o CPI dessas instruções é 2 em vez de 1. Decore: desvios tomados custam dois ciclos. Essa observação sustenta toda a análise de desempenho que você vai fazer.
Métricas de Desempenho
Quando alguém te disser que um processador é “duas vezes mais rápido” do que outro, pergunte: em qual carga? Com qual compilador? Sob qual frequência? Medindo o quê? Sem essas qualificações, “mais rápido” é palavra vazia. Esta seção te dá o vocabulário para conversar com precisão.
A métrica fundamental é o tempo de execução — duração em segundos entre o início e a conclusão da tarefa. Tudo entra: ciclos da CPU, esperas por memória, E/S, qualquer delay. Para análise interna ao processador, decompomos esse tempo em três fatores, na equação central da disciplina:
T = N_{\text{instr}} \cdot \text{CPI} \cdot T_{cy}
Aqui, N_{\text{instr}} é o número total de instruções executadas, CPI é o número médio de ciclos de máquina por instrução (Cycles Per Instruction) e T_{cy} é o período de um ciclo de máquina. Cada fator depende de uma camada distinta: N_{\text{instr}} depende do algoritmo e do compilador; CPI depende da arquitetura, microarquitetura e mistura de instruções; T_{cy} depende exclusivamente da organização. Otimizar desempenho é atacar simultaneamente os três.
flowchart LR
XT["Cristal externo<br/>Fosc = 8 MHz"]
DIV["Divisor<br/>÷ 4"]
FCY["Clock de máquina<br/>Fcy = 2 MHz<br/>Tcy = 500 ns"]
CPU["CPU<br/>(Q1, Q2, Q3, Q4)"]
XT --> DIV --> FCY --> CPU
Tem um detalhe específico do PIC18 que você vai memorizar com firmeza: o cristal externo gera F_{osc}, mas internamente um divisor por quatro produz o clock de máquina F_{cy} = F_{osc}/4. Para o cristal de 8 MHz típico do KIT, F_{cy} vale 2 MHz, e portanto T_{cy} = 500 ns. Anota, sublinha. A confusão mais frequente desta disciplina é trocar F_{osc} por F_{cy}, e quando isso acontece, a previsão teórica fica quatro vezes menor que o valor medido. Não passe vergonha por causa de um fator de quatro.
Para uma mistura de instruções com frequências relativas f_i e CPIs individuais c_i, o CPI médio é \text{CPI}_{\text{médio}} = \sum_i f_i \, c_i. Exemplo: 90% de instruções com CPI 1 e 10% de desvios tomados com CPI 2 dão 0{,}90 \cdot 1 + 0{,}10 \cdot 2 = 1{,}10. A 8 MHz com 10 000 instruções, o tempo é 10\,000 \cdot 1{,}10 \cdot 500\ \text{ns} \approx 5{,}5 ms.
O conceito gêmeo do CPI é o throughput. Em processadores, medimos em IPC (Instructions Per Cycle) ou MIPS. A relação é \text{IPC} = 1/\text{CPI}. No PIC18, em código sem desvios tomados, o IPC fica próximo de 1 em pipeline cheio. Superescalares modernos chegam a IPC maior que 1 — tema do Módulo 15. MIPS e MFLOPS têm uma armadilha: dependem da mistura de instruções, e uma máquina com mais instruções “fáceis” pode ter MIPS maior sem ser mais rápida. Por isso a indústria desenvolveu benchmarks padronizados (SPEC, CoreMark, EEMBC).
Para tornar palpável o efeito do CPI, escrevi um experimento: duas versões do mesmo laço de soma, uma simples e outra com laço desenrolado em blocos de quatro. O trabalho útil é igual, mas a fração de instruções de controle muda, e o CPI médio muda junto. Medindo a largura do pulso em RD0 com osciloscópio, você vê a diferença prevista pela teoria com os próprios olhos.
01_cpi_demo.c
/*
* Modulo 01 - Demonstracao do conceito de CPI (Cycles Per Instruction).
* Plataforma: PIC18F4550 + KIT ACEPIC PRO V8.2.
*
* Duas funcoes realizam exatamente a mesma soma de 100 valores armazenados
* em um vetor, mas com numero de instrucoes e mistura de CPIs diferentes.
* Compilando com XC8 e inspecionando o .lst, voce conta as instrucoes
* geradas e calcula o CPI medio de cada versao. Esse exercicio fixa a
* relacao T = N_instr * CPI_medio * Tcy estudada no capitulo.
*/
#include <xc.h>
#include <stdint.h>
#pragma config FOSC = XT_XT
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config MCLRE = ON
#pragma config PBADEN = OFF
#define _XTAL_FREQ 8000000UL
static const uint8_t valores[100] = {
/* 100 bytes constantes; ficam na Flash, lidos via TBLRD */
1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,15,16,17,18,19,20,
21,22,23,24,25,26,27,28,29,30, 31,32,33,34,35,36,37,38,39,40,
41,42,43,44,45,46,47,48,49,50, 51,52,53,54,55,56,57,58,59,60,
61,62,63,64,65,66,67,68,69,70, 71,72,73,74,75,76,77,78,79,80,
81,82,83,84,85,86,87,88,89,90, 91,92,93,94,95,96,97,98,99,100
};
static volatile uint16_t soma;
/* Versao 1: laço explícito. Muitas instruções de controle (incremento
* de índice, comparacao, desvio condicional). CPI medio mais alto pelo
* peso dos desvios tomados. */
static void soma_v1(void)
{
soma = 0;
for (uint8_t i = 0; i < 100; i++) {
soma = (uint16_t)(soma + valores[i]);
}
}
/* Versao 2: laco desenrolado em blocos de 4. Reduz a fracao de instrucoes
* de controle e, em consequencia, derruba o CPI medio mesmo executando
* praticamente o mesmo numero de somas. */
static void soma_v2(void)
{
soma = 0;
for (uint8_t i = 0; i < 100; i += 4) {
soma = (uint16_t)(soma + valores[i]);
soma = (uint16_t)(soma + valores[i + 1]);
soma = (uint16_t)(soma + valores[i + 2]);
soma = (uint16_t)(soma + valores[i + 3]);
}
}
void main(void)
{
TRISD = 0x00;
LATD = 0x00;
while (1) {
LATDbits.LATD0 = 1;
soma_v1();
LATDbits.LATD0 = 0;
__delay_ms(20);
LATDbits.LATD1 = 1;
soma_v2();
LATDbits.LATD1 = 0;
__delay_ms(200);
}
}01_cpi_demo.asm
; Modulo 01 - Demonstracao de CPI em assembly puro.
; Plataforma: PIC18F4550 + ACEPIC PRO V8.2.
;
; O programa realiza dois trechos de codigo equivalentes em efeito,
; mas com numero distinto de instrucoes e CPI medio distinto. RD0
; delimita o trecho 1 (laço); RD1 delimita o trecho 2 (desenrolado).
; Medindo a largura dos pulsos com osciloscopio, o estudante observa
; diretamente a relacao T = N_instr * CPI_medio * Tcy.
LIST P=18F4550
#include <p18f4550.inc>
CONFIG FOSC=XT_XT, WDT=OFF, LVP=OFF, MCLRE=ON, PBADEN=OFF
CBLOCK 0x00
ACC_L
ACC_H
IDX
D1, D2, D3
ENDC
ORG 0x0000
GOTO INICIO
ORG 0x0040
INICIO:
CLRF TRISD, ACCESS
CLRF LATD, ACCESS
LOOP_PRINC:
; --- Trecho 1: laço de 100 incrementos ----------------------
BSF LATD, 0, ACCESS
CLRF ACC_L, ACCESS
CLRF ACC_H, ACCESS
MOVLW d'100'
MOVWF IDX, ACCESS
LACO_V1:
MOVLW 1
ADDWF ACC_L, F, ACCESS
MOVLW 0
ADDWFC ACC_H, F, ACCESS
DECFSZ IDX, F, ACCESS
BRA LACO_V1
BCF LATD, 0, ACCESS
CALL DELAY_CURTO
; --- Trecho 2: laço desenrolado em blocos de 4 --------------
BSF LATD, 1, ACCESS
CLRF ACC_L, ACCESS
CLRF ACC_H, ACCESS
MOVLW d'25' ; 25 iteracoes de 4 somas cada
MOVWF IDX, ACCESS
LACO_V2:
MOVLW 1
ADDWF ACC_L, F, ACCESS
ADDWFC ACC_H, F, ACCESS
MOVLW 1
ADDWF ACC_L, F, ACCESS
ADDWFC ACC_H, F, ACCESS
MOVLW 1
ADDWF ACC_L, F, ACCESS
ADDWFC ACC_H, F, ACCESS
MOVLW 1
ADDWF ACC_L, F, ACCESS
ADDWFC ACC_H, F, ACCESS
DECFSZ IDX, F, ACCESS
BRA LACO_V2
BCF LATD, 1, ACCESS
CALL DELAY_LONGO
BRA LOOP_PRINC
DELAY_CURTO:
MOVLW d'10'
MOVWF D3, ACCESS
DC_3:
MOVLW d'200'
MOVWF D2, ACCESS
DC_2:
MOVLW d'20'
MOVWF D1, ACCESS
DC_1:
DECFSZ D1, F, ACCESS
BRA DC_1
DECFSZ D2, F, ACCESS
BRA DC_2
DECFSZ D3, F, ACCESS
BRA DC_3
RETURN
DELAY_LONGO:
MOVLW d'100'
MOVWF D3, ACCESS
DL_3:
MOVLW d'200'
MOVWF D2, ACCESS
DL_2:
MOVLW d'20'
MOVWF D1, ACCESS
DL_1:
DECFSZ D1, F, ACCESS
BRA DL_1
DECFSZ D2, F, ACCESS
BRA DL_2
DECFSZ D3, F, ACCESS
BRA DL_3
RETURN
ENDAgora a Lei de Amdahl, talvez a lição quantitativa mais importante deste módulo. Suponha que você identifique uma fração f do tempo de execução que pode ser acelerada por um fator k — paralelização, instrução especializada, reescrita em assembly. Qual o ganho global S (o speedup)? Gene Amdahl, em 1967, deu a resposta:
S = \frac{1}{(1-f) + \dfrac{f}{k}}
No limite em que k \to \infty, o speedup máximo vale 1/(1-f). Esse teto não depende de quão rápido você tornar a porção acelerada, depende apenas da fração que sobrou sem otimização.
flowchart LR
T0["Tempo original<br/>T = 1"]
F["Fração f<br/>acelerável"]
NF["Fração (1−f)<br/>inalterada"]
K["Aceleração<br/>por fator k"]
S["Speedup global<br/>S = 1 / ((1−f) + f/k)"]
LIM["Limite k → ∞<br/>S_max = 1 / (1−f)"]
T0 --> F
T0 --> NF
F --> K
K --> S
NF --> S
S --> LIM
A lição é desconcertante. Acelerar infinitamente 90% do tempo produz speedup global de apenas dez vezes, porque os 10% restantes continuam consumindo o mesmo tempo absoluto. Acelerar por fator 10 uma fração de 50% do tempo dá speedup de 1,82 vezes, não 5,5. Otimização vale a pena onde o programa gasta tempo, e o ganho global é tetado pela fração não otimizada. Antes de qualquer otimização, pergunte: que fração do tempo total essa rotina consome?
A Lei de Gustafson, de 1988, oferece um contraponto. À medida que as máquinas ficam mais rápidas, os usuários aumentam o tamanho dos problemas, e a fração paralelizável cresce mais rápido que a sequencial. Sob essa hipótese, o speedup escalado vale (1-f) + k \cdot f, crescendo linearmente em k, sem o teto rígido de Amdahl. Não há contradição: Amdahl é strong scaling (problema fixo, mais recursos); Gustafson é weak scaling (problema cresce com os recursos). Para sistemas embarcados, em que o problema é dado pela aplicação, Amdahl costuma ser mais relevante. Para data centers, Gustafson.
Um programa gasta 30% do tempo em E/S sequencial obrigatória e 70% em um laço puramente computacional. Qual é o speedup máximo teórico, mesmo paralelizando o laço infinitamente? Faça a conta. É exatamente o tipo de pergunta que aparece na prova.
Da Teoria ao Kit: o Projeto Integrador do Módulo
A cadeia de ferramentas que conecta o seu código C ao silício é uma sequência de cinco blocos encadeados, e cada elo é um ponto de falha.
flowchart LR
SRC["Código-fonte<br/>(.c / .asm)<br/>MPLAB X IDE"]
XC8["XC8 (C)<br/>ou pic-as (ASM)"]
LINK["Linker<br/>(.elf)"]
HEX["Imagem<br/>Intel HEX (.hex)"]
CHIP["PIC18F4550<br/>(Flash gravada)"]
SRC --> XC8 --> LINK --> HEX
HEX -->|"bootloader<br/>via USB"| CHIP
HEX -->|"PICkit<br/>via ICSP"| CHIP
O MPLAB X IDE, fornecido gratuitamente pela Microchip, é o ambiente integrado. O XC8 traduz seu C em assembly e código de máquina; o pic-as faz o mesmo a partir de assembly puro. A saída é um .hex no formato Intel HEX, gravado na Flash pelo bootloader residente no chip (via USB, com o ACEPIC Terminal ou o AN1310) ou por um programador externo como o PICkit conectado ao header ICSP.
A primeira tarefa do Projeto Integrador é colocar essa cadeia inteira para funcionar e gravar um programa que pisca os oito LEDs do kit em sequência.
01_blink_leds.c
/*
* Modulo 01 - Tarefa 1: programa de validacao do ambiente.
* Plataforma: PIC18F4550 + KIT ACEPIC PRO V8.2.
* Cristal externo de 8 MHz (XT) -> Fosc = 8 MHz, Tcy = 0,5 us.
* LEDs L1..L8 ligados em PORTD (RD0..RD7); jumper LEDS = fechado.
* Compilador: Microchip XC8.
*/
#include <xc.h>
// Configuracao de fusiveis para o cristal de 8 MHz do kit, WDT desligado,
// LVP desligado, MCLR habilitado, brown-out desligado.
#pragma config FOSC = XT_XT
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config MCLRE = ON
#pragma config PBADEN = OFF // PORTB em modo digital apos reset
#define _XTAL_FREQ 8000000UL
static void delay_500ms(void)
{
// Atraso baseado em macro do XC8, equivalente a 500 ms.
__delay_ms(500);
}
void main(void)
{
TRISD = 0x00; // PORTD inteiro como saida (LEDs L1..L8)
LATD = 0x00;
while (1) {
// Acende um LED de cada vez, varrendo da direita para a esquerda.
for (unsigned char i = 0; i < 8; i++) {
LATD = (unsigned char)(1u << i);
delay_500ms();
}
LATD = 0x00;
delay_500ms();
}
}01_blink_leds.asm
; Modulo 01 - Tarefa 1: programa de validacao do ambiente em assembly.
; Plataforma: PIC18F4550 + KIT ACEPIC PRO V8.2.
; Cristal externo 8 MHz, Tcy = 0,5 us.
; LEDs L1..L8 em RD0..RD7.
; Montador: MPASMX / pic-as (sintaxe MPASM classica).
LIST P=18F4550
#include <p18f4550.inc>
CONFIG FOSC=XT_XT, WDT=OFF, LVP=OFF, MCLRE=ON, PBADEN=OFF
; ---------------- Variaveis em Access Bank ----------------
CBLOCK 0x00
MASK ; padrao atual dos LEDs
D1, D2, D3 ; contadores do atraso
ENDC
; ---------------- Vetor de reset ----------------
ORG 0x0000
GOTO INICIO
ORG 0x0020
INICIO:
CLRF TRISD, ACCESS ; PORTD todo como saida
CLRF LATD, ACCESS
MOVLW 0x01
MOVWF MASK, ACCESS
LOOP_PRINC:
MOVF MASK, W, ACCESS
MOVWF LATD, ACCESS
CALL DELAY_500MS
; Desloca a mascara um bit para a esquerda.
RLNCF MASK, F, ACCESS
; Se completou 8 posicoes, recomeca com 0x01.
MOVF MASK, W, ACCESS
BNZ LOOP_PRINC
MOVLW 0x01
MOVWF MASK, ACCESS
BRA LOOP_PRINC
; ---------------- Atraso por software ----------------
; Aproximadamente 500 ms a Tcy = 0,5 us.
; Loop triplo: D3 * D2 * D1 ciclos = 250 * 200 * 20 ~ 1e6 ciclos -> 500 ms.
DELAY_500MS:
MOVLW d'250'
MOVWF D3, ACCESS
DL_3:
MOVLW d'200'
MOVWF D2, ACCESS
DL_2:
MOVLW d'20'
MOVWF D1, ACCESS
DL_1:
DECFSZ D1, F, ACCESS
BRA DL_1
DECFSZ D2, F, ACCESS
BRA DL_2
DECFSZ D3, F, ACCESS
BRA DL_3
RETURN
ENDO programa é deliberadamente simples — PORTD como saída, varredura L1 a L8 com 500 ms entre eles. Qualquer um de vocês escreveria em meia hora. Mas o ponto pedagógico não está no programa, está na cadeia inteira que precisa estar de pé: driver do CH340G instalado, versão compatível do MPLAB X, XC8 reconhecendo o PIC18F4550, jumpers do kit na posição correta, bootloader íntegro. Cada elo é uma oportunidade de falha, e lidar com elas é parte da experiência do módulo.
A segunda tarefa pede evidência empírica da Harvard modificada. Você grava um programa que define uma tabela de oito padrões binários em const uint8_t (alocada em Flash pelo XC8) e uma variável de índice em RAM; a cada iteração, o byte é lido via TBLRD e escrito em LATD.
01_harvard_demo.c
/*
* Modulo 01 - Tarefa 2: evidencia da arquitetura Harvard modificada.
* Demonstra dois aspectos arquiteturais do PIC18F4550:
* (a) constantes literais ficam na memoria de programa (rom const)
* e sao lidas via tabela (TBLPTR/TBLRD), nao competindo com a RAM;
* (b) variaveis vivem em data memory (RAM) e nao usam o barramento
* de instrucao.
*
* A tarefa pedagogica e: compilar, abrir o .lst/.map e identificar o
* endereco de cada simbolo, confirmando empiricamente a separacao de
* espacos de enderecamento prevista pela arquitetura Harvard.
*
* Plataforma: PIC18F4550 + ACEPIC PRO V8.2. LEDs em PORTD.
*/
#include <xc.h>
#include <stdint.h>
#pragma config FOSC = XT_XT
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config MCLRE = ON
#pragma config PBADEN = OFF
#define _XTAL_FREQ 8000000UL
// Tabela em memoria de programa (Flash, 32 KB). Cada padrao acende um
// LED diferente. A diretiva 'const' instrui o XC8 a alocar em ROM.
static const uint8_t padroes[8] = {
0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF
};
// Variavel em RAM (Access Bank). Demonstra o segundo espaco.
static uint8_t indice;
void main(void)
{
TRISD = 0x00;
LATD = 0x00;
indice = 0;
while (1) {
// O acesso a 'padroes[indice]' gera instrucoes TBLPTR/TBLRD,
// enquanto a leitura de 'indice' usa o barramento de dados.
LATD = padroes[indice];
__delay_ms(300);
indice++;
if (indice >= 8) indice = 0;
}
}01_harvard_demo.asm
; Modulo 01 - Tarefa 2: evidencia da arquitetura Harvard modificada.
; A tabela 'PADROES' fica explicitamente em memoria de programa e e
; lida com TBLRD*, separada da RAM onde mora 'INDICE'. Esse contraste
; e o ponto central da analise solicitada na tarefa.
;
; Plataforma: PIC18F4550 + ACEPIC PRO V8.2.
LIST P=18F4550
#include <p18f4550.inc>
CONFIG FOSC=XT_XT, WDT=OFF, LVP=OFF, MCLRE=ON, PBADEN=OFF
CBLOCK 0x00
INDICE
AUX
D1, D2, D3
ENDC
ORG 0x0000
GOTO INICIO
; Tabela em memoria de PROGRAMA. O endereco e carregado em TBLPTR e
; lido com TBLRD, sem ocupar a RAM de dados.
ORG 0x0100
PADROES:
DB 0x01, 0x03
DB 0x07, 0x0F
DB 0x1F, 0x3F
DB 0x7F, 0xFF
ORG 0x0050
INICIO:
CLRF TRISD, ACCESS
CLRF LATD, ACCESS
CLRF INDICE, ACCESS
LOOP_PRINC:
; Carrega TBLPTR com (PADROES + INDICE) usando aritmetica de 16 bits.
MOVLW LOW(PADROES)
MOVWF TBLPTRL, ACCESS
MOVLW HIGH(PADROES)
MOVWF TBLPTRH, ACCESS
MOVLW UPPER(PADROES)
MOVWF TBLPTRU, ACCESS
MOVF INDICE, W, ACCESS
ADDWF TBLPTRL, F, ACCESS
MOVLW 0
ADDWFC TBLPTRH, F, ACCESS
TBLRD* ; lê Flash em TABLAT
MOVF TABLAT, W, ACCESS
MOVWF LATD, ACCESS
INCF INDICE, F, ACCESS
MOVLW d'8'
SUBWF INDICE, W, ACCESS ; W = INDICE - 8
BNZ SEM_RESET
CLRF INDICE, ACCESS
SEM_RESET:
CALL DELAY_300MS
BRA LOOP_PRINC
DELAY_300MS:
MOVLW d'150'
MOVWF D3, ACCESS
DL_3:
MOVLW d'200'
MOVWF D2, ACCESS
DL_2:
MOVLW d'20'
MOVWF D1, ACCESS
DL_1:
DECFSZ D1, F, ACCESS
BRA DL_1
DECFSZ D2, F, ACCESS
BRA DL_2
DECFSZ D3, F, ACCESS
BRA DL_3
RETURN
ENDO entregável exige um quadro classificando os elementos do PIC18F4550 entre arquitetura e organização, e a inspeção do arquivo .map gerado pelo XC8. Ele lista os endereços alocados a cada símbolo. Você vai ver, com os próprios olhos, que padroes[] mora numa faixa baixa (Flash, a partir de 0x000000) enquanto a variável de índice mora em outra faixa (RAM, no Access Bank). Essa observação cristaliza a separação de espaços que, no diagrama, parecia apenas conceitual.
A terceira tarefa fecha o ciclo teoria-medição. Você grava um programa que eleva RD0 antes de um trecho instrumentado e o abaixa depois, observa o pulso no osciloscópio, calcula o tempo teórico pela contagem de instruções do datasheet e compara com a medida.
01_medir_tempo.c
/*
* Modulo 01 - Tarefa 3: medicao empirica do tempo de execucao.
*
* Para tornar visivel o tempo gasto por uma sequencia de instrucoes,
* o programa eleva um pino digital (RD0 / L1) imediatamente antes do
* trecho sob medicao e o abaixa logo depois. A largura do pulso medida
* com osciloscopio (ou logic analyzer) e comparada com o valor teorico
* calculado a partir de Fosc, Tcy e da quantidade de ciclos por
* instrucao informada no datasheet.
*
* Fosc = 8 MHz -> Fcy = Fosc/4 = 2 MHz -> Tcy = 500 ns.
*
* Plataforma: PIC18F4550 + ACEPIC PRO V8.2.
*/
#include <xc.h>
#include <stdint.h>
#pragma config FOSC = XT_XT
#pragma config WDT = OFF
#pragma config LVP = OFF
#pragma config MCLRE = ON
#pragma config PBADEN = OFF
#define _XTAL_FREQ 8000000UL
#define MARCADOR LATDbits.LATD0 // L1 = pino monitorado pelo osciloscopio
static uint16_t acumulador;
static void trecho_medido(void)
{
// 1000 iteracoes de soma simples. O objetivo nao e fazer algo util,
// mas oferecer uma carga de trabalho previsivel para comparacao
// entre tempo teorico e tempo medido.
for (uint16_t i = 0; i < 1000; i++) {
acumulador += i;
}
}
void main(void)
{
TRISD = 0x00;
LATD = 0x00;
acumulador = 0;
while (1) {
MARCADOR = 1; // borda de subida = inicio da medicao
trecho_medido();
MARCADOR = 0; // borda de descida = fim da medicao
__delay_ms(50); // janela morta para o osciloscopio disparar
}
}01_medir_tempo.asm
; Modulo 01 - Tarefa 3: medicao empirica do tempo de execucao em ASM.
;
; O trecho sob medicao executa um numero conhecido de instrucoes de
; um ciclo cada, permitindo calcular com precisao o tempo teorico:
; N_iter * (instrucoes_no_corpo) * Tcy.
; Comparar com o pulso medido em RD0 valida (ou refuta) a hipotese.
;
; Plataforma: PIC18F4550 + ACEPIC PRO V8.2.
LIST P=18F4550
#include <p18f4550.inc>
CONFIG FOSC=XT_XT, WDT=OFF, LVP=OFF, MCLRE=ON, PBADEN=OFF
CBLOCK 0x00
CNT_L
CNT_H
D1, D2, D3
ENDC
ORG 0x0000
GOTO INICIO
ORG 0x0030
INICIO:
CLRF TRISD, ACCESS
CLRF LATD, ACCESS
LOOP_PRINC:
BSF LATD, 0, ACCESS ; borda de subida no L1
; --- Trecho medido: 1000 iteracoes de um decremento de 16 bits ---
MOVLW LOW(d'1000')
MOVWF CNT_L, ACCESS
MOVLW HIGH(d'1000')
MOVWF CNT_H, ACCESS
LACO_MED:
MOVLW 1
SUBWF CNT_L, F, ACCESS
MOVLW 0
SUBWFB CNT_H, F, ACCESS
MOVF CNT_L, W, ACCESS
IORWF CNT_H, W, ACCESS
BNZ LACO_MED
; --------------------------------------------------------------
BCF LATD, 0, ACCESS ; borda de descida no L1
CALL DELAY_50MS
BRA LOOP_PRINC
DELAY_50MS:
MOVLW d'25'
MOVWF D3, ACCESS
DL_3:
MOVLW d'200'
MOVWF D2, ACCESS
DL_2:
MOVLW d'20'
MOVWF D1, ACCESS
DL_1:
DECFSZ D1, F, ACCESS
BRA DL_1
DECFSZ D2, F, ACCESS
BRA DL_2
DECFSZ D3, F, ACCESS
BRA DL_3
RETURN
ENDO entregável inclui tabela de instruções, cálculo teórico, valor medido, erro relativo e discussão das fontes de incerteza. Essa é a primeira tarefa em que você deixa de ser usuário do microcontrolador e age como engenheiro: prevê, mede, confronta.
Configuração física do kit: pontos críticos
Quatro pontos do KIT ACEPIC PRO V8.2 que comem aula de tutoria quando ignorados. O jumper LEDS deve estar fechado para que L1 a L8 acendam quando você escrever em LATD. O jumper J1 na posição 1-2, alimentando o chip com 5 V regulados. Os jumpers JP14 do cristal de 8 MHz fechados na vertical; se abertos, o chip cai no oscilador interno e seu programa parece rodar em frequência errada. O DIP-switch DP2 com as chaves 5 a 8 em OFF — elas controlam os cátodos dos displays de 7 segmentos compartilhados com PORTD.
E tem o diário de projeto, talvez a ferramenta mais valiosa do semestre. Arquivo em Markdown na pasta /docs/diario/ da dupla, atualizado a cada tutoria com data, presentes, atividades, problemas, soluções e plano da semana. Oferece continuidade entre sessões, materializa o aprendizado pelo ato de escrever e serve de evidência para a avaliação contínua. É o caderno de laboratório do engenheiro.
Síntese e o Que Vem Pela Frente
Olha onde a gente chegou. Você partiu de uma distinção aparentemente acadêmica — arquitetura versus organização — e desembocou na configuração física de um microcontrolador real, com tempo medido em osciloscópio. Passou pela história em cinco gerações, pela briga RISC versus CISC, pelos modelos Von Neumann e Harvard (com a modificada do PIC18) e pelas métricas que sustentam as análises dos próximos quatorze módulos.
A pergunta de abertura — como dois processadores com a mesma arquitetura podem diferir cinco vezes em desempenho? — agora tem resposta precisa: arquitetura define o contrato com o programador, organização define o desempenho real. Essa é a tese central do nosso campo.
Antes de virar a página, autoavalie-se. Você deve enunciar as definições operacionais de arquitetura e organização e aplicar a prova do programador. Deve descrever o ciclo de busca-decodificação-execução e identificar o gargalo de Von Neumann numa frase. Deve diferenciar Harvard pura de modificada e justificar a escolha da segunda para o PIC18F4550. Deve calcular o tempo de execução pela equação T = N_{\text{instr}} \cdot \text{CPI} \cdot T_{cy}, sem esquecer da divisão por quatro no clock. Deve aplicar a Lei de Amdahl em cenários típicos. E deve ter, no diário de projeto, o relato da primeira sessão com o LED piscando, o quadro Arq/Org e o pulso medido.
No Módulo 02, mergulhamos na representação de dados e aritmética computacional: complemento de dois, IEEE 754, somadores e multiplicadores. Deixo uma pergunta para o intervalo: por que somar dois números de 16 bits num chip de 8 bits como o PIC18 exige mais de uma instrução, e qual registrador especial entra em cena nessa segunda instrução?
Antes da próxima aula, abra o MPLAB X, compile o programa do LED piscando, conecte o osciloscópio em RD0 e meça a largura do pulso. Compare com o valor que você calcular a partir da contagem de instruções e da relação T_{cy} = 4/F_{osc}. O encontro entre teoria e medição é o ponto de partida do seu trabalho no semestre inteiro.