Módulo 1: Fundamentos de Arquitetura e Organização de Computadores — Resumo

Olha só: dois Intel x86, mesmo binário, e um termina cinco vezes antes do outro. Mesma arquitetura, desempenhos completamente diferentes. Por quê? A resposta cabe em duas palavras que a literatura técnica mistura — arquitetura e organização — e que neste módulo a gente separa de vez.

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"]
Figura 1: Mapa do módulo: das definições até a primeira medição no kit.

Arquitetura e Organização

Vou direto. Arquitetura é o que você, programador, enxerga do hardware: instruções, registradores nomeáveis, modos de endereçamento, modelo de memória, mecanismos de exceção, E/S. É um contrato público — o fabricante diz “estas instruções existem e fazem isso”, e seu código depende disso. Organização é como o fabricante implementou o cardápio por dentro: pipeline, caches, frequência, larguras de barramento, tecnologia das memórias. Duas organizações diferentes podem implementar a mesma arquitetura — foi assim que a IBM montou o System/360 em 1964, com modelos baratos e caríssimos rodando o mesmo programa.

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
Figura 2: As duas camadas: o programador só enxerga a arquitetura; a organização fica oculta atrás do contrato.

Tem um truque que eu chamo de prova do programador e ele resolve quase tudo: se você muda um detalhe e o resultado lógico de algum programa correto muda junto, é arquitetura; se só muda tempo, consumo ou custo, é organização. Olha o Core i9-13900K e o i3-13100: os dois são x86-64, o binário roda nos dois. Arquiteturalmente, irmãos. Por dentro, o i9 tem mais núcleos, mais cache, clock maior, pipeline maior. Organizações em outro planeta. Aí está a resposta da abertura.

Pensa rápido: se eu trocar a SRAM de 2 KB do PIC18F4550 por uma de 8 KB sem mexer no mapa de endereçamento visível ao programador, isso muda arquitetura ou organização? Aplica a prova do programador.

E ainda tem a microarquitetura, dentro da organização, descrevendo como o processador implementa internamente a arquitetura — pipeline, execução fora de ordem, unidade de controle. Cuidado com o marketing: “arquitetura Skylake” ou “arquitetura M2” são, no rigor que a gente adota, microarquiteturas dentro das famílias x86-64 e ARMv8-A. Voltam nos Módulos 04 e 05.

Gerações e a Briga RISC versus CISC

Por que história numa disciplina técnica? Porque cada inovação arquitetural respondeu a uma limitação tecnológica concreta — e entender a limitação é o jeito 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
Figura 3: As cinco gerações segundo a tradição da literatura clássica.

A primeira geração (1940–1955) é a das válvulas: o ENIAC era programado por reconexão de cabos, e foi em 1945 que von Neumann formulou no EDVAC o programa armazenado. A segunda trouxe transistores discretos, FORTRAN e COBOL. A terceira (1960–1970) trouxe circuitos integrados, o System/360 e a microprogramação. A quarta começou em 1971 com o Intel 4004 e viabilizou o PC. A quinta, dos anos 1980 em diante, é a do VLSI e da computação ubíqua. O PIC18F4550 da sua mesa, projetado por volta de 2007, é típico da quinta — mas executa internamente um modelo conceitual de 1945. A história do nosso campo é cumulativa.

A briga RISC versus CISC vale uma nota. CISC (VAX-11, x86) apostou em conjuntos enormes para reduzir o trabalho do compilador. Patterson e Hennessy perceberam que os compiladores só usavam um subconjunto pequeno e propuseram o contrário: poucas instruções simples, tamanho fixo, um ciclo cada, memória só via load/store. O PIC18F4550 é híbrido — instrução de 16 bits de tamanho fixo (RISC), mas 75 instruções com várias misturando memória e aritmética como ADDWF (CISC). Desfecho pragmático: x86 modernos traduzem para micro-operações RISC, e ARM/RISC-V acumularam extensões que os aproximaram do CISC.

Von Neumann e a Harvard Modificada do PIC

