flowchart LR
IR["Opcode no IR<br/>16 bits da instrucao"] --> UC["Unidade de<br/>controle"]
EST["Estado interno<br/>memoria da FSM"] --> UC
FLAGS["Flags do STATUS<br/>Z, C, DC, OV, N"] --> UC
UC --> SIN["Vetor de sinais<br/>de controle agora"]
UC --> PROX["Proximo estado<br/>interno"]
Exercícios do Módulo 05: Unidade de Controle, Máquinas de Estados e o Pipeline de Dois Estágios
Os três exercícios a seguir foram pensados para você fixar, em ordem crescente de dificuldade, o que estudamos sobre a unidade de controle do PIC18F4550 do seu kit ACEPIC PRO V8.2: como o opcode vira sinais, por que uma instrução afeta certos flags e não outros, a diferença entre controle hardwired e microprogramado, e a aritmética do pipeline de dois estágios com a penalidade de desvio \overline{\text{CPI}} = 1 + f_b. O primeiro pede que você leia o comportamento da unidade de controle a partir do datasheet, instrução por instrução; o segundo exige cálculo quantitativo de CPI e tempo de execução para dois laços; o terceiro liga toda a teoria à máquina de estados de modos de operação que você vai projetar no Projeto Integrador. Resolva cada um antes de comparar com colegas — quem só lê a resolução pronta nunca desenvolve a intuição de prever, no papel, qual fio a unidade de controle ativa em qual sub-ciclo.
Exercício 1: Lendo a Unidade de Controle no Comportamento de Duas Instruções
Nível Básico
Eu quero começar pelo trabalho silencioso que a unidade de controle faz a cada ciclo de máquina dentro do PIC18F4550 do seu kit. Lembre que ela não move dado nenhum: ela só decide, ao ver os dezesseis bits de uma instrução, quais fios do caminho de dados ativar agora e qual será o próximo estado interno. No material vimos isso com duas instruções quase gêmeas. A ADDWF f, d, a tem o opcode no padrão 0010\,01\,d\,a\,fffffffff e, segundo o datasheet, atualiza os flags Z, C, DC, OV e N. A ANDWF f, d, a tem o padrão 0001\,01\,d\,a\,fffffffff e atualiza apenas Z e N.
Este exercício parece simples até você tentar a primeira vez — eu mesmo me embolei, no começo, ao tentar explicar por que o ANDWF não mexe no carry. A ideia é você olhar para essas duas instruções não como programador, mas como arquiteto inspecionando os sinais que a unidade de controle gera para cada uma.
O que peço de você: (a) explique, em prosa, o que cada um dos bits d e a controla no caminho de dados quando a unidade de controle decodifica essas instruções, dizendo qual sinal muda quando d=0 em vez de d=1; (b) compare os sinais gerados para ADDWF e para ANDWF e identifique exatamente qual sinal de controle muda entre as duas e quais permanecem idênticos; (c) explique por que a máscara de flags do ANDWF exclui C, DC e OV, justificando a partir da natureza da operação lógica AND e não como uma regra arbitrária do datasheet; e (d) com base no que vimos sobre DECFSZ f, d, a, que decrementa f e pula a próxima instrução se o resultado for zero, argumente por que a unidade de controle não pode ser puramente combinacional e precisa ter memória interna.
O diagrama abaixo mostra de onde a unidade de controle tira suas três entradas e o que ela produz; é o esqueleto que você vai usar para raciocinar sobre cada item:
Você terá terminado quando conseguir dizer, sem olhar a resolução, qual único sinal separa um ADDWF de um ANDWF e por que a memória interna da unidade de controle é o que torna possível uma instrução de pulo condicional.
Exercício 2: Calculando o CPI e o Tempo de Dois Laços no Pipeline de Dois Estágios
Nível Intermediário
Agora vamos sair da inspeção qualitativa e ir para os números, que é onde a maioria dos enganos sobre desempenho aparece. Trabalhe com o PIC18F4550 do seu kit ACEPIC PRO V8.2 no clock interno de 48 MHz obtido pelo PLL a partir do cristal externo. Como cada ciclo de máquina equivale a quatro sub-ciclos do oscilador, temos T_{cm} = 4 \cdot T_{Qx}, com T_{Qx} = 1/(48 \times 10^6) \approx 20{,}83~\text{ns}, de modo que T_{cm} \approx 83{,}33~\text{ns}. No pipeline de dois estágios, a maioria das instruções conclui em um ciclo de máquina; quando um desvio é tomado, a instrução pré-buscada é descartada e abre-se uma bolha, custando um ciclo adicional. O modelo que derivamos no material é \overline{\text{CPI}} = (1 - f_b)\cdot 1 + f_b \cdot 2 = 1 + f_b, onde f_b é a fração de instruções que são desvios tomados.
Considere dois laços que produzem o mesmo resultado de processamento de leituras do ADC. O laço A tem corpo de dez instruções, das quais exatamente uma é o desvio de retorno tomado a cada iteração. O laço B faz o mesmo trabalho com corpo de duas instruções, das quais uma é o desvio de retorno tomado a cada iteração. Para simplificar, trate todos os desvios de retorno como tomados e todas as demais instruções como de um ciclo.
O que peço de você: (a) calcule a fração f_b de desvios tomados de cada laço e, com \overline{\text{CPI}} = 1 + f_b, obtenha o CPI médio de A e de B, mostrando as contas; (b) supondo que cada laço execute mil iterações, calcule o número total de ciclos de máquina consumidos por cada um e o tempo total em microssegundos usando T_{\text{exec}} = N_{\text{inst}} \cdot \overline{\text{CPI}} \cdot 83{,}33~\text{ns}, lembrando que N_{\text{inst}} é o número de instruções efetivamente executadas; (c) calcule de quanto o throughput do laço B cai em relação ao teto ideal de uma instrução por ciclo e compare com a queda do laço A, explicando por que o mesmo trabalho útil custa proporcionalmente mais no laço de corpo curto; e (d) explique, em duas ou três frases e à luz da assimetria que vimos no material, por que desvios não tomados não pagam penalidade, e por que isso fundamenta a técnica de colocar o caso frequente no caminho não tomado.
O diagrama abaixo contrasta o perfil de custo dos dois laços, que você vai usar para montar a contagem de ciclos:
flowchart TB
A["Laco A<br/>corpo de 10 instrucoes"] --> AB["1 desvio tomado<br/>em 10 instrucoes"]
B["Laco B<br/>corpo de 2 instrucoes"] --> BB["1 desvio tomado<br/>em 2 instrucoes"]
AB --> CPIA["f_b pequeno<br/>CPI proximo de 1"]
BB --> CPIB["f_b grande<br/>CPI bem acima de 1"]
CPIA --> CMP["Compare o tempo total<br/>e a perda de throughput"]
CPIB --> CMP
Você terá terminado quando tiver, em números com unidades, o CPI médio dos dois laços, o tempo total de mil iterações de cada um em microssegundos, o percentual de queda de throughput em relação ao teto ideal, e uma frase ligando a assimetria do desvio à reorganização de código.
Exercício 3: Projetando no Papel a FSM de Modos de Operação e Sua Implementação
Nível Desafiador
Chegou a hora de amarrar a teoria à primeira tarefa do Projeto Integrador deste módulo, em que você vai projetar uma máquina de estados finitos que gerencia os modos de operação do seu sistema de monitoramento no PIC18F4550 do kit ACEPIC PRO V8.2. Pense em três modos — operação normal, configuração e diagnóstico — selecionados por botões ligados ao PORTB do kit, com o modo corrente sinalizado por LEDs do PORTD e, no modo de operação, o valor lido exibido no LCD Sunstar 2004A. No material insisti que projetar essa FSM em C é, do ponto de vista lógico, o mesmo problema que o arquiteto resolve ao desenhar a unidade de controle em silício: mudam só as ferramentas e as restrições.
Quero que você projete a máquina toda no papel — diagrama, tabela e raciocínio de implementação — antes de escrever uma linha de código, porque é exatamente esse o entregável formal que vou exigir antes da codificação. Há decisões de modelagem que separam uma FSM robusta de uma que trava no laboratório, e elas são o coração deste exercício.
O que peço de você: (a) decida e justifique se a sua FSM seguirá o modelo de Moore ou de Mealy, conectando a escolha ao que vimos sobre estabilidade dos sinais e ausência de glitches, e relacione isso ao fato de o próprio PIC18F4550 adotar o modelo de Moore na unidade de controle; (b) desenhe o diagrama de estados com pelo menos os três modos e construa a tabela de transições completa, com cada linha indicando estado atual, entrada de botão, próximo estado e a ação de saída associada — garantindo que todo estado tenha uma transição definida para toda entrada possível, inclusive a permanência no estado atual como caso padrão; (c) explique como você usaria a interrupção de Timer0 para fazer o debouncing dos botões do PORTB e entregar à FSM apenas eventos já filtrados, e por que misturar debounce com a lógica de transição é uma das armadilhas que vimos; e (d) descreva, formalmente, como a sua tabela de transições corresponde à função \delta : Q \times \Sigma \to Q e a saída à função \lambda de Moore, e como essa mesma tabela poderia ser implementada tanto por um switch quanto por uma matriz bidimensional indexada por estado e entrada, comentando a diferença de custo entre as duas formas.
O diagrama abaixo mostra um esqueleto possível de transições entre os três modos, que você vai completar e formalizar com a tabela:
stateDiagram-v2
[*] --> Normal
Normal --> Config: botao MODO
Config --> Diagnostico: botao MODO
Diagnostico --> Normal: botao MODO
Normal --> Normal: sem evento
Config --> Config: ajuste
Diagnostico --> Diagnostico: leitura
Quando o seu diagrama, a sua tabela de transições e a sua justificativa do modelo de Moore formarem um conjunto coerente — de modo que outro colega consiga implementar a FSM em C a partir só do que você documentou, sem adivinhar nenhuma transição — você terá o critério de pronto deste exercício, que é justamente a representação formal que precede a codificação na tarefa do projeto.
Orientações para Resolução
O propósito destes exercícios não é só chegar ao resultado certo, mas treinar seu raciocínio sobre a ponte entre a matemática das máquinas de estados e o silício que a executa. Antes de resolver qualquer coisa, releia, no material do módulo, as seções sobre o papel da unidade de controle, as máquinas de Moore e Mealy, o modelo de CPI do pipeline de dois estágios e a forma canônica de FSM em C.
Para o exercício básico, trate o datasheet como uma especificação da unidade de controle e não como uma lista de regras a decorar — pergunte sempre “por que esse fio é ativado aqui?”. Para o intermediário, escreva todas as contas com unidades, sem pular etapas, e confira se o CPI obtido faz sentido em relação ao piso de um ciclo. Para o desafiador, transcreva o diagrama em tabela antes de pensar em código e teste mentalmente cada entrada em cada estado, procurando a transição que você esqueceu de definir.
Discuta suas soluções com os colegas do seu grupo e traga suas dúvidas para a aula teórica, onde vamos comparar as escolhas de modelagem de cada um e ligar o que vocês previram no papel ao comportamento real do kit.