Ciclo de uma Instrução Na coluna anterior vimos que microprocessadores são circuitos integrados versáteis, capazes de executar diferentes operações de acordo com as instruções que recebem. Aprendemos ainda o que é uma instrução e vimos que um programa é um conjunto de instruções encadeadas. Com isso podemos prosseguir nosso caminho para destrinchar o funcionamento – e o procedimento de inicialização – de um computador. O microprocessador é apenas um dos componentes de um computador. O mais importante deles, é verdade, mas que pouco pode fazer sozinho. Por isso o microprocessador está inserido em um grande circuito impresso denominado “placamãe” (do inglês “motherboard”). Se você abrir o gabinete de seu computador poderá vê-la com facilidade no fundo dos gabinetes horizontais ou junto a uma das paredes laterais dos gabinetes verticais. A placa-mãe contém centenas de componentes. Para o que nos interessa, fixemos nossa atenção em quatro deles, o microprocessador, também conhecido como Unidade Central de Processamento, ou UCP, a Memória Principal (MP, ou memória RAM), os encaixes para as controladoras dos dispositivos de entrada e saída (ou “slots”) e o barramento (conjunto de condutores elétricos e seus circuitos de controle que interliga os demais elementos da placa-mãe). O aspecto de uma placa-mãe é o mostrado na Figura 1, onde estão assinalados os “slots”, o soquete onde se encaixará a unidade central de processamento (UCP) e os conectores onde serão inseridos os módulos da memória principal (MP). Os condutores elétricos que formam o barramento podem ser percebidos sob a forma de finos riscos dourados sobre a placa. Figura 1: Aspecto de uma placa-mãe O microprocessador é o “coração” de um computador. A ele compete processar dados, executando as instruções em uma determinada seqüência. Portanto, ele só pode funcionar se for continuamente alimentado com instruções, uma após a outra. Instruções, como vimos na coluna anterior, são números que o microprocessador interpreta como ordens (ou comandos) para executar determinadas ações que, em conjunto, constituem um programa. Para que possam ser introduzidas no microprocessador, as instruções devem estar armazenadas em algum lugar. Esse lugar é a memória principal, ou “memória RAM”. Daqui para diante vamos nos referir a ela como MP. Nos computadores modernos a MP é constituída por um conjunto de circuitos integrados montados em plaquetas de circuito impresso denominadas módulos de memória (ou “pentes” de memória). Cada um deles abriga um grande número de “células” de memória. Cada célula da MP pode assumir um dentre dois estados diferentes (nos módulos de memória cujas células são formadas por microscópicos capacitores, estes estados são “carregado” e “descarregado”). Se associarmos um destes estados ao valor “um” e outro ao valor “zero”, poderemos usar uma célula da MP para armazenar um “bit” (“bit” é a contração da expressão inglesa “binary digit”, ou “algarismo binário”; “um” e “zero” são os dois únicos algarismos utilizados para representar qualquer número no sistema numérico binário, ou de base dois, usado internamente nos computadores). Se agruparmos células adjacentes oito a oito, cada conjunto de oito células pode armazenar oito bits, ou um “byte”. Este grupo de oito células forma uma “posição” de memória. Então, do ponto de vista lógico, a MP é um enorme conjunto de posições de memória, cada uma capaz de armazenar um byte. A memória só tem serventia para armazenar dados se for possível recuperá-los mais adiante, quando for preciso usá-los. Portanto, se eu armazeno um dado em uma posição de memória, preciso identificá-la para que mais tarde eu possa voltar a ela para buscar meu dado. Para que isso seja possível cada posição de memória é associada a um número, ou “endereço”. Logo, se do ponto de vista físico a memória principal é formada por um ou mais módulos contendo circuitos integrados, do ponto de vista lógico ela nada mais é que uma imensa pilha de posições de memória identificadas por seus endereços, cada uma com oito células. Veja, na Figura 2, um diagrama esquemático da mesma placa-mãe mostrada na Figura 1, porém vista sob seu aspecto lógico. Repare na memória principal: no esquema usado como exemplo, ela é constituída por 256 posições de memória de oito células cada, identificadas por seus endereços que vão de zero a 255 (números em azul, mostrados tanto em decimal quanto em binário). Figura 2: Placa-mãe, diagrama esquemático Agora, examinemos os demais componentes. No alto, à direita, aparecem os “slots”, conectores elétricos nos quais são encaixadas as placas controladoras dos periféricos, ou dispositivos de entrada e saída. Deixê-mo-los de lado por ora, eles nada têm a ver com nosso assunto de hoje. Em baixo, à direita, aparece a UCP e seus componentes internos. Já voltaremos a ela. Antes, examinemos o barramento. O barramento é representado por um conjunto de linhas paralelas em verde, azul e vermelho. Essas linhas interligam os três outros elementos: o conjunto dos slots, a CPU e a MP (mais especificamente, o circuito integrado controlador da MP, que faz parte do barramento e que controla as operações de leitura e escrita na memória). O trecho do barramento representado pelas linhas verdes é chamado de “barramento de dados”. Nessas linhas, apenas circulam dados. O trecho do barramento representado pelas linhas azuis é o “barramento de endereços”. Como é de esperar, nessas linhas somente circulam endereços. Note que tanto dados quanto endereços são números representados no sistema binário que usa apenas os algarismos “um” e “zero”. Portanto, tanto dados como endereços circulam no barramento sob a forma de pulsos elétricos (tensões elétricas aplicadas por um curto período) simultâneos nas diversas linhas, onde uma linha que transporta um pulso representa “um” e a que apresenta ausência de tensão naquele mesmo momento representa um “zero’. Já o trecho do barramento representado pelas linhas vermelhas é o barramento de controle. Nele também circulam pulsos elétricos, mas nesse caso os pulsos não precisam necessariamente serem combinados para formar números. Cada linha tem sua função, e os pulsos que as percorrem são interpretados como sinais de controle de acordo com a função da linha correspondente. Agora, sim, vamos dar uma espiada na UCP. Ela consiste de quatro elementos: Unidade de Controle, a Unidade Lógica e Aritmética (ULA), os Registradores (Regs.) a Unidade de Entrada e Saída (representada por um canal por onde circulam dados dois registradores especiais, o Registrador de Dados da Memória, ou RDM, e Registrador de Endereços da Memória, ou REM). a e e o A ULA é o elemento da UCP capaz de executar operações aritméticas (somas, subtrações, multiplicações, etc.) e lógicas (comparações, deslocamentos ou complementos de bits, etc.). Ela é usada quando a execução de uma instrução exige uma destas operações. No momento, ela não nos interessa. A Unidade de Controle, ou UC, é a parte mais importante da UCP. Nela estão os circuitos lógicos que são acionados para executar cada instrução ao serem energizados pelo decodificador, que também faz parte dela (veja coluna anterior). É a UC que aciona a ULA, quando necessário, e providencia as operações de leitura e escrita na MP e nos dispositivos de entrada e saída. Seu funcionamento é bastante complexo, mas por ora nos interessa apenas um aspecto: a UC é a responsável pela execução das instruções. Cada vez que uma instrução é fornecida à UC, esta instrução é imediatamente decodificada e executada (já veremos como se fornecem instruções à UC). Os Registradores são posições de memória que se localizam dentro da UCP. Mas são posições de memórias tão importantes que não são identificadas por endereços (números), mas sim por nomes. Cada registrador tem um nome. Um deles, por exemplo, é o “Acumulador” (ACC), que geralmente recebe o resultado das operações efetuadas pela ULA. Registradores são usados todo o tempo pela CPU. Funcionam como uma espécie de “bloco de rascunho”. Neles são armazenados operandos das operações aritméticas ou lógicas, resultados intermediários, endereços, etc. Alguns são tão importantes que desempenham exclusivamente uma função. Como os dois assinalados na Figura 2, o Ponteiro de Instruções (PI) e Registrador de Instruções (RI), que desempenham papel fundamental na execução dos programas, como já veremos. Note que o RI é o único registrador que se comunica diretamente com a Unidade de Controle. A Unidade de Entrada e Saída da UCP controla não apenas a entrada e saída de dados e endereços como também efetua a comunicação entre seus componentes internos. Repare que ela comunica todos os registradores com a ULA e com seus dois registradores REM e RDM. A função do REM é conter o endereço da posição da MP onde se realizará cada operação de leitura ou escrita. Toda a vez que a UCP precisa se comunicar com a MP, seja para armazenar, seja para ler um dado em uma certa posição de memória, o endereço desta posição de memória é escrito no REM e enviado para a controladora da MP através do barramento de endereços. A unidade de controle da MP então “aponta” seus circuitos internos para a posição de memória correspondente a este endereço. A função do RDM é servir de “passagem” para dados que entram e saem da UCP. Quando um dado vai ser escrito na MP, ele é antes transcrito no RDM. A controladora da MP lê então no REM o endereço da posição da memória em que o dado deverá ser escrito e, através do barramento de dados, o envia do RDM para a controladora da MP, que providencia a escrita. Quando a operação é de leitura, a controladora da MP lê no REM o endereço da posição de memória de onde o dado deverá ser lido, vai “buscar” o dado no referido endereço e o transporta através do barramento de dados, escrevendo-o no RDM. Dados somente podem entrar e sair da UCP passando pelo RDM. Pronto, agora que conhecemos os diversos elementos envolvidos, poderemos entender como programas são executados. Embora a UCP seja eventualmente chamada de circuito “inteligente”, sua “inteligência” é bastante limitada. Na verdade, ela só sabe fazer uma coisa: executar continuamente o chamado “ciclo de busca e execução”. E ela faz isso durante todo o tempo em que está energizada, ou seja, desde o momento em que o micro é ligado até ele ser desligado. E é exclusivamente através da repetição contínua do ciclo de busca e execução que a UCP consegue executar todos os programas. Vejamos então no que consiste este ciclo. O ciclo de busca e execução consiste de três passos que são executados seqüencialmente e repetidos à exaustão. Vamos examiná-lo passo a passo. Imaginemos que, no momento em que começa a nossa observação, o Ponteiro de Instrução (PI) contenha o valor binário “01111001” (correspondente ao decimal “121”) em suas oito células de memória. Imaginemos ainda que na posição da MP cujo endereço é 121 exista o valor “00001011”, como mostrado na Figura 3. E imaginemos ainda que as posições de memória imediatamente acima da correspondente ao endereço 121 contenham os valores mostrados na Figura 3, que exibe o estado inicial dos registradores da UCP e das posições da MP ao começarmos a observar o ciclo. O conteúdo das demais posições da MP, assim como dos demais registradores da UCP, não são relevantes para nossa discussão e podem ser quaisquer. Figura 3: Estado inicial dos registradores e da MP Uma posição de memória, esteja ela na MP ou nos registradores, só pode conter um número expresso no sistema binário (no exemplo, tanto as posições de MP quanto os registradores têm oito células, ou seja, uma “largura” de oito bits, o que significa que podem conter um byte; os registradores dos modernos microprocessadores em geral têm uma largura de 64 bits, ou oito bytes, mas o do nosso exemplo, embora elementar, serve perfeitamente para ilustrar o ciclo de busca e execução). Esse número, no entanto, pode ter diversos significados ou funções, dependendo de como seja interpretado. Senão vejamos: todos os dados processados pelo computador são expressos sob a forma de números (ou seja, digitalizados; veja as colunas anteriores sobre digitalização de sons). Portanto, um número contido em uma posição de memória pode representar um dado. Por outro lado, como vimos na coluna passada, as instruções que o microprocessador decodifica e executa, também são números. Nos primórdios da era dos computadores havia uma memória específica para conter instruções e uma outra, independente, apenas para conter dados. Porém, durante o final da primeira metade do século passado, um genial matemático nascido na Hungria e naturalizado americano, John von Neumann (pronuncia-se “fón nóiman”), percebeu que isso complicava desnecessariamente a “arquitetura” (ou organização interna) dos computadores e sugeriu que tanto os dados quanto as instruções passassem a ser armazenadas na mesma memória, ou seja, na MP. Isso deu origem à chamada “arquitetura de von Neumann”. Hoje em dia, todos os computadores modernos são “máquinas de von Neumann”, ou seja, máquinas que armazenam tanto dados quanto instruções no mesmo espaço de endereçamento de memória. Portanto, um número contido em uma posição de memória também pode representar uma instrução. Finalmente, endereços de posições da memória principal também são números. E quando se deseja armazenar a referência a uma determinada posição da MP, armazena-se seu endereço em outra posição de memória. Portanto, um número contido em uma posição de memória também pode representar um endereço. As posições de memória, quando utilizadas para armazenar endereços de outras posições de memória, recebem a designação genérica de “Ponteiro”. Portanto, fica fácil concluir que o registrador denominado “Ponteiro de instruções”, ou PI, contém um endereço. Mais especificamente: contém o endereço da posição da MP que armazena a próxima instrução a ser executada. Então, o primeiro passo do ciclo de busca e execução consiste justamente em ir buscar esta instrução na memória principal e transcrevê-la no registrador denominado “Registrador de Instruções”, ou RI. Este passo, o da busca da instrução, está representado na Figura 4. A linha azul mostra o local (posição da MP) para o qual o PI “aponta”, enquanto a linha verde representa a tranporte do conteúdo daquela posição de memória para o RI. Figura 4: Representação do passo “busca”. Repare que, concluído este passo, o valor “00001011”, contido na posição de memória “apontada” pelo PI (de endereço 121, ou “01111001”) aparece transcrito no interior do registrador de instrução, ou RI. O segundo passo é um passo intermediário. Ele consiste simplesmente em ajustar o ponteiro de instruções de forma a fazê-lo apontar para o endereço da posição da MP que contém a instrução seguinte, a próxima a ser executada. Em princípio, essa instrução é a que fica na posição de memória subseqüente à da que acabou de ser transferida para o RI. Esclarecendo: se a instrução a ser executada neste ciclo é a contida na posição de MP de endereço 121, a próxima será aquela armazenada na posição cujo endereço é 122. Portanto, esse passo intermediário nada mais faz que incrementar (somar um, aumentar em uma unidade) o conteúdo do PI. Veja o resultado na Figura 5. O registrador PI contém agora o número “01111010”, que corresponde ao decimal 122. Note que a seta azul, que mostra o endereço da posição de memória para a qual PI está “apontando”, agora aponta para o endereço 122. Figura 5: Segundo passo: incrementando PI Note que PI foi incrementado antes que a instrução correspondente a este ciclo tenha sido executada. E há boas razões para isso. Se a instrução fosse executada e somente depois disso PI fosse incrementado, a instrução subseqüente seria obrigatoriamente a contida na posição de memória seguinte (no exemplo, a de endereço 122). Mas incrementar o ponteiro antes de executar a instrução enseja que o conteúdo de PI seja alterado durante a execução da instrução. Ou seja: o próprio programa pode controlar seu fluxo. Se não fosse isso, todo programa seria executado ordenadamente da primeira á última instrução, inexoravelmente, sem que o usuário pudesse alterar esta ordem. É justamente a possibilidade de que uma instrução altere o conteúdo do PI, decidindo assim que instrução será executada à seguir, que torna a arte da programação tão flexível e fascinante. Vale a pena pensar um pouco sobre isso para perceber a imensa complexidade que se esconde por detrás de um conceito tão singelo. Executados os dois primeiros passos, o terceiro é o mais simples de ser descrito, embora seja de fato o mais complexo de ser completado pela UCP: o número contido no RI (no exemplo, o valor “00001011”, transcrito da posição de memória 121) é introduzido na Unidade de Controle, interpretado como uma instrução, que é imediatamente executada. Este terceiro e último passo do ciclo de busca e execução é o passo da “execução”. Veja sua representação gráfica na Figura 6. Figura 6: Representação do passo “execução”. O que esta instrução faz, como ela é executada, que tarefas intermediários envolve, nada disso é relevante para a análise do ciclo de busca e execução. A única coisa que importa é que este ciclo, constituído pelos três passos acima descritos, é repetido indefinidamente pela UCP, ciclo após ciclo, durante todo o tempo em que o micro permanece ligado. Agora podemos entender porque pode-se armazenar dados, endereços e instruções no mesmo espaço de memória, já que todos são números. O micro funciona de forma absolutamente automática, introduzindo na UC o número contido no RI, interpretandoo como uma instrução que é decodificada e executada. Não importa como o número foi parar lá: se ele está no RI, será considerado uma instrução que será executada (o que explica alguns travamentos do computador: um programa mal concebido pode colocar no RI um número errado e o resultado pode ser desastroso). Na medida que os ciclos de busca e execução são repetidos, as instruções são executadas uma após a outra e o programa segue seu curso. E se você entendeu como funciona o ciclo de busca e execução, certamente já descobriu um ponto fundamental: para que uma instrução seja executada, é preciso que ela seja lida em uma das posições da MP e transferida para o RI. A própria natureza do ciclo de busca e execução impede que qualquer instrução seja executada se ela não for lida de uma posição da MP. Ou seja: para que um programa seja executado, é preciso que suas instruções sejam antes transcritas para a MP. Quem faz esta transcrição? Ou seja, quem “põe” o programa na MP? Quando descobrirmos isso na próxima coluna, estaremos a um passo de decifrar o aparente mistério do “boot”.