A invenção que justifica o nome é brutal: instruções são números, ficam na mesma memória dos dados, lidas do mesmo jeito. Antes do EDVAC, programar era religar cabos por horas; com programa armazenado, programa virou dado, e isso destrava compiladores e sistemas operacionais. O modelo tem cinco subsistemas — unidade de controle, ULA, registradores, memória principal e E/S — e roda o ciclo de busca-decodificação-execução: o PC aponta a próxima instrução, a memória devolve, o IR recebe e decodifica, e o PC é incrementado ou alterado por desvio.

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
Figura 4: Modelo de Von Neumann: memória única, barramento único, serialização forçada entre busca e dado.

Tem uma pegadinha: instrução e dado dividem o mesmo barramento, então a CPU não busca uma instrução e lê um dado no mesmo instante. Backus, no Turing de 1977, batizou isso de gargalo de Von Neumann:

\tau \geq \tau_p + 2\,\tau_m,

porque cada instrução exige buscar a instrução e mais um acesso ao dado. Quando \tau_m engole \tau_p — situação que virou regra — a CPU passa a maior parte do tempo esperando. É a memory wall. Em CPU de propósito geral, a saída foi a hierarquia de caches do Módulo 09. Em microcontrolador, foi outra: trocar o modelo.

A Harvard mantém instruções e dados em memórias fisicamente separadas, cada uma com seu barramento. O nome vem do Mark I de Howard Aiken, de 1944. Num mesmo ciclo, o processador busca uma instrução e lê ou escreve um dado, sem briga. No PIC18 as larguras diferem — instrução tem 16 bits, dado tem 8 — e as tecnologias também: Flash para instrução, SRAM para dado. Daí sai, em regime permanente, uma instrução por ciclo de máquina sem cache.

Mas a Harvard pura tem um problema: tabelas e constantes grandes não cabem na RAM, e ocupariam RAM mesmo sendo imutáveis. Desastre num embarcado. A Harvard modificada do PIC18 resolve com instruções específicas que leem bytes da memória de instruções como se fossem dados: TBLRD*, TBLRD*+, TBLRD*- e TBLRD+*, via ponteiro TBLPTR com retorno em TABLAT. Na prática, ao declarar static const uint8_t tabela[] = {...} em C, o XC8 aloca em Flash e emite essa sequência sozinho.

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
Figura 5: Harvard modificada do PIC18F4550: dois espaços principais, duas vias paralelas e a EEPROM como terceiro espaço com protocolo próprio.

Tem ainda um terceiro espaço no PIC18: a EEPROM de 256 bytes para dados que sobrevivem ao desligamento, acessada por EECON1/EECON2. Curiosidade: o x86 moderno, para o programador, é Von Neumann — uma memória só. Mas as caches L1 dele são separadas em instrução e dado, organização de inspiração harvardiana. Arquitetura Von Neumann, organização mista — a prova do programador resolve o paradoxo numa frase.

O PIC18F4550 como Estudo de Caso

Por que esse chip? Regularidade ortogonal (75 instruções, quase todas de um ciclo, codificação fixa de 16 bits) que permite estudar a ISA inteira em um módulo; periféricos integrados (ADC, USB, UART, SPI, I²C, comparadores, timers) no mesmo datasheet; timing previsível, sem cache nem execução fora de ordem, com tempo de execução calculável no papel; e o KIT ACEPIC PRO V8.2, barato e robusto.

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
Figura 6: Anatomia em blocos do PIC18F4550: núcleo com ULA, W e STATUS, três memórias, periféricos integrados e cadeia de clock.

A CPU traz unidade de controle, ULA de 8 bits, WREG e STATUS com cinco flags (Carry, Digit Carry, Zero, Overflow, Negative). A Flash de 32 KB guarda 16 K palavras de 16 bits, reprogramável in-circuit. A SRAM de 2 KB se organiza em 16 bancos via BSR, com o Access Bank combinando 96 bytes da RAM e 160 bytes de SFRs. Os periféricos: dois MSSP, EUSART, USB 2.0 full-speed, ADC de 10 bits, três comparadores, quatro timers, dois CCP e 35 pinos de I/O.

Aplica a prova do programador — é a base da Tarefa 3 do Projeto Integrador. As 75 instruções, o WREG, os flags, os três espaços de memória, SFRs como TRISx, LATx e ADCONx são arquitetura. Já o pipeline de dois estágios, o Access Bank, a largura física do barramento, o cristal externo, a divisão por quatro, a PLL do USB são organização. Trocar a SRAM por uma mais rápida muda só tempo.

