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.

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 percurso do módulo: dos fundamentos conceituais à prática no kit.

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

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
Figura 3: As cinco gerações segundo a tradição da literatura clássica.

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

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

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

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"]
Figura 7: Pipeline de dois estágios em regime permanente: uma instrução concluída por ciclo de máquina.

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

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

    END

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

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

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

    END

O 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

    END

O 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

    END

O 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.