Prévia do material em texto
20 21 .2 3. O computador e o processador “Conto os versos de um poema, calculo a altura de uma estrela, avalio o número de franjas, meço a área de um país, ou a força de uma torrente – aplico, enfim, fórmulas algébricas e princípios geométricos – sem me preocupar com os louros que possa tirar de meus cálculos e estudos!” – Malba Tahan, O Homem que Calculava De uma forma simplificada, o computador é um equipamento que recebe, processa e retorna as informações ao usuário, transformando-as com uma determinada utilidade, segundo as instruções definidas por um programa. Um programa é um conjunto de instruções e dados que são carregados na memória do computador no formato binário e que definem uma forma de interação com o usuário e especificam as tarefas que serão realizadas pelo computador. Os programas são inicialmente definidos pelos programadores com o uso de uma linguagem de alto nível (como C, Python, Fortran e outras) e que são posteriormente traduzidos pelo compilador para a linguagem de máquina, que é a linguagem que o processador entende. A seguir vamos ver, modernamente, como isso tudo começou e detalhes sobre a arquitetura e o funcionamento do computador. 3.1 ARQUITETURA DE VON NEUMANN Basicamente, a estrutura e a funcionalidade do computador moderno foram definidas por Von Neumann em 1945, durante o projeto do computador EDVAC, com a publicação de um relatório (NEUMANN; GODFREY, 1993) descrevendo a sua arquitetura, conforme apresentado na Seção 2.3.3. Para entendermos a importância da arquitetura Von Neumann vamos começar fazendo uma pergunta: qual a diferença entre uma calculadora e um computador? Uma calculadora básica realiza apenas as funções pré-determinadas em seu teclado. Se desejarmos fazer um novo tipo de operação, isso só será possível com a modificação dos circuitos eletrônicos que compõem a calculadora, além do seu teclado, para a inclusão da nova função. Não há, portanto, flexibilidade para realizar alterações na calculadora para se adaptar a novas aplicações. O computador, por sua vez, é um equipamento que oferece a possibilidade de ser confi- gurado facilmente para novas tarefas, de acordo com as necessidades de cada aplicação do usuário. A grande inovação da proposta de Von Neumann foi uma nova forma de arquite- 20 21 .2 134 3. O computador e o processador tura para o computador que permitisse um alto grau de flexibilidade, de forma a adaptá-lo facilmente para diversas aplicações. A proposta de computador controlado pelo programa armazenado em memória (NEU- MANN; GODFREY, 1993) foi um dos conceitos fundamentais apresentados por Von Neumann que permitiu essa flexibilidade. Em seu modelo de computador foi introduzido o conceito de memória, um dispositivo de armazenamento temporário, para onde programas (instruções e dados) diferentes poderiam ser carregados a partir de uma unidade de entrada, para serem executados pela unidade aritmética e lógica, com os resultados sendo transferidos da memória para uma unidade de saída, tudo isso sob a coordenação de uma unidade de controle. Deste modo, ficava garantida a flexibilidade do computador, que pode ter o seu funcionamento facil- mente alterado mediante o uso de instruções e dados diferentes, de acordo com a aplicação de cada usuário. Figura 3.1 – Arquitetura de Von Neumann © 2021 Gabriel P. Silva Sendo mais formal, os componentes da máquina de Von Neumann (Figura 3.1) podem ser descritos assim: 20 21 .2 3.1. Arquitetura de Von Neumann 135 • Unidade Aritmética e Lógica: É a unidade que executa as operações aritméti- cas e lógicas tais como: soma, subtração, multiplicação, divisão, raiz quadrada, movimentação entre a unidade aritmética e a memória, verificação do sinal do re- sultado, conversão de decimal para binário e vice-versa. Um total de 10 operações fundamentais foi definido por Von Neumann no artigo original. • Unidade de Controle: É a unidade responsável pelo sequenciamento das opera- ções, transferência dos dados e instruções e pelo controle das demais unidades do computador. • Memória: É a unidade onde as instruções, os dados de entrada, as tabelas de refe- rência, e os resultados intermediários são armazenados para permitir a execução de um programa. • Entrada: É a unidade que transfere a informação (numérica ou não) do meio externo. Todas as transferências devem ser feitas para a memória e nunca direta- mente para a unidade de controle. • Saída: É a unidade que transfere a informação (numérica ou não) para o meio externo. Todas as transferências devem ser feitas da memória para o meio externo, e nunca diretamente da unidade de controle. Von Neumann, em uma analogia com o comportamento dos neurônios, sugere o uso da numeração binária para a representação interna dos números, ao invés da numeração decimal, pela evidente economia que isso proporciona no tempo gasto nos cálculos e na complexidade dos circuitos. O componente eletrônico básico da máquina EDVAC, com comportamento análogo ao neurônio biológico era o E-element, que poderia ser implementado com 1 ou 2 tubos de vácuo (válvulas) e combinado para criar circuitos mais complexos para a unidade aritmética, memória e unidade de controle. O E-element é um dispositivo que recebe e emite sinais por uma linha conectada a ele, de forma equivalente ao axônio de um neurônio. Além disso, esses sinais, tais como sinais do sistema nervoso, demoram uma quantidade de tempo para serem transmitidos. Entretanto, diferentemente do sistema nervoso humano, essa quantidade de tempo possui um valor fixo, pois alguns outros atrasos presentes no sistema nervoso humano são ignorados pelos E-elements. Além disso, outra diferença do E-element para o sistema nervoso humano é que todos esses elementos atuam de forma sincronizada pelo relógio central da máquina, enquanto que o funcionamento dos neurônios é assíncrono. As válvulas foram escolhidas como elementos básicos por serem dispositivos existentes, com a tecnologia disponível naquela época, de menor tempo de chaveamento (mudança do valor lógico 0 para o valor lógico 1). O uso de um sinal elétrico periódico para cadenciar todas as operações do computador foi também proposto por Von Neumann, dando origem ao que chamamos de relógio do computador. O modelo de arquitetura de Von Neumann continua sendo utilizado no projeto dos compu- 20 21 .2 136 3. O computador e o processador tadores comerciais nos dias de hoje e o estudo de suas características permite uma compreensão adequada do funcionamento dos computadores atuais. Note que no modelo de Von Neumann tudo armazenado na memória: em princípio dados e instruções ficam na mesma memória, sem conflito, desde que estejam em endereços diferentes. Contudo, há algumas situações nas quais é conveniente armazenar dados e instruções em memórias fisicamente diferentes, esse tipo especial de organização recebe o nome especial de arquitetura Harvard(Fig. 3.2). Figura 3.2 – Arquitetura Harvard © 2021 Gabriel P. Silva Esse nome deriva do fato de que esse tipo de organização foi adotado pelo processador Mark I apresentado na Seção 2.2.5, desenvolvido pela Universidade de Harvard. 3.2 MODELO DE BARRAMENTO DE SISTEMA O modelo de Von Neumann passou por um refinamento que recebeu o nome de modelo de barramento de sistema (Figura 3.3). Nesse modelo, a unidade de controle e a unidade aritmética, e também os registradores, são agregados em um único elemento que recebe o nome de processador. A unidade de entrada e a unidade de saída são apresentadas agora também como uma única unidade, chamada de unidade de entrada/saída. A memória continua sendo vista com uma unidade independente, com as mesmas funções da arquitetura de Von Neumann, ou seja, armazenamento de dados e instruções dos programas em execução. Um elemento novo que surge é o próprio barramento de sistema, que faz a interligação entre o processador, a memória e a unidade de entrada/saída. O barramento de sistema é 20 21 .2 3.2. Modelo de Barramentode Sistema 137 Figura 3.3 – Modelo de Barramento de Sistema © 2021 Gabriel P. Silva composto pelos barramentos de endereço, dados e controle. O barramento de endereços transporta os sinais de endereço através de fios ou trilhas até a memória. Sinais esses que vão, principalmente, determinar qual a posição de memória que irá ser lida ou escrita. Os endereços podem ser fornecidos tanto pelo processador como pela unidade de entrada/saída. A informação dessa posição de memória, que está sendo lida ou escrita na memória, transita pelo barramento de dados, que é bidirecional. Apesar do nome, tanto instruções como os dados propriamente ditos circulam por esse barramento. O barramento de controle indica qual a natureza da operação que vai ser realizada: leitura ou escrita, na maior parte dos casos, e possui também sinais para a arbitragem do barramento, para determinar quem vai utilizar o barramento naquele momento, que pode ser tanto o processador como a unidade de entrada/saída. Eventualmente, nos modernos computadores, existem também um ou mais barramentos dedicados para ligar os periféricos à unidade de entrada/saída. Isso permite que o acesso do processador à memória se faça com maior eficiência, pela diminuição do tráfego de dados no barramento de sistema. Em realidade, o modelo de barramento de sistema foi se modificando ao longo dos anos, se adaptando às demandas de miniaturização dos computadores, que se tornaram cada vez mais compactos, portáteis e com menor consumo de energia. Nas placas-mãe (motherboard em inglês) dos computadores pessoais modernos não há um barramento de sistema explícito, mas apenas um controlador (ou chipset em inglês) que faz a intermediação entre o processador e os dispositivos de entrada e saída, como pode ser visto na Figura 3.4. Nesse tipo de arquitetura estão embutidos na mesma pastilha, além do processador: o 20 21 .2 138 3. O computador e o processador Figura 3.4 – Placa de Processador Moderno © 2016 Intel controlador e o barramento de acesso à memória principal; o controlador e a interface para o barramento de interconexão à placa de vídeo; além de possuir um terceiro barramento que faz a interface com o (chipset). Esse chipset, conhecido como ponte sul, é responsável por diversas funções tais como: controlador de DMA; controlador de interrupção; temporizadores; relógio de tempo real; controlador USB; controlador de áudio; controlador de ethernet ; interface para os discos rígidos; interface para o barramento PCI Express; entre outros componentes que iremos detalhar mais adiante. A seguir vamos examinar cada um dos componentes do modelo de barramento de sistema com mais detalhes. 3.2.1 Processador No processador, além da unidade aritmética e lógica (UAL) e unidade de controle, encontramos também os registradores. Os registradores são elementos de memória, de pequena capacidade, mas de alta velocidade, colocados junto da UAL para armazenar os valores que vão ser utilizados como operandos e receber os resultados gerados pela UAL. Se os operandos e resultados fossem armazenados diretamente na memória, o tempo para a realização das operações da UAL aumentaria tremendamente. O conjunto desses registradores presentes no processador é denominado de banco de registradores. 20 21 .2 3.2. Modelo de Barramento de Sistema 139 Os registradores do processador são referenciados explicitamente pelas instruções lógicas, aritméticas e de transferência de dados, podendo ser operandos fontes (lidos) ou de destino (escritos) para essas instruções. Contudo, além desses registradores, existem ainda outros registradores que são transparentes ao programador, tais como o registrador de instrução (RI), cuja função é armazenar a instrução que está sendo executada atualmente pelo processador. Existe um outro registrador especial denominado apontador de instruções (PC), que contém o endereço da próxima instrução que vai ser executada. Esse registrador pode ser alterado, por exemplo, pelas instruções de desvio, chamada e retorno de procedimento (funções e subrotinas). A função do processador é executar os programas que estão armazenados na memória principal. Isso é feito buscando suas instruções, examinando-as, e então executando-as uma após a outra. O processador é responsável pela realização de uma série de funções, dentre as quais destacamos: • Buscar instruções e dados na memória; • Programar a transferência de dados entre a memória e os dispositivos de entra- da/saída; • Decodificar as instruções; • Realizar das operações aritméticas e lógicas; • Responder aos sinais enviados por dispositivos de entrada/saída, tais como inter- rupções e sinais de erro. Na Figura 3.5 podemos ver a fotografia de um processador de 64 bits utilizado nos modernos computadores. Figura 3.5 – Processador Intel Core I7 © Jud McCranie [CC BY-SA 4.0 (h�ps://creativecommons.org/licenses/by-sa/4.0)] O processador tem seu funcionamento sincronizado pelo relógio, que pode operar em frequência diferente dos demais componentes do computador, e serve para cadenciar as diversas fases de execução das instruções. �anto mais rápido (maior a frequência) for o sinal de relógio, mais rápido as instruções, e por consequência os programas, serão executados. No 20 21 .2 140 3. O computador e o processador entanto, o atraso dos componentes básicos do processador (portas lógicas, flip-flops, etc.) e a potência máxima que consegue ser dissipada pelo seu encapsulamento, limitam a frequência máxima de relógio do processador. Com a evolução dos computadores, outros componentes que anteriormente eram externos, têm sido incorporados à mesma pastilha em que está o processador, entre esses elencamos: memória cache; controlador de vídeo; e até mesmo outros processadores. Maiores detalhes sobre o funcionamento do processador podem ser vistos no Capítulo 3.4. 3.2.2 Memória A memória principal é utilizada para armazenar os programas e dados que vão ser processados durante a operação normal do computador. A menor unidade de informação que pode ser manipulada individualmente na memória é o byte, um conjunto de 8 bits, sendo que cada byte possui um endereço distinto na memória. Ou seja, para que qualquer informação possa ser lida ou escrita na memória, deve ser acompanhada de um endereço, que pode ser fornecido tanto pelo processador como pela unidade de entrada/saída. Figura 3.6 – Pente de Memória de Computador © 2021 Gabriel P. Silva Os dados ou instruções armazenados na memória são transferidos pelo barramento de dados, cuja largura em bits varia de acordo com o tipo de pastilha ou cartão de memória utilizado para compor a memória principal do processador, mas um valor comum nos modernos computadores é uma largura de 64 bits. A unidade de memória do computador é formada uma parte volátil, chamada de memória principal, e por outra parte não volátil. As informações armazenadas na memória principal podem ser alteradas durante a execução de um programa, mas são mantidas apenas enquanto o computador estiver ligado. Uma memória principal com capacidade de armazenamento na ordem de alguns gigabytes é comum nos computadores pessoais modernos. A memória não volátil, que mantém o seu conteúdo quando o computador é desligado, é uti- lizada para armazenar os programas responsáveis por iniciar o funcionamento do computador, realizar os testes iniciais e copiar o sistema operacional do disco para a memória principal. Nos primeiros computadores pessoais compatíveis com o IBM/PC, essa memória recebia o nome do programa que ela armazenava: BIOS (Basic Input/Output System) — veja a Seção 3.3.1. 20 21 .2 3.2. Modelo de Barramento de Sistema 141 Embora seja não volátil, nos modernos computadores a BIOS pode ser atualizada diretamente no computador, mediante reprogramação de seu conteúdo, mas isso deve acontecer apenas eventualmente. Maiores detalhes sobre a memória do computador serão apresentados no Capítulo 4. 3.2.3 Entrada e Saída A unidadede entrada e saída (E/S) não se encontra definida por um único encapsulamento ou componente no computador. Em realidade, essa unidade é constituída por diversos controlado- res e interfaces que permitem a comunicação entre os dispositivos de entrada/saída (também chamados de periféricos) com o processador e a memória. Sem os periféricos a comunicação entre o homem e o computador não seria possível. Normalmente a unidade de E/S faz a conversão da informação do formato binário, arma- zenado no computador, para formato analógico, perceptível no meio externo pelos sentidos humanos e vice-versa. Eventualmente a informação pode ser transferida sempre no formato binário quando, por exemplo, ocorre a comunicação entre dois computadores ou quando a informação é armazenada em dispositivos removíveis. Exemplos de dispositivos de entrada/saída são o teclado, mouse, impressora, monitor de vídeo, disco rígido, pendrive, interface de rede, entre outros. Os periféricos se interligam aos controladores através de barramentos específicos, cha- mados de barramentos de E/S. Cada tipo de periférico tem um barramento com um padrão próprio, mais adequado para transferir seus dados de/para o computador, resultando em uma enorme quantidade de padrões de barramentos disponíveis para uso. Figura 3.7 – Teclado de Computador © 2021 Gabriel P. Silva Os dispositivos de entrada/saída que são responsáveis pelo armazenamento de informação de uma forma não volátil (meio magnético ou ótico, por exemplo) são chamados de memória secundária ou memória de massa. Toda informação que precisa ser mantida depois que o computador for desligado é guardada nesses dispositivos. A memória secundária é onde os programas e dados, incluindo aqueles do sistema operaci- onal, são armazenados de uma forma persistente no computador. Hoje em dia é constituída, 20 21 .2 142 3. O computador e o processador principalmente, pelo conjunto de discos magnéticos do computador e também, cada vez mais, pelos discos de estado sólido. Há vários outros tipos de dispositivos, removíveis ou não, que podem ser considerados parte da memória secundária, tais como fitas magnéticas, discos óticos, pendrives, entre outros. Uma das características da memória secundária é o alto volume de dados e o baixo custo de armazenamento por byte quando comparado com a memória principal. Maiores detalhes sobre o funcionamento dos dispositivos e barramentos de entrada e saída podem ser encontrados no Capítulo 5. Informações adicionais sobre a memória secundária e os sistemas de armazenamento são apresentadas no Capítulo 6. 3.3 INICIANDO O COMPUTADOR Os modernos computadores são controlados por um conjunto de programas que recebem o nome de sistema operacional. É o sistema operacional que é responsável por mediar todas as ações entre os usuários, ou suas aplicações, e o hardware do computador. �ando um computador é ligado, uma de suas primeiras tarefas é carregar o sistema operacional na memória principal do computador e deixá-lo disponível para todos usuários. Isso é um requisito fundamental tanto para os grandes computadores corporativos, como também para os computadores de uso pessoal. Porém, a carga do sistema operacional em um computador é um processo complexo que é realizado em diversas etapas. Deve-se notar que, quando o computador é ligado, a memória principal (RAM) do computador não tem dados válidos, pois é volátil e perdeu todo seu conteúdo quando o computador foi desligado. Assim, inicialmente, o processador deve executar um programa que esteja armazenado em uma memória não volátil do computador, normalmente uma memória reprogramável do tipo FLASH. 1 Dependendo do tipo de computador, esse programa pode seguir diversos padrões. Sem perda de generalidade, iremos focar nosso estudo nos computadores pessoais compatíveis com o IBM/PC, que utilizam o padrão BIOS, legado, ou UEFI, mais moderno, cujos detalhes veremos a seguir. 3.3.1 BIOS A BIOS é uma abreviatura de Basic Input-Output System, sendo responsável por ativar os com- ponentes de hardware do seu computador, garantir que eles estejam funcionando corretamente e, em seguida, executar o gerenciador de partida que vai iniciar o sistema operacional que você tenha instalado. Normalmente, existe uma interface de usuário para a BIOS, que pode ser ativada com uma combinação de teclas. Nessa interface podem ser definidas várias configurações de hardware, 1 h�ps://pt.wikipedia.org/wiki/Memória_flash 20 21 .2 3.3. Iniciando o computador 143 Figura 3.8 – Carregando o Gerenciador de Partida © 2021 Gabriel P. Silva hora do sistema, dispositivos de boot e respectiva ordem de prioridade. Essas informações de- vem ser armazenadas de uma forma persistente, para que possam estar disponíveis novamente no próximo boot. As primeiras memórias não voláteis dos computadores pessoais eram apenas de leitura, o que obrigou os projetistas a encontrarem soluções para armazenar de forma permanente algumas informações no computador. Então, quando você salva uma configuração, ela é armazenada em uma pequena memória CMOS, que é alimentada por uma bateria à parte, da própria placa-mãe e permanece ativa enquanto essa bateria estiver com carga. Essa bateria também é responsável por guardar a hora do computador atualizada, alimentando o RTC (Real Time Clock) quando computador é desligado.�ando você liga o computador, a BIOS irá testar e configurar o seu computador e recuperar a hora atual a partir dessas configurações salvas. Esse teste inicial é conhecido pelo nome de POST (Power-On Self Test), e serve para verificar diversos componentes, tais como: fonte de alimentação; adaptador de vídeo; memória principal (RAM); temporizador; teclado e mouse; etc. Após esses testes iniciais, se tudo estiver em ordem, o dispositivo de boot, que pode ser um disco rígido, um pendrive ou mesmo a ethernet, deve ser acessado para que o processo de carga do sistema operacional seja iniciada. No caso do disco rígido, a BIOS procura por umMaster Boot Record (MBR - veja a Seção 6.1.3), onde está armazenada a primeira parte do gerenciador de partida, um pequeno trecho de código, com menos de 512 bytes. Como é um código muito pequeno, a sua única utilidade é procurar outro arquivo no disco e carregá-lo para realizar o processo de iniciação real. Como tal, este código de bootstrap do MBR é frequentemente denominado de primeiro estágio do gerenciador de partida. O lugar exato onde o segundo estágio do gerenciador de partida será buscado pode mudar, dependendo do sistema operacional em uso. Por exemplo, no caso do Windows uma partição marcada como ativa será procurada na tabela de partição que fica no MBR. O primeiro setor dessa partição ativa, ou seja, apenas 512 bytes, serãomais uma vez carregados namemória. Esse código não é ainda o segundo estágio do gerenciador de partida, mas apenas uma continuação 20 21 .2 144 3. O computador e o processador Figura 3.9 – Escolhendo o Sistema Operacional © 2021 Gabriel P. Silva do primeiro estágio, podendo se estender por vários setores da partição ativa. Depois de totalmente carregado, o primeiro estágio irá buscar a segunda parte do gerenciador de partida, que normalmente estará no sistema de arquivos do Windows. No caso do sistema operacional Linux, dependendo do gerenciador de partida utilizado (LILO, GRUB ou GRUB2), o processo de carga apresenta algumas variações. Mas basicamente, o segundo estágio do gerenciador de partida é buscado em um setor do disco ou mesmo em um arquivo no próprio sistema de arquivos do Linux. A segunda parte do gerenciador de partida é a parte real do programa, que contém a interface de usuário e o carregador do núcleo do sistema operacional. A interface de usuário pode ser algo com uma simples linha de comando (versões antigas do LILO), um menu ou ambos. Ele permite que você selecione qualquer número de sistemas operacionais e especifique parâmetros adicionais de carga. As opções disponíveis são especificadaspor um arquivo de configuração. Já o carregador do sistema operacional faz a carga do núcleo do sistema operaci- onal na memória e o executa. Como alternativa, podemos ainda carregar outro carregador de partida específico para outro sistema operacional e deixá-lo executar, no que é chamado de carregamento em cadeia. Após todos esses passos, o sistema operacional estará carregado, e o seu computador estará pronto para uso. 3.3.2 UEFI Em 2007, a Intel, AMD, Microso�, e outros fabricantes de computadores pessoais lançaram a especificação Unified Extensible Firmware Interface (UEFI), utilizada hoje em dia pela quase totalidade dos computadores no lugar da BIOS. A UEFI substitui o BIOS tradicional nos computadores pessoais e não há como mudar de BIOS para UEFI em um computador já existente. Você precisa comprar um novo hardware que suporte e inclua a UEFI, como a maioria dos novos computadores fazem. A maioria das implementações de UEFI fornece emulação de BIOS para que você possa escolher instalar e 20 21 .2 3.3. Iniciando o computador 145 iniciar sistemas operacionais antigos que esperam uma BIOS em vez da UEFI, para que sejam compatíveis com versões anteriores. Ao invés do MBR, o UEFI utiliza uma nova de particionamento do disco, chamada de GUID Partition Table (GPT - veja a Seção 6.1.3) que permite superar muitas limitações do antigo padrão BIOS/MBR, com partições maiores e redundância para a tabela de partição. O UEFI também definiu um formato padrão para os seus programas executáveis, além de definir uma extensão do formato FAT32 para ser utilizado nas partições que armazenam esses programas. Ou seja, o UEFI carrega programas executáveis, compilados com um formato definido na especificação do padrão, que estão armazenados em partições de sistema destinadas exclusivamente para o UEFI, formatadas também com um padrão descrito na sua especificação do padrão. Além disso, há uma série de atributos no UEFI, tais como o Secure Boot, que permite verificar se houve violações no sistema operacional que está sendo carregado; e pode suportar o acesso à rede, permitindo que possa ser feito acesso remoto ao computador, mesmo antes da carga do sistema operacional. Como uma BIOS tradicional, o único recurso disponível seria o acesso físico ao computador para configurá-lo. Em síntese, o UEFI é essencialmente um mini sistema operacional executando direto no firmware do processador, podendo ser carregado da memória FLASH da placa mãe, carregado do disco rígido ou mesmo através da rede. As distribuições Linux usam a ferramenta efibootmgr para io gerenciador de partida do UEFI. A distribuição Linux cria uma partição de sistema no padrão EFI, se ainda não houver uma, e instala um carregador de boot EFI com uma configuração apropriada - frequentemente o grub2-efi, mas há outros - em um caminho correto na partição do sistema EFI e chama o efibootmgr para adicionar uma entrada do gerenciador de partida UEFI com o nome apropriado apontando para seu carregador de partida. O UEFI possui também um modo de compatibilidade com o padrão BIOS, configurá- vel na interface de usuário. Contudo, não é recomendável misturar instalações de sistemas operacionais com uso de BIOS e UEFI no mesmo computador. Se você iniciar a mídia de instalação no modo “UEFI nativo”, ele fará uma instalação UEFI nativa do sistema operacional, que vai tentar gravar um bootloader de formato EFI em uma partição do sistema EFI e tentará adicionar uma entrada corresponde ao menu de partida. Se você deseja fazer uma instalação nativa UEFI, provavelmente deseja instalar em um disco formatado com GPT. Se você iniciar a mídia de instalação no modo “compatibilidade do BIOS”, será feita uma instalação compatível com a BIOS do sistema operacional: ele tentará gravar um carregador de partida do tipo MBR no primeiro setor do disco. Se você deseja fazer uma instalação do tipo “compatibilidade do BIOS”, provavelmente deseja instalar em um disco formatado com MBR. 20 21 .2 146 3. O computador e o processador 3.4 FUNCIONAMENTO DO PROCESSADOR O processador é o componente eletrônico no computador responsável pela interpretação das instruções em linguagem demáquina e controle de todos os demais dispositivos do computador, com o objetivo de realizar as tarefas determinadas pelo usuário. Para executar um programa que está na memória, o processador realiza permanentemente a busca de instruções, no endereço de memória indicado pelo apontador de instruções (PC). Depois que foi lida da memória, a instrução é transferida para o registrador de instrução (RI) e o valor do apontador de instruções é automaticamente incrementado para o endereço da instrução seguinte, indefinidamente até que uma instrução de transferência de controle seja executada. Por exemplo, caso a instrução executada seja uma instrução de desvio incondicional, o valor do apontador de instruções é alterado para o endereço especificado nessa instrução. As instruções acessam os seus dados, chamados também de operandos, de diversas ma- neiras, ou modos de endereçamento, em posições distintas na memória do computador. Veja mais detalhes sobre modos de endereçamento na Seção 3.6. Para o processamento das instruções o processador conta com um circuito especial, cha- mado de unidade aritmética e lógica (UAL), capaz de realizar operações aritméticas como soma e subtração com os operandos das instruções, sempre no formato binário. A fim de agilizar essas operações, o processador possui internamente dispositivos especiais de armaze- namento, chamados de registradores ou acumuladores, para guardar os resultados temporários dessas operações. A unidade aritmética e lógica pode realizar diversas operações, entre elas destacamos: • Adição • Subtração • Multiplicação • Divisão • Operações lógicas (E, OU, OU EXCLUSIVO, INVERSÃO, etc.). • Deslocamento e Rotação (à esquerda e à direita) • Comparação As operações aritméticas e lógicas são realizadas com a leitura dos operandos dos regis- tradores ou memória e com a escrita do resultado no registrador de destino ou memória. Os registradores são referenciados explicitamente pelas instruções e os endereços de memória podem ser constantes embutidas na própria instrução ou valores contidos em registradores. A largura da arquitetura de um processador (8, 16, 32 ou 64 bits) é definida pela largura em bits do maior operando inteiro que pode ser processador em uma única operação pela UAL. Note que a largura de uma arquitetura: 20 21 .2 3.4. Funcionamento do Processador 147 • NÃO é definida pelo tamanho em bits da instrução; • NÃO é definida pela largura do barramento de dados interno ou externo; • NÃO é definida pela largura em bits dos operandos da unidade de ponto flutuante; • NÃO é definida pela largura em bits do apontador de instruções (PC) ou do barramento de endereços. Como consequência direta, a largura em bits do maior operando admitido pela UAL irá determinar, normalmente, a largura em bits do acumulador e dos registradores de uso geral do processador. Não há sentido para que sejam maiores ou menores do que isso. Uma representação esquemática da unidade aritmética e lógica pode ser vista na Figura 3.10. Figura 3.10 – Unidade Aritmética e Lógica © 2020 Gabriel P. Silva Nesta figuraA eB são os operandos da função a ser realizada pela ALU, que é determinada pelo código colocado em F , cujo resultado final estará disponível em R, com os eventuais valores de códigos de condição da operação (Negativo, Zero, Carry,Overflow, etc.) apresentados em D. 3.4.1 Unidade de Controle A unidade de controle é responsável pela coordenação da atividade de todos os componentes do processador, realizando também busca da instrução na memória e transferindo-da para o registrador de instruções (RI). A unidade de controle faz a decodificação da instrução que está no RI: 20 21 .2 148 3. O computador e o processador Figura 3.11 – Unidade de Controle por Hardware © 2020 Gabriel P. Silva •Determina qual o tipo de operação vai ser realizada pela U.A.L.; • Determina quantos e quais são os operandos de leitura, e qual o registrador de destino, se houver; • Lê os operandos necessários para a execução da instrução e os coloca na entrada da U.A.L.; • A unidade de controle lê o resultado da saída da U.A.L. e envia para o destino correto. Há duas formas básicas para se implementar a unidade de controle: • Através de microprogramação • Controle direto pelo hardware (PLA, ROM) As unidades de controle microprogramadas possuem em seu interior uma memória, nor- malmente do tipo PROM, mas podendo ser uma RAM, com um microprograma que decodifica as instruções e geram as diversas palavras de controle para a execução de uma instrução. A palavra de controle é um conjunto de sinais, coordenados pelo relógio do processador, que faz o acionamento de registradores, unidades funcionais, controle de multiplexadores e outros circuitos do processador para a correta execução correta das instruções. As unidades controladas pelo hardware possuem uma lógica de controle mais simples, normalmente uma PLA e uma máquina de estados simples, que gera as palavras de controle para a execução das instruções. Em cada estado, a máquina de estados ativa um conjunto de saídas diferentes de controle 20 21 .2 3.4. Funcionamento do Processador 149 para as unidades funcionais, registradores e multiplexadores que compõem o hardware do processador, de acordo com a instrução que está sendo executada; além de fornecer informações utilizadas para definir qual vai ser o próximo estado. A função que define o próximo estado pode estar implementada como uma máquina de estados finitos ou fazendo-se uso de um sequenciador explícito. Se o número de estados for grande e houver muitas sequências de estados consecutivos sem desvio, a implementação com uso de um sequenciador explícito é mais eficiente. A lógica de controle, que decodifica o estado atual nos sinais de controle pode ser imple- mentada com ROMs ou PLAs, ou uma combinação dos dois. As PLAs são mais eficientes, a menos que a função de controle seja muito densa, quando então o uso de ROMs pode ser mais adequado. As unidades de controle microprogramadas são características das arquiteturas do tipo CISC. O controle diretamente pelo hardware é encontrado normalmente nas arquiteturas do tipo RISC (veja a seção 3.8). A seguir apresentamos um texto extraído de (AUDE, 2001b), onde é explicado o funciona- mento da unidade de controle microprogramada. “A técnica de controle microprogramado foi proposta por Maurice Wilkes em 1951 [Wilk51]. Sua filosofia consiste em armazenar na chamada Memória de Controle as informações neces- sárias para ativação dos sinais de controle da arquitetura do processador. Cada palavra de memória, corresponde a uma microinstrução, e consiste, em geral, de dois campos. O primeiro deles, campo de controle, é constituído por um conjunto de bits associados aos sinais de controle da arquitetura do processador. Cada bit tem posição fixa nas diversas microinstruções e pode comandar a ativação de um sinal de relógio, a liberação de um registrador em um barramento, a definição da entrada a ser selecionada em um multiplexador, etc. O segundo campo, denominado campo de endereçamento, é constituído por um outro conjunto de bits utilizado na determinação do endereço na Memória de Controle onde está armazenada a pró- xima microinstrução a ser executada. Na operação da Unidade de Controle microprogramada, um conjunto de microinstruções é executado sequencialmente para se processar todas as fases de uma instrução. A este conjunto de microinstruções dá–se o nome de microprograma da instrução. A Figura 3.12 ilustra a estrutura geral de uma Unidade de Controle Microprogramada. �ando a microinstrução endereçada é lida da memória de controle, ela é armazenada no registrador de controle. Os bits do campo de endereçamento da microinstrução são utilizados na determinação do endereço da próxima microinstrução a ser lida da Memória de Controle, enquanto que os bits do campo de controle comandam os pontos de controle da Unidade Aritmética e do Sistema de Memória. O endereçamento na Memória de Controle da próxima microinstrução a ser executada pode ser explicitamente determinado pelo campo de endereçamento da microinstrução atual ou através do uso de um registrador contador de microprogramas. Neste último caso, desvios incondicionais no microprograma são usualmente implementados através da especificação do 20 21 .2 150 3. O computador e o processador Figura 3.12 – Unidade de Controle Microprogramada © 2020 Gabriel P. Silva endereço alvo do desvio pelo campo de endereçamento da microinstrução atual. Em qualquer estrutura adotada de endereçamento da Memória de Controle, no entanto, situações de desvio condicional na execução do microprograma podem ocorrer, tanto em função do resultado da decodificação da instrução como em função do estado de sinais gerados pela Unidade Aritmética. Portanto, o circuito de Geração do Endereço da próxima microinstrução deve receber informações do decodificador de instruções e dos sinais da Unidade Aritmética que podem alterar o fluxo de execução dos microprogramas. A maneira como o endereço final é efetivamente formado varia bastante, tendo em vista um compromisso entre o grau de flexibilidade que se quer dar a este processo e a complexidade do circuito resultante. Em uma Unidade de Controle microprogramada, a Memória de Controle pode ser imple- mentada como memórias RAM (Random Access Memory), possibilitando que o microprograma seja alterado facilmente na fase de teste e avaliação do projeto ou que a arquitetura do proces- sador emule diferentes conjuntos de instruções, carregando-se na Memória de Controle os novos microprogramas necessários para a emulação desejada. Entretanto, o uso de tecnologia RAM para implementar a Memória de Controle obriga que, na fase de inicialização do sistema, os microprogramas sejam carregados na Memória de Controle a partir de uma fonte de dados externa, já que as memórias RAM são voláteis. Para contornar este problema, pode-se utilizar a tecnologia de memórias de leitura exclusiva (ROM – Read Only Memory) para se implementar a Memória de Controle. Porém, neste caso, perde-se um pouco da flexibilidade de se imple- mentar a nível de microprograma a emulação de outras arquiteturas, já que a alteração dos microprogramas gravados usualmente requer a o apagamento dos microprogramas antigos e a 20 21 .2 3.4. Funcionamento do Processador 151 gravação dos novos microprogramas nos módulos de memória através de dispositivos especiais. Além disso, as memórias de leitura exclusiva tendem a ter um tempo de acesso maior do que as memórias RAM, podendo tornar mais lento o processamento das microinstruções. Microprogramação horizontal x vertical Existem basicamente dois estilos para se definir a microprogramação das instruções de um processador: a microprogramação horizontal e a microprogramação vertical. A microprogra- mação é dita totalmente horizontal quando a cada ponto de controle da Unidade Aritmética e das Interfaces com os Sistemas de Memória e de E/S do processador corresponde um único bit no campo de controle das microinstruções. Portanto, com a adoção do estilo de microprogra- mação horizontal, os bits de controle da microinstrução atuam diretamente sobre os pontos de controle da arquitetura do processador, não sendo necessária a introdução de nenhum circuito de decodificação da informação armazenada na microinstrução, o que tende a tornar mais rápida a ação da lógica de controle. Além disso, a microprogramação horizontal nunca impede a execução de micro-operações em paralelo, bastando para isso que os bits correspondentes a estas micro-operações estejam ativados na mesma microinstrução. Há, portanto, uma maior flexibilidade na microprogramação da arquitetura, já que qualquer combinação de pontos de controle pode ser acionadaem uma única microinstrução. Esta característica é muito útil em projetos de sistemas computacionais que pretendem ser reconfiguráveis, através da emulação de diferentes conjuntos de instruções. Duas são as desvantagens principais da microprogramação horizontal. A primeira delas está relacionada com o fato de que as microinstruções tendem a ser muito largas, ou seja, a conter um grande número de bits de controle. Com isso, a Memória de Controle tende a ser muito larga e curta, já que o número total de microinstruções tende a não ser muito grande com o uso de microprogramação horizontal. Este fato dificulta a implementação da Memória de Controle com módulos de memória comerciais, já que estes tendem a conter um grande número de palavras com poucos bits, ou seja, tendem a ser compridas e pouco largas, tendo, portanto, a relação de aspecto inversa àquela que é de fato necessária. Esta questão, no entanto, não é relevante em implementações personalizadas da Memória de Controle em circuitos integrados, já que, neste caso, a Memória de Controle é totalmente projetada a partir de células básicas de 1 bit de memória. A segunda desvantagem do uso de microprogramação horizontal está associada ao grande número de microinstruções diferentes que normalmente são geradas para a composição dos microprogramas. Com isso, torna-se mais difícil a definição de um micro-assembly, baseado em um conjunto não muito extenso de microinstruções com funcionalidades diferentes. Amicroprogramação vertical tem como filosofia determinar um conjunto nãomuito extenso de microinstruções que podem ser utilizadas na definição dos microprogramas que controlam o processamento das diferentes instruções, tornando muito simples a definição de um micro- assembly para a especificação desses microprogramas. Cada microinstrução do conjunto 20 21 .2 152 3. O computador e o processador realiza, em geral, poucas micro-operações, sendo, portanto, bastante simples. Supondo que, por exemplo, este conjunto é composto por um número de microinstruções inferior ou igual a 2n e superior a 2n−1, bastam apenas n bits para especificar uma dada microinstrução do conjunto. Sendo assim, a Memória de Controle precisa apenas armazenar em cada palavra o código de n bits que especifica a microinstrução a ser executada. Em consequência, a Memória de Controle se torna muito estreita e, em geral, mais longa, já que com a perda de poder de expressão das microinstruções para facilitar a definição de um conjunto reduzido de microinstruções, o número de microinstruções associado a cada instrução tende a crescer. É importante observar que com a utilização de microprogramação vertical, a execução das instruções tende a se tornar mais lenta por dois motivos. Em primeiro lugar, como a informação é armazenada de forma codificada na Memória de Controle, é necessária a introdução de circuitos de decodificação do código da microinstrução para que os sinais de controle da arquitetura do processador sejam efetivamente gerados. Com isso, o processamento de cada microinstrução tende a se tornar mais lento. Em segundo lugar, conforme já foi dito, o número de microinstruções associadas ao processamento de cada instrução é maior do que no caso da microprogramação horizontal. A decodificação do código de uma microinstrução vertical pode ser feita com circuitos decodificadores ou através do esquema de nanoprogramação, onde a Memória de Controle é composta de duas seções. A primeira delas armazena as microinstruções codificadas que servem de endereçamento para a segunda seção da Memória de Controle, chamada de Me- mória de Nanoprogramas, onde fica armazenada a microinstrução horizontal (nanoinstrução) correspondente ao código de microinstrução gerado. Generalizando-se esta idéia, pode-se inclusive fazer com que a cada microinstrução vertical corresponda eventualmente a mais de uma nanoinstrução, ou seja, a um nanoprograma armazenado na Memória de Nanoprogramas. Frequentemente, a Unidade de Controle microprogramada utiliza uma solução de compro- misso entre a microprogramação totalmente horizontal e a microprogramação vertical. Nesta solução, adota-se o princípio da microprogramação horizontal, mas é feita a codificação de grupos de bits de controle que se referem a ações de controle que são sempre ou na maioria das vezes mutuamente exclusivas. Tal situação ocorre, por exemplo, com um grupo de bits de controle onde cada um deles comanda a liberação de um registrador diferente em um mesmo barramento. Como sempre se libera apenas um registrador de cada vez em um barramento, nenhuma microinstrução vai precisar acionar dois ou mais bits de controle deste grupo si- multaneamente. Logo, se existem k registradores que podem ser liberados no barramento, pode-se codificar a informação de qual o registrador que deve ser liberado com o uso de apenas log2k bits de controle, ao invés de k bits de controle, sem perda alguma de flexibilidade na microprogramação. Com a adoção desta solução de compromisso, obtém-se praticamente a mesma flexibilidade da microprogramação horizontal, com o uso de umaMemória de Controle não tão larga. Porém, circuitos de decodificação devem ser utilizados para explicitar a ação de controle definida pelos campos codificados da microinstrução e a definição de um micro-assembly continua não 20 21 .2 3.4. Funcionamento do Processador 153 sendo simples.” 3.4.2 Execução das Instruções O processador executa uma instrução em uma série de etapas: • Busca a próxima instrução que está localizada na memória para o registrador de instrução; • Atualiza o apontador de instruções (PC) para o endereço da próxima instrução a ser executada; • Determina o tipo de instrução e o número de operandos; • Busca os operandos, se houver, para os registradores do processador; • Executa a instrução; • Armazena os resultados; • Volta ao passo 1 para executar a próxima instrução. Os processadores mais simples possuem pelo menos um acumulador (AC), enquanto que os mais sofisticados possuem dezenas ou até mesmo centenas de registradores para armazenar esses resultados temporários das operações. Em qualquer caso, em algum momento, esses valores armazenados nos registradores serão transferidos para a memória do computador, nas posições correspondentes às variáveis do programa. Um modelo bem simples de processador pode ser visto na Figura 3.13. Figura 3.13 – Processador com Acumulador © 2016 Gabriel P. Silva Uma facilidade que os processadores modernos oferecem é para a chamada de rotinas ou procedimentos, ou seja, trechos de programa que podem ser acessados a partir de vários 20 21 .2 154 3. O computador e o processador pontos do programa principal. A chamada de procedimentos, ao contrário de um desvio normal, requer que um endereço de retorno seja armazenado em algum local, para que o processador possa retornar para o ponto do programa principal de onde a rotina foi chamada. Assim, esse endereço armazenado é utilizado para atualizar o valor do PC para retornar de uma rotina, voltando para o endereço da instrução imediatamente depois daquela que originalmente chamou a rotina. Diversas formas podem ser utilizadas para armazenar este endereço de retorno, sendo que uma delas guarda este endereço em uma estrutura dados na memória, chamada de pilha, onde os elementos são retirados sempre na ordem inversa com que são colocados, ou seja, os últimos elementos colocados são os primeiros a serem retirados e vice-versa. Existe então um registrador especial, chamado de um apontador de pilha (SP), que aponta sempre para o último elemento que está no topo da pilha e que é automaticamente atualizado quando os elementos são inseridos ou retirados da pilha. Uma característica especial da pilha é que ela é “cresce” no sentido inverso dos endereços de memória, do final para o começo da memória.�ando um valor é inserido na pilha, o apontador de pilha é decrementado, antes da movimentação dos dados, de um valor igual aotamanho do dado a ser colocado na pilha. �ando um valor é retirado da pilha, o apontador é incrementado, depois da movimentação dos dados, de um valor igual ao tamanho do dado retirado na pilha. 3.5 TIPOS DE ARQUITETURA DE PROCESSADORES Os processadores podem ter diversos tipos de arquitetura que se diferenciam basicamente em relação à forma de acesso e de armazenamento interno dos operandos para a execução das instruções. Faremos nesta seção uma breve introdução aos seguintes tipos de arquitetura: • Pilha • Acumulador • Memória-Memória • Registrador-Memória • Registrador-Registrador Para cada uma dessas arquiteturas mostraremos na Tabela 3.1 como realizar a operação C := A+B em detalhes, utilizando pseudo instruções em linguagem de montagem. A arquitetura do tipo Memória-Memória é a que apresenta o menor número de instruções na tradução da linguagem de alto nível para a linguagem de máquina, contudo, como veremos a seguir, essa compactação de código vem com um custo adicional em termos de complexidade e tempo de execução do programa. 20 21 .2 3.5. Tipos de Arquitetura de Processadores 155 Pilha Acumulador Memória-Memória Registrador- Memória Registrador- Registrador PUSH A LOAD A ADD C, B, A LOAD R1, A LOAD R1, A PUSH B ADD B ADD R1, B LOAD R2, B ADD STORE C STORE C, R1 ADD R3, R1, R2 POP C STORE C, R3 Tabela 3.1 – Tipos de Arquitetura 3.5.1 Arquitetura de Pilha Nos processadores com arquitetura de pilha todos os operandos implicitamente estão no topo da pilha. Com isso, as instruções gastam menos bits, quando comparados com as arquiteturas com registrador, para codificar a origem e destino das operações. Isso era uma propriedade importante nos computadores mais antigos, pois resultava em um tamanho menor para a codificação das instruções, permitindo uma significativa economia de memória. Figura 3.14 – Arquitetura de Pilha © 2016 Gabriel P. Silva As únicas operações de acesso à memória são “POP” e “PUSH”, para retirar e colocar um operando no topo da pilha. Normalmente os primeiros elementos no topo da pilha se encontram junto ao processador e o restante da pilha é distribuído na memória a partir do endereço dado pelo apontador de pilha. A Figura 3.14 representa um modelo desta arquitetura. A máquina virtual Java pode ser considerado um exemplo moderno deste tipo de arquitetura. ✞ ☎ PUSH A PUSH B ADD POP C ✝ ✆ No exemplo mostrado acima, podemos verificar que a operação C := A+B é feita 20 21 .2 156 3. O computador e o processador colocando-se primeiro o valor da variável A no topo da pilha, com a a instrução PUSH A. Logo a seguir a variável B é colocado no topo da pilha com a instrução PUSH B. Agora, com os valores de A e B já colocados nas duas primeiras posições da pilha, a instrução ADD é executada, somando esses dois valores e o resultado é colocado por sua vez no topo da pilha. A seguir o resultado é retirado do topo da pilha e escrito na variável C em memória com a instrução POP C. 3.5.2 Arquitetura de Acumulador A arquitetura de acumulador possui o acumulador com um dos operandos implícitos na maioria instruções. O acumulador é um registrador especial colocado junto à unidade aritmética e lógica (UAL) com o intuito de agilizar as operações que são realizadas pelo processador. Se todas as operações fossem realizadas diretamente com todos os operandos em memória provavelmente haveria um grande impacto negativo no desempenho desses processadores, já que tempo gasto para acessar os dados na memória é bem maior que o tempo para acessar o dado armazenado no acumulador. É um modelo de arquitetura muito utilizado em processadores mais simples, tantos nos processadores mais antigos como nos modernos processadores embarcados, por ser de fácil implementação e ser uma solução de compromisso entre custo e desempenho. Exemplos modernos de arquitetura de acumulador são os processadores PIC e o 8051. A Figura 3.15 representa um modelo desta arquitetura. ✞ ☎ LOAD A ADD B STORE C ✝ ✆ No exemplo mostrado acima, podemos verificar que a operação C := A+B é feita colocando-e primeiro o valor da variável A no acumulador, com a instrução LOAD A. Logo a seguir o acumulador é somado com a variável B com a instruçãoADDB, sendo que o resultado é colocado de volta no acumulador. A seguir o resultado é retirado do acumulador e escrito na variável C em memória com a instrução STORE C. 3.5.3 Arquitetura Memória-Memória Os processadores com arquitetura memória-memória possuem instruções aritméticas e ló- gicas com todos os operandos colocados de forma explícita, ou seja, possuem um total de 3 operandos, podendo estar todos em memória. Embora em sua maioria não dispensem o uso também de registradores, as instruções aritméticas e lógicas podem referenciar todas as suas variáveis diretamente na memória. Normalmente o código gerado para essas máquinas possui um número menor de instruções mas que, por sua vez, resultam em arquiteturas com imple- 20 21 .2 3.5. Tipos de Arquitetura de Processadores 157 Figura 3.15 – Arquitetura de Acumulador © 2016 Gabriel P. Silva mentação bastante complexa. Um exemplo de arquitetura deste tipo é o VAX, um processador bastante comercializado nas décadas de 70 e 80 no século passado. ✞ ☎ ADD C, B, A ✝ ✆ No exemplo mostrado acima, podemos verificar que a operação C := A+B é feita com apenas uma única instrução ADD C, B, A que lê as variáveis A e B da memória, realiza a soma e escreve o resultado de volta na memória na variável C. 3.5.4 Arquitetura Registrador-Memória Os processadores com arquitetura registrador-memória normalmente possuem instruções aritméticas e lógicas com dois operandos, sendo que um deles está em memória e o outro em registrador. O resultado da operação é escrito automaticamente no mesmo registrador. Os exemplos clássicos deste tipo arquitetura são o IBM 360 e os processadores da linha Intel x86. ✞ ☎ LOAD R1, A ADD R1, B STORE C, R1 ✝ ✆ No exemplo mostrado acima podemos verificar que a operação C := A+B é realizada colocando-se primeiro o valor da variável A no registrador R1, com a instrução LOAD R1, A. Logo a seguir o valor armazenado no registrador é somado com a variável B com a instrução ADD R1, B, sendo que o resultado é colocado de volta no registrador R1. A seguir o resultado é copiado do registrador R1 e escrito na variável C em memória com a instrução STORE C, R1. 20 21 .2 158 3. O computador e o processador 3.5.5 Arquitetura Registrador-Registrador Os processadores com arquitetura registrador-registrador possuem características particulares. A primeira delas é que as instruções aritméticas e lógicas possuem os três operandos em registrador, sendo dois de origem e um destino. As únicas instruções que fazem acesso à memória são “LOAD”, para carregar os dados da memória para os registradores e “STORE”, para fazer o caminho inverso. Figura 3.16 – Arquitetura de Registrador © 2016 Gabriel P. Silva A compilação dos programas em alto nível resultam um código com um maior número de instruções, porém mais simples. Essas características permitem o desenvolvimento de projetos de processadores mais simples e, em consequência, mais rápidos e com menor consumo de energia. Por isso é o modelo de arquitetura, característico das arquiteturas RISC (veja a Seção 3.8), é o mais disseminado entre os processadores comerciais atualmente. A Figura 3.16 apresenta um modelo simplificado desta arquitetura. ✞ ☎ LOAD R1, A LOAD R2, B ADD R3, R1, R2 STORE C, R3 ✝ ✆ No exemplo mostrado acima, podemos verificar que a operação C := A+B é feita colocando-se primeiro o valor da variável A no registrador R1 com a instrução LOAD R1, A. Logo a seguir o registrador R2 recebe o valor da variável B com a instrução LOAD R1, B. Depois conteúdo de R1 é somado com R2 e o resultado é colocado no registrador R3. A seguir o valor armazenado em R3 é escrito na variável C em memória com a instrução STORE C, R3. 20 21 .2 3.6. Modos de Endereçamento 159 3.6 MODOS DE ENDEREÇAMENTOEm uma arquitetura de processador as instruções podem ter diversos modos de acessar os seus operandos. Os operandos podem ser constantes ou variáveis em registrador ou memória. Alguns modos de endereçamento existentes podem ser vistos a seguir: • Registrador ou Acumulador ADD R4, R3⇒ Regs[4] ← Regs[4]+Regs[3] Operando no registrador ou acumulador. • Imediato ADD R4, #8⇒ Regs[4] ← Regs[4]+8 Operando é uma constante na instrução. • Direto ou Absoluto ADD R1, (1001)⇒ Regs[1] ← Regs[1]+Mem[1001] Operando em memória com endereço na instrução. • Indireto (via Registrador) ADD R4, (R1)⇒ Regs[4] ← Regs[4]+Mem[Reg[1]] Operando em memória com endereço no registrador. • Indireto via Memória ADD R2, @(1003)⇒ Regs[2] ← Regs[2]+Mem[Mem[1003]] Operando em memória com endereço na memória. • Deslocamento ADD R2, 100(R1) ⇒ Regs[2] ← Regs[2]+Mem[R1+100] Operando em memória com endereço obtido pela soma do conteúdo do registrador com uma constante. • Indexado ADD R2, (R3+R4) ⇒ Regs[2] ← Regs[2]+Mem[R3+R4] Operando em memória com endereço obtido pela soma do conteúdo dos registradores. • Pilha PUSH ⇒ SP = SP +1 ; MEM[SP] ← ACC A pilha é um operando implícito da instrução 20 21 .2 160 3. O computador e o processador Note que uma instrução pode fazer uso de modos diferentes para buscar cada um dos seus operandos. A Figura 3.17 ilustra alguns modos de endereçamento. Figura 3.17 – Modos de Endereçamento © 2020 Gabriel P. Silva • No modo registrador ou acumulador, o operando da instrução está armazenado em um registrador ou no acumulador. Note que no caso do acumulador, ele será um operando implícito da instrução, e não aparecerá no código em linguagem de montagem. • No modo imediato o valor do operando está codificado na própria instrução ou em bytes subsequentes a ela. • No modo direto, o valor codificado na instrução (ou nos bytes subsequentes) não é operando em si, mas o endereço do operando na memória. Um novo acesso precisa ser realizado para acessar o dado propriamente dito. • No modo indireto, alguma vezes chamado de modo indireto via registrador, o registrador não possui o operando, mas o endereço do operando na memória. Aqui também é necessário um acesso à memória para buscar o operando. • Nomodo indireto via memória, a instrução (ou os bytes subsequentes) contém o endereço de memória da posição de memória que tem o endereço do operando. São necessários dois acessos à memória para buscar o operando. 20 21 .2 3.7. Ordenação dos bytes na memória 161 • No modo deslocamento, a instrução (ou os bytes subsequentes) contém uma constante que é somada ao conteúdo de um registrador, também especificado na instrução, para obter o endereço do operando na memória. É necessário mais um acesso à memoria para buscar o operando da instrução. • No modo indexado, o valor codificado na instrução indica quais registradores devem ter seus conteúdos somados para obter-se o endereço do operando na memória. É necessário mais um acesso à memoria para buscar o operando da instrução. • No modo pilha, o apontador de pilha (SP) é utilizado para endereçar a memória e buscar o operando, de uma forma implícita. Existem ainda outros modos de endereçamento mais complexos utilizado por diversos processadores, mas cujo estudo foge ao escopo deste livro. Para maiores informações reco- mendamos a consulta ao livro de Hennessy e Pa�erson (HENNESSY JOHN L. ; PATTERSON, 2017). 3.7 ORDENAÇÃO DOS BYTES NA MEMÓRIA Uma variável com mais de um byte de comprimento pode ser armazenada de duas formas diferentes, de acordo com a ordenação que o processador dá para a sequência de bytes dessa variável na memória. Estes modos de ordenação são conhecidos com big-endian e li�le-endian. Um sistema big-endian armazena o byte mais significativo de uma palavra no menor endereço de memória e o menos significativo no maior. Um sistema li�le-endian, por outro lado, armazena o byte menos significativo no menor endereço. Os computadores armazenam as varáveis em vários grupos de tamanhos binários. Na maioria dos computadores modernos, o menor grupo de dados com um endereço tem oito bits e é chamado de byte. As variáveis com dois ou mais bytes, por exemplo, uma variável de 32 bits contém quatro bytes, possui duas maneiras distintas para um computador ordenar os seus bytes individuais na memória e, ao longo da história da computação, os dois métodos foram usados, levando a alguns problemas ocasionais. Internamente, qualquer computador funciona igualmente bem, independentemente de qual ordenação ele usa, já que seu hardware usa consistentemente a mesma ordenação para armazenar e carregar seus dados. Por esse motivo, programadores e usuários de computador normalmente ignoram a ordenação do computador com o qual estão trabalhando. No entanto, essa ordenação pode se tornar um problema ao mover dados externamente ao computador – como ao transmitir dados entre computadores diferentes pela internet, ou um programador investigando bytes de dados internos do computador a partir de um dump de memória – e a ordenação usada difere do esperado. Nesses casos, a ordenação dos dados deve ser entendida e levada em consideração. Por exemplo, o formato de codificação de caracteres UTF-16 e UTF-32 (veja Seção 1.2) usam unidades de código com dois e quatro bytes de comprimento, respectivamente. Para essas 20 21 .2 162 3. O computador e o processador codificações UTFs, existem três variantes: big-endian (BE), li�le-endian (LE) e não marcado. O formato BE usa serialização de bytes com o byte mais significativo primeiro, o formato LE usa serialização de bytes com o byte menos significativo primeiro e o formato não marcado usa serialização de bytes big-endian por padrão, mas pode incluir um marcador com a ordem de bytes (BOM em inglês) no início da transmissão para indicar a serialização de bytes real usada. Um marcador de ordem de bytes (BOM) consiste no código de caractere U+FEFF no início de um fluxo de dados, onde pode ser usado como uma assinatura que define a ordem de bytes e a forma de codificação, principalmente de arquivos de texto simples não marcados. Em alguns protocolos de nível superior, o uso de um BOM pode ser obrigatório (ou proibido) no fluxo de dados Unicode definido nesse protocolo. Tabela 3.2 – Formato da Codificação Unicode Bytes Formato da Codificação 00 00 FE FF UTF-32, big-endian FF FE 00 00 UTF-32, li�le-endian FE FF UTF-16, big-endian FF FE UTF-16, li�le-endian EF BB BF UTF-8 Embora desnecessário, alguns arquivos com formato UTF-8 podem vir com a sequência 0xEFBBBF no seu início, o que pode gerar problemas de conversão quando transferidos entre sistemas operacionais diferentes, como por exemplo, do Windows para o Linux ou vice-versa. Ambos os tipos de ordenação são amplamente utilizados no desenvolvimento dos processa- dores. A escolha inicial da ordenação de um novo projeto geralmente é arbitrária, mas revisões e atualizações de tecnologia posteriores perpetuam essa ordenação existente e muitos outros atributos de projeto para manter a compatibilidade com versões anteriores. O li�le-endian é a ordem dominante para arquiteturas de processador (x86, originalmente as implementações de ARMmais antigas, além do RISC-V) e nas respectivas memórias associadas. Por outro lado, a ordenação utilizada nos processadores Motorola 68K; nas versões mais antigas do SPARC (V8 de 32 bits) e PowerPC; e na maioria dos protocolos de rede é o big-endian, como no conjunto de protocolos da Internet, onde é chamada de ordem de rede, transmitindo o byte mais significativo primeiro. Algumas arquiteturas, como os processadores MIPS; as versões mais recentes do ARM, PowerPC (Motorola) e SPARC V9 de 64 bits (Sun/Oracle) podem fazer uso de um ou outro modo de ordenação indistintamente, a partir de uma configuração em um registrador de controle, e por isso são chamadas de bi-endian. Uma curiosidade a respeito da origem dos termos li�le-endian e big-endian, que se deve a um artigo“On Holy Wars and a Plea For Peace” de Danny Cohen publicado em 1 de abril (sic!) de 1980 (Danny Cohen, 1980). Uma versão editada apareceu na IEEE Computer Magazine, em outubro de 1981. 20 21 .2 3.8. RISC versus CISC 163 Figura 3.18 – Ordenação dos bytes h�ps://www.wikiwand.com/en/Endianness Este artigo clássico, muito influente e divertido, introduziu os termos li�le-endian e big- endian e instou as pessoas a parar de travar guerras sagradas em torno de qual ordenação de bytes era melhor. Ainda é uma leitura obrigatória para qualquer pessoa que tenha algum interesse relativo à ordenação de bytes. Os termos li�le-endian e big-endian foram emprestados da sátira de Swi�, “Viagens de Gulliver” (SWIFT, 2004), na qual dois países entraram em guerra pela questão sobre qual extremidade de um ovo cozido, a menor ou a maior (li�le end ou big end), ele deveria ser quebrado para ser consumido. Anteriormente, a ordenação dos bytes na memória tinha sido alvo de discussões intensas, tanto na indústria e academia, mas que se acalmaram bastante nos últimos anos. 3.8 RISC VERSUS CISC Um dos objetivos da arquitetura de um processador é permitir a execução dos programas o mais rapidamente possível. Há várias técnicas que são empregadas para isso, mas de uma forma simplificada o tempo de execução de um programa pode ser definido pela seguinte equação: Tp = Ci × Tc ×Ni (3.1) Onde, 20 21 .2 164 3. O computador e o processador - Tp = tempo de execução do programa - Ci = ciclos gastos em média por instrução - Tc = tempo de duração de um ciclo - Ni = número de instruções do programa O Ci também é conhecido com CPI (Ciclos por Instrução) e define o número médio de ciclos gastos por cada instrução. É um valor que varia de acordo com o tipo de programa, por exemplo, inteiro ou de ponto flutuante, além da arquitetura do processador e é obtido dividindo-se o número total de ciclos de relógio gastos para executar um programa pelo total de instruções executadas. O seu inverso é IPC (Instruções por Ciclo) e tem sido usado mais modernamente na arquiteturas superescalares, para indicar o número de instruções, normalmente maior do que um, que podem ser executadas a cada ciclo de relógio do processador. O tempo do ciclo (Tc) é o inverso da frequência do relógio, segundo a fórmula: Tc = 1 F (3.2) Por exemplo, se a frequência do relógio for 100 MHz (100×106), o tempo de ciclo de relógio será de 10 ns (10× 10−9). Logo, quando maior a frequência do relógio, menor será o tempo de ciclo de relógio, normalmente expresso em nanosegundos, e menor será o tempo total de execução do programa. Logo, se buscava reduzir o tempo de execução aumentando ao máximo a frequência do relógio. Mas isso tem um limite em função do atraso dos componentes do processador, assim como da potência que pode ser dissipada pelo conjunto encapsulamento e dissipador. Uma outra forma de melhorar o desempenho é diminuir o número total de instruções (Ni) gastas para traduzir um programa da linguagem de alto nível para a linguagem de máquina, assim sendo, instruções cada vez mais complexas eram implementadas no conjunto de instruções do processador. Essas instruções podiam realizar de uma só vez várias operações complexas, acessando o maior número possível de operandos de uma única vez, com vários e diversos modos de endereçamento possíveis. Mas a contrapartida é que o número de ciclos para executar cada instrução era muito maior, e um hardware mais complexo resultava em frequências de relógio menores, dado o longo tempo necessário para a decodificação das instruções. Essa aproximação foi utilizada pelas arquiteturas CISC (complex instruction set computers), utilizada nas primeiras arquiteturas de processadores, incluindo aquelas utilizadas nos primeiros microprocessadores, sendo absolutos até o início da década de 80. No início da década de 80 surgiu nas universidades americanas (Berkley e Stanford especi- ficamente), uma nova proposta de arquitetura para os processadores. Nesse novo conceito, 20 21 .2 3.8. RISC versus CISC 165 procurava-se reduzir o tempo de execução dos programas através da diminuição do número de ciclos gastos para executar cada instrução e também no tempo de duração de cada ciclo de máquina. Para atingir esse objetivo as instruções foram simplificadas ao máximo, realizando cada uma delas o menor número operações e com a menor quantidade de operandos possível. Além disso, os modos de endereçamento dos operandos utilizados eram extremamente simples, com o objetivo de diminuir a complexidade do hardware do processador. As novas arquiteturas receberam o nome de RISC (Reduced Instruction Set Computers). A consequência negativa disso é que um maior número de instruções em linguagem de máquina eram necessárias para codificar um programa em linguagem de alto nível quando comparados com as arquiteturas convencionais da época, mas fato esse plenamente compensado pelos demais ganhos que a arquitetura apresentava. Durante a década que se seguiu um intenso debate foi realizado sobre qual tipo de arquite- tura seria melhor e mais rápida. Porém, no início da década de 90, os processadores RISC se estabeleceram como o padrão de arquitetura no mercado. Exemplos de arquitetura CISC eram então os processadores x86 da Intel. Já os processadores SPARC, MIPS e ARM são exemplos de arquiteturas RISC. Atualmente os processadores da Intel são uma arquitetura híbrida, sendo externamente compatíveis com o código da arquitetura x86, mas que são traduzidas em tempo de execução para as instruções RISC da arquitetura interna que efetivamente executam as instruções. Resumindo, as arquiteturas CISC apresentavam as seguintes características: • Instruções complexas demandando um número grande e variável de ciclos de máquina para sua execução; • Uso de diversos modos de endereçamento de operandos; • Instruções com formato muito variável; • Diferentes tipos de instruções podiam referenciar operandos na memória principal; • Cada fase do processamento da instrução podia ter duração variável em função da complexidade. �e resultavam nas seguintes consequências: • Implementação com uso de pipeline (vamos ver mais adiante) é difícil; • A taxa média de execução das instruções por ciclo tende a ser bastante superior a 1 ciclo por instrução (CPI); • A unidade de controle é em geral microprogramada; • Códigos compactos podem ser gerados pelos compiladores; Por outro lado as arquiteturas RISC ofereciam as seguintes características resumidamente: 20 21 .2 166 3. O computador e o processador • Instruções mais simples demandando um número fixo de ciclos de máquina para sua execução; • Uso de poucos modos simples de endereçamento de operandos; • Poucos formatos diferentes de instruções; • Apenas as instruções de load e store referenciam operandos na memória principal; • Cada fase de processamento da instrução tem a duração fixa igual a um ciclo de máquina. Resultando também nas seguintes consequências: • São implementadas com o uso do pipeline; • A taxa média de execução de instruções por ciclo de máquina é igual ou inferior a 1 ciclo por instrução (CPI); • A unidade de controle é em geral hardwired ; • O processo de compilação é complexo e requer cuidados especiais para otimização do desempenho do código gerado.