O ciclo de instrução compacta as cinco fases conceituais em dois estágios físicos, fetch e execute, porque a Harvard permite buscar a próxima instrução enquanto a atual executa. Após a latência inicial de um ciclo, conclui-se uma instrução por ciclo de máquina. A exceção são as que mexem no PC — GOTO, CALL, BRA tomado, RETURN, RETFIE, BTFSS/BTFSC causando skip. Nessas, o prefetch trouxe a instrução errada e é descartado, e o CPI vira 2. Decora, porque cai.

Métricas de Desempenho

Quando alguém te disser que um processador é “duas vezes mais rápido”, devolve a pergunta: em qual carga, qual compilador, qual frequência, medindo o quê? Sem isso, “mais rápido” é palavra vazia. A equação central da disciplina é:

T = N_{\text{instr}} \cdot \text{CPI} \cdot T_{cy}.

Cada fator depende de uma camada: N_{\text{instr}} depende do algoritmo e do compilador; CPI depende da arquitetura, da microarquitetura e da mistura de instruções; T_{cy} depende exclusivamente da organização. Otimizar é atacar os três ao mesmo tempo.

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
Figura 7: Cadeia de clock do PIC18: o cristal externo Fosc é dividido por 4 para gerar o clock de máquina Fcy.

Detalhe do PIC18 que cai em prova: o cristal externo gera F_{osc}, mas um divisor por quatro produz o clock de máquina F_{cy} = F_{osc}/4. Para o cristal de 8 MHz do KIT, F_{cy} = 2 MHz e T_{cy} = 500 ns. Trocar F_{osc} por F_{cy} é o erro mais frequente da disciplina e dá previsão quatro vezes menor que a medida. Para uma mistura com frequências f_i e CPIs c_i,

\text{CPI}_{\text{médio}} = \sum_i f_i \, c_i.

Um programa com 90% de instruções de CPI 1 e 10% de desvios tomados (CPI 2) tem CPI médio 1,10; a 8 MHz, com 10 000 instruções, dá 5,5 ms. O conceito gêmeo é o throughput: IPC = 1/\text{CPI}, e no PIC18, em pipeline cheio, fica próximo de 1. Superescalares chegam a IPC maior que 1 — Módulo 15. Pra tornar o efeito palpável, um pulso em RD0 delimitando um laço de soma — padrão que volta nas tarefas do Projeto Integrador.

#include <xc.h>
void main(void) {
  TRISD = 0x00; LATD = 0x00;
  uint16_t s = 0;
  LATDbits.LATD0 = 1;
  for (uint8_t i = 0; i < 100; i++) s += i;
  LATDbits.LATD0 = 0;
  while (1);
}
    BCF   TRISD, 0, A        ; RD0 como saida
    CLRF  CONT, A
    BSF   LATD,  0, A        ; sobe pulso
LOOP
    INCF  CONT, F, A
    MOVF  CONT, W, A
    SUBLW d'100'
    BNZ   LOOP
    BCF   LATD,  0, A        ; desce pulso
    BRA   $

A Lei de Amdahl é a lição quantitativa mais importante daqui. Pergunta natural: se você acelera uma fração f do tempo por um fator k, qual o ganho global? Gene Amdahl, 1967, respondeu assim:

S = \frac{1}{(1-f) + \dfrac{f}{k}}.

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
Figura 8: Geometria da Lei de Amdahl: a fração não acelerada estabelece o teto do speedup global.

No limite k \to \infty, o teto é S_{\max} = 1/(1-f). Lê de novo: acelerar infinitamente 90% do tempo dá speedup de apenas dez vezes, porque os 10% restantes seguem consumindo o mesmo absoluto. Acelerar por dez uma fração de 50% dá 1,82, não 5,5. Na prática, otimização vale a pena onde o programa gasta tempo, e o ganho global tem teto na fração não otimizada. Antes de otimizar, pergunta: que fração do tempo essa rotina consome?

