Nesta aula, aprenderemos sobre os elementos de um microprocessador e como ele funciona.
Na aula anterior, explicamos o que é um microcontrolador e o que o diferencia de um microprocessador, bem como explicamos o objetivo deste curso de microcontroladores.
Informações básicas
Obs.: Microprocessador e processador significam a mesma coisa.
Na aula passada, vimos a seguinte explicação de microprocessador: “É um circuito digital capaz de executar instruções previamente estabelecidas”.
Estas instruções são códigos binários que o microprocessador interpreta para executar certas operações internas. Isto inclui: operações algébricas entre dois números, testes lógicos, manipulação da memória e entre outras operações. E um conjunto de instruções é que formam um código (um procedimento mais complexo). Mais a frente veremos exemplos de instruções.
Aliado ao processador, existem as memórias que ficam externas ao circuito. Elas podem ser responsáveis por:
- Armazenar as instruções a serem executadas.
- Armazenar dados temporários (ex: o resultado numérico de uma instrução).
Memórias
Para entender melhor alguns conceitos envolvendo as memórias, irei fazer um breve comentário a respeito.
Existem as memórias primárias e as secundárias. As secundárias incluem os: HDs, SSD etc (não é o foco). E as primárias são:
- Memória RAM:
- Realiza escrita e leitura.
- É volátil – Os dados não são retidos se a alimentação for desligada.
- Tipos: SRAM, DRAM.
- Memória ROM:
- Realiza gravação e leitura.
- É não volátil – Os dados são retidos mesmo se a alimentação for desligada.
- Tipos: MROM, PROM, EPROM, EEPROM, FLASH.
Uma diferença considerável entre as duas, além da retenção dos dados, é a diferença entre a escrita e gravação dos dados. A essência dos dois é a mesma: armazenar um dado na memória. Entretanto, enquanto o processo de escrita pode demorar dezenas de nanosegundos, a gravação pode demorar dezenas de milissegundos.
Portanto, isto faz com que a memória RAM seja extremamente mais rápida. E, por isto, é empregada nos microprocessadores para armazenar dados temporários.
Já no caso das instruções, podem ser empregadas as memória ROM. Isto porque as instruções precisam continuar na memória mesmo que o dispositivo (processador + memoria + etc) seja desligado. Caso contrário, se o dispositivo fosse desligado, ele não ia fazer mais nada, pois ia perder as instruções (o “código”).
Registrador
Tendo em vista os conceitos que vimos no tópico anterior, podemos entender agora o que é um registrador.
Um registrador nada mais é do que um espaço de memória que ocupa n bytes. Este valor n pode depender da arquitetura do microprocessador: se for um processador de 8 bits, o registrador ocupa 1 byte. Se for de 16 bits, ocupa 2 bytes. E assim em diante. Entretanto, podem existir exceções: em um microprocessador de 8 bits, podem existir registradores de 2 bytes.
Quando estamos falando de microcontroladores, normalmente o registrador diz respeito a um espaço de 1 byte (8 bits). Isto porque muitos microcontroladores (os mais simples) possuem um processador de 8 bits.
Endereço de memória
Uma informação importante sobre as memórias são os endereços. O endereço serve para acessar uma posição de memória específica.
Vamos dar um exemplo de uma suposta memória de 256 bytes. Esta memória é capaz de armazenar 256 bytes de dados os quais podem ser acessados individualmente.
Mas, para isto, utiliza-se um endereço. Este é um número, normalmente indicado em hexadecimal (convenção), que serve para indicar uma determinada posição da memória. O endereço 0x00 acessa a primeira posição da memória; 0x01 a segunda … 0x0A a décima primeira … e 0xFF a última.
Instruções de um microprocessador
Para finalizar a introdução, é importante explicar um pouco melhor as instruções.
A criação de uma sequência de instruções gera um algorítimo (que executa determinada tarefa). E, para gerar esta sequência utilizando as instruções do processador diretamente, utiliza-se a linguagem de programação chamada Assembly.
Nesta linguagem, os comandos existentes são específicos para cada processador que você irá programar (embora possam existir comandos parecidos). E estes comandos são transcritos diretamente para as instruções que o microprocessador executará. Esta programação direta é chamada de código de máquina (pois são os códigos que o processador de fato entende). Portanto, é uma linguagem extremamente eficiente (rápida e que ocupa menos memória possível).
Na linguagem de programação C, por exemplo, existem comandos (palavras) padronizados que servem para criar algorítimos para inúmeros processadores diferentes utilizando o mesmo código. Entretanto, um código escrito em C (ou qualquer outra linguagem) tem que ser traduzido para as instruções específicas do processador alvo. Esta tradução é feita por um compilador. E a tradução de uma linguagem não é tão eficiente quanto a programação direta em Assembly, pois este processo de tradução não é 100% eficiente (adiciona redundâncias).
O código de máquina é chamado de baixo nível e quanto mais distante uma linguagem de programação for dele, mais alto nível ela será (menos eficiente). Entretanto, as linguagens que não são totalmente baixo nível possuem diversas vantagens que fazem esta ineficiência ser menos relevante (um exemplo é o Python). A própria linguagem C ainda é bastante eficiente (baixo nível) e possui uma série de vantagens sobre o Assembly (principalmente facilidade de desenvolvimento). Com isto, ela é escolhida como a principal forma de programação de microcontroladores em diversas situações.
Organização do microprocessador
Visão geral
Um microprocessador possui 3 principais elementos: Unidade Lógica e Aritmética (ALU), Lógica de Controle e Registradores. Estes 3 elementos formam a chamada CPU (Unidade Central de Processamento).
Nos tempos atuais, normalmente quando se fala de CPU, imagina-se um processador de vários núcleos. Entretanto, iremos trabalhar em cima de um microprocessador simples de 1 núcleo. Isto é, um processador que possui apenas uma ALU e uma lógica de controle (e alguns registradores, claro).
Veja a imagem abaixo que ilustra o que foi falado acima:
Além do que foi comentado, apareceram dois outros blocos: dispositivos de entrada e saída. Estes dispositivos simbolizam os periféricos que podem aparecer conectados à CPU. Na aula passada comentamos um pouco sobre estes periféricos.
Enfim, vamos entender agora o que são os elementos que estão dentro da CPU.
ALU (Unidade Lógica e Aritmética)
A ALU é um circuito interno da CPU responsável por fazer operações de soma, substração, multiplicação, divisão, comparação lógica (maior, menor, igual) e operações bit a bit (AND, OR, NOT). Mas não são todos os processadores que possuem uma ALU capaz de realizar todas estas funções.
De todo modo, qualquer instrução que envolver uma operação matemática irá passar pela ALU.
Lógica de Controle
A lógica de controle é o circuito que garante todo o fluxo de funcionamento da CPU. Este fluxo envolve:
- Fetch (busca):
- Processo de buscar uma nova instrução para ser executada.
- Decode (decodificar):
- Processo de interpretar o que a instrução quer dizer.
- Execution (execução):
- Processo de executar a instrução.
Estes três passos são executados continuamente de forma sequencial (fetch -> decode -> execution -> fetch -> …).
Estes passos serão vistos com mais detalhes no tópico sobre o funcionamento do microprocessador.
Registradores
Os registradores são responsáveis por armazenar dados temporários relacionados à operação momentânea da CPU. Um conjunto deles pode ser utilizado para armazenar o resultado de alguma operação matemática, que são os registradores de propósito geral. No caso dos processadores AVR, existem 32 deles.
E, os demais registradores são dedicados a certas funções que veremos nos tópicos seguintes.
Mas, qual a necessidade destes registradores se existe a memória externa? A explicação é devido a velocidade de acesso. Mesmo que a memória RAM externa seja rápida, é mais rápido ainda acessar estes registros internos do que a memória externa.
Registradores dedicados
Program Counter (PC)
O PC é um registrador que armazena o endereço de memória da próxima instrução a ser executada. Este registrador serve para a CPU acompanhar o fluxo das instruções.
Current Instruction Register (CIR)
O CIR é um registrador que armazena a instrução que está sendo executada no momento.
Acumulador
ALGUNS microprocessadores antigos, ao invés de possuírem diversos registradores de propósito geral, possuíam um registrador chamado acumulador (Accumulator). O acumulador servia para armazenar o resultado de operações intermediárias da ALU.
Registrador de Status (SR)
O SR é um registrador que armazena algumas informações da última operação aritmética executada. Ele possui diversos bits (chamados flags), por exemplo:
- Overflow flag: Indica que o resultado da operação “transbordou” o tamanho dos bits utilizados na operação. (Ex: o resultado é um número de 9 bits, mas a operação envolveu dois números de 8 bits).
- Zero flag: Indica que a operação resultou em 0 (zero).
- Negative flag: Indica que a operação resultou em um número negativo.
Entre outras flags…
Memory Address Register (MAR)
O MAR é um registrador que armazena o endereço de memória para ser lido ou escrito. Isto é, ele que fornece o endereço da memória para ser acessada.
Memory Data Register (MDR / MBR)
O MDR é um registrador que armazena o dado que foi lido ou que é para ser escrito na memória.
Isto é, se a CPU estiver lendo a memória, o MDR conterá o valor lido do endereço dado pelo MAR. E, se a CPU estiver escrevendo na memória, o MDR conterá o valor a ser escrito no endereço dado pelo MAR.
Barramentos de um microprocessador
Para que os diferentes elementos do microprocessador funcionem e se comuniquem, existem os barramentos, que são as ligações físicas entre estes elementos. O primeiro é o barramento de alimentação, que é de onde vem a energia do sistema.
O restante dos barramentos são um conjunto de várias ligações paralelas (vários bits). E cada barramento pode ter um tamanho de bits diferentes. Dentre eles, temos:
- Endereço:
- Interliga a CPU à memória externa
- Serve para a CPU introduzir um endereço da memória para que:
- Ou o dado guardado neste endereço seja retornado no barramento de dados.
- Ou então para que seja possível gravar um dado neste endereço.
- O tamanho deste barramento depende do tamanho da memória. Ex: Se for um barramento de 16 bits, a CPU pode acessar 65.536 espaços de memória (2^16 combinações). isto é 65.536 bytes de memória.
- Dados:
- Interliga a memória à CPU.
- É o barramento que retorna os dados da memória de acordo com o endereço introduzido no barramento de endereço.
- Ou então é o barramento que contém o dado para ser guardado em um endereço da memória.
- O tamanho deste barramento normalmente é ditado pelo tipo do processador (se é 8/16/32 ou 64 bits).
- Controle:
- Interliga a Lógica de Controle aos demais elementos da CPU.
- Serve para o circuito da Lógica de Controle obter status de algumas coisas e para ele controlar a CPU.
Funcionamento básico do microprocessador
Para entender o funcionamento do processador por completo, recomendo este vídeo que é muito bem explicado e didático. Recomendo também dar uma olhada na animação deste site, que mostra o passo a passo do funcionamento.
De todo modo, vou dar uma explicação simplificada adiante.
Instruções
Agora, vamos ver alguns exemplos de instruções em Assembly para entender esta parte melhor. Conforme foi falado, as instruções variam de processador para processador. Mas, como referência, vou utilizar a arquitetura dos microprocessadores dos microcontroladores AVR. Neste link, você pode acessar um manual contendo todas as instruções do AVR.
Enfim, uma das instruções disponíveis é a LDI. Esta instrução serve para carregar uma constante (número) de 8 bits em um registrador de propósito geral. Seu formato é o seguinte:
LDI Rd,K
Onde: Rd é o registrador de propósito geral e pode ir de R16 à R31. E K é o número de 8 bits.
As instruções no AVR são códigos binários de 16 bits. No caso do LDI, o código é o seguinte:
1110 KKKK dddd KKKK
As letras K correspondem aos bits da constante (8 bits) e as letras d correspondem ao número do registrador (4 bits -> faixa de 16 à 31).
Outra instrução existente é a ADD que adiciona os valores de dois registradores de propósito geral e armazena o resultado em um deles. Seu formato é o seguinte:
ADD Rd,Rr
Onde: Rd e Rr são os registradores de propósito geral e podem ir de R0 à R31. O resultado da adição é armazenado no registrador Rd. Veja o código binário correspondente no manual das instruções.
Agora, vamos ver o exemplo de um programa que soma os números 6 e 8:
LDI R16,0x6 // Carrega 6 no registrador R16
LDI R17,0x8 // Carrega 8 no registrador R17
ADD R16,R17 // Soma os registradores R16 e R17
No fim da execução do código acima, o registrador R16 conterá o resultado da soma: 14 ou 0xE.nú
Funcionamento - Estado inicial
Vamos utilizar a imagem abaixo como referência para a explicação.
Na imagem acima, para simplificar o entendimento, estou considerando apenas uma memória externa, que armazena tanto as instruções quanto eventuais dados temporários.
Considere o seguinte estado inicial:
- A memória externa contém instruções quaisquer (adicionar números, carregar/ler valores etc).
- O Program Counter está apontando para o endereço 0 (1ª instrução).
Funcionamento - Passo a passo
A partir do estado inicial, o microprocessador executará as seguintes etapas de forma consecutiva:
- O valor do Program Counter (inicialmente 0) é transferido para o Memory Address (MAR) para que a primeira instrução seja extraída da memória.
- A Lógica de Controle manda um sinal para a memória permitindo que o endereço 0 (MAR) seja lido da memória.
- A memória retorna a instrução contida no endereço 0. E esta instrução é retornada no registrador Memory Data (MDR).
- A instrução é transferida do MDR para o registrador Current Instruction.
- O conteúdo do CIR é enviado à Lógica de Controle para que ele decodifique a instrução.
- Antes de decodificar, a Lógica de Controle incrementa o PC em 1 para ele apontar para a próxima instrução.
- A instrução é decodificada e, dependendo de qual for ela, o processo pode seguir diferentes caminhos.
- Se for uma instrução aritmética, a Lógica de Controle mandará o(s) valor(es) contidos nos Registradores de Propósito geral para a ALU. Com isto, a ALU será executada gerando as flags para o Registrador de Status que podem ou não ser usados de volta pela Lógica de Controle. Além das flags, o resultado gerado pela ALU pode ser armazenado de volta nos Registradores de Propósito Geral.
- Se for uma instrução para ler um valor da memória, a Lógica de Controle carregará o MAR com o endereço desejado. Com isto, ela manda um sinal para a memória e o valor é carregado no MDR. E, em seguida, ele é armazenado em algum Registrador de Propósito Geral.
- Se for uma instrução para escrever um valor na memória, a Lógica de Controle carregará o MAR e o MDR com o endereço e o valor desejado respectivamente. Com isto, ela manda um sinal para a memória indicando a escrita.
Funcionamento - Ciclo
Depois de todo o procedimento anterior, o microprocessador retorna ao passo 1, porém agora o PC aponta para o endereço 1 (2ª instrução). E este processo se repete ciclicamente.
O funcionamento varia de processador para processador, pois cada um tem um conjunto de instruções diferente e uma arquitetura diferente. Mas a essência é a mesma.
Arquiteturas: 8 / 16 / 32 / 64 bits
Nos tópicos anteriores, comentei indiretamente das diferenças existentes entre os microprocessadores de 8/16/32 ou 64 bits. Agora vamos ver em detalhes.
Barramento de dados
A principal delas é no barramento de dados. Enquanto um processador de 64 bits consegue trabalhar com dados de 64 bits diretamente, um de 8 bits consegue trabalhar com dados de apenas 8 bits por vez. Com 8 bits você só forma números de 0 a 255, o que é uma faixa bem limitada. Portanto, processadores de 8 bits são mais restritos.
Para entender melhor as diferenças, vamos responder a seguinte pergunta: Como somar dois números de 16 bits em um microprocessador de 8 bits?
Bem, você teria que segmentar a soma em duas partes, uma somando os 8 primeiros bits e a outra somando os últimos 8 bits. Na segunda soma teríamos que utilizar uma soma que leva em conta os bits de carry da soma anterior para considerar o valor extrapolado da primeira soma.
Ou seja, enquanto um processador de 16 bits faria esta soma em “uma etapa” um processador de 8 bits gastaria o “dobro” de instruções.
Sendo assim, quanto mais bits tem o processador, mais rápido e eficiente ele será.
Barramento de endereço
Outra diferença é no barramento de endereçamento da memória. Um processador de 32 bits consegue acessar até 4G bytes da memória (2^32). Isto, em computadores modernos é pouco, pois existem computadores com até 64GB de memória RAM. Ou seja, utilizar um processador de 64 bits te permite utilizar mais memória RAM (até 18 milhões de terabytes).
E isto implica em executar os programas mais rápido, pois eles executando na RAM são mais rápidos do que no seu disco.
Então, se você tiver mais de 4GB de RAM e um processador de 64 bits, não faz sentido utilizar a versão 32 bits do Windows (exemplo), pois você estará subutilizando sua RAM.
Diferentes tipos arquiteturas de um microprocessador
Organização dos barramentos
A estrutura do barramento de um microprocessador pode definir o tipo de arquitetura do mesmo. E as duas principais são:
- Arquitetura Von Neumann:
- Arquitetura onde existe apenas um barramento para dados e instruções.
- Esta é arquitetura que foi utilizada para explicar os microprocessadores ao longo desta aula.
- Arquitetura Harvard:
- Existe um barramento para receber instruções e outro separado para os dados da memória.
- A vantagem é que o processador pode obter um dado ao mesmo tempo que lê uma instrução. Isto faz com que a arquitetura Harvard seja mais rápida.
Conjunto de instruções
Outro fator que define a arquitetura de um microprocessador são os conjuntos das instruções. Dentre eles temos dois tipos:
- Complex Instructions Set Computers (CISC):
- Conjunto mais abrangente de instruções, contendo muitas operações diferentes (ex: cerca de 250 instruções).
- Gastam muitos pulsos de clock para executar uma instrução.
- O tamanho das instruções (bytes) é variável.
- Reduced Instruction Set Computers (RISC):
- Conjunto de instruções reduzidas (ex: cerca de 130 instruções)
- Gastam apenas 1 pulso de clock para executar uma instrução (bem mais rápido que o CISC).
- O tamanho da instrução (bytes) é fixo.
Observações finais
O objetivo desta aula foi dar um panorama geral da arquitetura de um microprocessador. É claro que existem muitos detalhes que foram resumidos, pois, caso contrário, daria para fazer um curso específico para a arquitetura de processadores.
O importante é entender a estrutura do processador de uma forma mais genérica para termos uma base para o entendimento dos microcontroladores. Por conta disto, na próxima aula, iremos aprender sobre a arquitetura de microcontroladores em específico do AVR e do PIC.
Referências: Bournetocode, Wikibooks, in One Lesson.
Arquitetura de um microcontrolador – Aula 3 – MC