A Lei de Gustafson (1988) é o contraponto: quando o problema cresce com os recursos, o speedup escalado vale (1-f) + k\cdot f, sem o teto rígido. Amdahl é strong scaling; Gustafson, weak scaling. Em embarcado, o problema é dado pela aplicação, então Amdahl pesa mais. Em data center, Gustafson.

Se um programa gasta 30% do tempo em E/S sequencial obrigatória e 70% em laço puramente computacional, qual o speedup máximo teórico mesmo paralelizando o laço infinitamente? Faz a conta agora. É exatamente o tipo de pergunta que cai na prova.

Da Teoria ao Kit: o Projeto Integrador do Módulo

A cadeia que conecta seu código C ao silício tem cinco blocos: MPLAB X IDE; XC8 traduzindo C em código de máquina; pic-as fazendo o mesmo a partir de assembly puro; arquivo .hex no formato Intel HEX; gravação via bootloader (AN1310 ou ACEPIC Terminal pela USB) ou via PICkit no header ICSP. Cada elo é candidato a travar.

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
Figura 9: Cadeia de ferramentas do PIC18: do código-fonte ao silício.

A primeira tarefa é pôr a cadeia em pé e gravar um programa que pisca os oito LEDs em sequência — PORTD como saída, 500 ms entre acionamentos. O programa é trivial; o aprendizado está no entorno: driver CH340G, MPLAB X compatível, XC8 reconhecendo o PIC18F4550, jumpers no lugar, bootloader íntegro. Quatro pontos do kit comem aula quando ignorados: jumper LEDS fechado (senão L1–L8 não acende); jumper J1 na posição 1-2 alimentando o chip com 5 V; jumpers JP14 do cristal de 8 MHz fechados na vertical (senão o chip cai no oscilador interno e o programa parece rodar em frequência errada); DIP-switch DP2 com chaves 5 a 8 em OFF, que controlam cátodos de displays compartilhados com PORTD.

A segunda tarefa pede evidência empírica da Harvard modificada. Você grava um programa que define uma tabela de oito padrões em const uint8_t (Flash) e um índice em RAM; a cada iteração, o byte é lido via TBLRD e escrito em LATD. O entregável traz o quadro Arq/Org do PIC18F4550 e a inspeção do .map, onde padroes[] aparece em endereços baixos (Flash, a partir de 0x000000) e o índice em outra faixa (RAM, no Access Bank). A separação conceitual vira dois conjuntos disjuntos de endereços.

A terceira tarefa fecha o ciclo teoria-medição. Você eleva RD0 antes de um trecho instrumentado, abaixa depois, mede o pulso no osciloscópio e compara com o tempo teórico pela contagem de instruções. O entregável traz tabela de instruções, cálculo teórico, valor medido, erro relativo e fontes de incerteza. Aqui você age como engenheiro: prevê, mede, confronta. E lembra do diário de projeto em /docs/diario/ — pesa na avaliação contínua.

Síntese

Você saiu de uma distinção aparentemente acadêmica — arquitetura versus organização — e desembocou na configuração física de um microcontrolador real, com pulso medido no osciloscópio. A pergunta da abertura, sobre os dois Intel diferindo cinco vezes, tem resposta precisa: arquitetura define o contrato com o programador, organização define o desempenho real. Faz um teste rápido: enuncia arquitetura e organização e aplica a prova do programador; descreve o ciclo de busca-decodificação-execução; identifica o gargalo de Von Neumann; diferencia Harvard pura de modificada; calcula T = N_{\text{instr}} \cdot \text{CPI} \cdot T_{cy} sem esquecer da divisão por quatro do clock; aplica Amdahl. Se travar, volta no Módulo 1. No Módulo 2 vamos para representação de dados e aritmética. Provocação: por que somar dois números de 16 bits num chip de 8 bits exige mais de uma instrução, e qual registrador especial entra em cena na segunda?

Antes da próxima aula, abre o MPLAB X, compila o pisca-LED da Tarefa 1, conecta o osciloscópio em RD0 e mede a largura do pulso. Compara com o valor que você calcular pela contagem de instruções e pela relação T_{cy} = 4/F_{osc}. O encontro entre teoria e medição é o ponto de partida do seu trabalho no semestre inteiro.