Arquitectura de Computadores

Notas de estudo

Alberto José Proença

1999/00

 

Índice geral

 

  1. Organização e arquitectura dum computador
  2. Análise do funcionamento do CPU dum computador
  1. Operações num processador
  2. Localização dos operandos
  3. Formato das instruções
  4. Instruções para tomada de decisões

 

A análise do funcionamento do processador dum computador - o principal elemento responsável por processar a informação dentro de um computador - é feita seguindo o modelo proposto no texto de apoio (ver 3.1, 3.2, 3.3, 3.4, e 3.5). Estas secções complementam a visão genérica sobre o funcionamento dum computador apresentada no capítulo anterior, e concentram-se no funcionamento do processador e sua relação com a memória, introduzindo-se igualmente várias instruções de linguagem máquina.

 

  1. Operações num processador

Qualquer processador tem capacidade para efectuar operações aritméticas e lógicas com valores do tipo inteiro. Na especificação de uma dessas operações, a realização física dos processadores (i.e., os circuitos digitais) impõem normalmente algumas limitações: os processadores apenas efectuam operações a partir de, no máximo, 2 operandos fonte. Por outras palavras, as instruções que são utilizadas para a realização de operações no processador precisam de especificar normalmente 3 operandos: 2 para fonte e um para destino.

• Nº de operandos em cada instrução

Quando o formato de instrução o permite, a especificação dos 3 operandos - para a realização de operações no processador - vêm directamente na própria instrução. Assim, se a operação pretendida é "a= b+c", uma instrução em linguagem máquina poderá ser "add a,b,c".

A maioria das arquitecturas de processadores existentes actualmente (e normalmente designadas por arquitecturas RISC, Reduced Instruction Set Computers) suportam este tipo de operação com especificação explícita de 3 operandos, mas com uma restrição: todos esses operandos deverão estar em registos. O motivo para esta limitação está relacionado com a própria filosofia RISC: as instruções deverão ser simples e rápidas. Operandos em memória introduzem acções extras no processador que podem conduzir a atrasos significativos na execução da instrução e comprometem o seu funcionamento interno em modo encadeado (pipeline na terminologia anglo-saxónica).

As arquitecturas processadores de baixo custo de gerações anteriores tinham limitações para representar os 3 operandos na instrução. As mais antigas - os microprocessadores dos anos 70 - apenas especificavam 1 operando, sendo o 2º operando fonte e o destino alocado implicitamente a um mesmo registo, designado por acumulador; a operação efectuada pelo CPU é do tipo "Acc= Acc <op> x". Outras, mais recentes (família Intel x86 e Motorola 68k, no início dos anos 80), especificam normalmente 2 operandos: um deles é simultaneamente fonte e destino (a= a+b).

Os exemplos na secção 3.2 introduzem a notação assembly a usar ao longo deste curso, bem como instruções do MIPS para adição e subtracção de inteiros (add e sub).

 

  1. Localização dos operandos

 • Variáveis escalares

Para que as instruções sejam executadas com rapidez e eficiência, os operandos deverão ser acedidos à velocidade de funcionamento do processador. Idealmente, todos os operandos - que incluem as variáveis dos programas desenvolvidos pelo utilizador - deveriam assim estar disponíveis em registos. Para que tal aconteça é necessário um n.º bastante elevado de registos. Contudo, com a evolução da tecnologia dos compiladores, tornou-se possível representar a maioria das variáveis escalares de qualquer programa usando apenas os 32 registos genéricos que as arquitecturas contemporâneas disponibilizam.

• Variáveis estruturadas

Na representação de variáveis estruturadas tal situação já se torna mais impraticável. As variáveis estruturadas são mantidas na memória. Dado que cada célula de memória é de 8 bits, convém não esquecer que quase todas as variáveis numéricas ocupam mais que uma célula: os inteiros nas arquitecturas RISC ocupam 32 bits, enquanto os reais ocupam 32 ou 64 bits, consoante são de precisão simples ou dupla. Os exemplos na secção 3.3 ilustram a utilização das instruções assembly para leitura/escrita dessas posições de memória. Mais concretamente, introduzem as instruções de leitura para registo de uma palavra de 32 bits (lw) e de escrita do conteúdo dum registo na memória (sw).

 

  1. Formato das instruções

A codificação das instruções assembly para linguagem máquina deverá ser compacta para que as instruções ocupem pouca memória e para que a sua transferência para o CPU seja rápida.

• Comprimento das instruções

Quando o custo das memórias e dos processadores era considerável, os instruction sets dos processadores eram compactados para pequenas dimensões (8 bits), à custa de compromissos com o n.º de operandos a incluir e com a utilização de instruções de comprimento variável (com consequências nefastas para um funcionamento em pipeline). Processadores projectados nos anos 70 e inícios de 80, considerados de processadores de 16-bits, centraram neste valor (16 bits) a dimensão mínima e/ou básica para o formato de instrução, mas incluindo sempre a possibilidade de conterem extensões de várias palavras extra.

As arquitecturas RISC tiveram como um dos seus objectivos a definição de formatos de instrução de comprimento fixo, e de dimensão tal que permitisse especificar os 3 operandos: 32 bits.

• Campos duma instrução

No formato de cada instrução em linguagem máquina é sempre possível identificar um conjunto de campos com informação bem definida: um campo que caracterize a operação a efectuar (normalmente designado por opcode) e tantos campos quantos o n.º de operandos que for possível especificar.

Uma análise detalhada dum dado processador permite verificar como esta estrutura é seguida por esse fabricante. A secção 3.4 analisa com algum detalhe 2 formatos presentes no MIPS (o tipo-R e o tipo-I), enquanto a secção 3.5 introduz o 3º formato de instrução do MIPS: o tipo-J.

O formato tipo-R é o utilizado pelas operações que necessitem de especificar 3 operandos em registos: 12 bits são usados para especificar a operação, 3x5 bits para seleccionar cada um dos 32 registos para fonte e destino, e os restantes 5 bits para uma operação adicional.

O formato tipo-I é o utilizado nas instruções que não necessitem de especificar 3 registos: ou porque um dos operandos pode vir incluído no formato da instrução (caso das constantes) ou porque há necessidade de incluir explicitamente um valor para se efectuar um cálculo de um endereço de memória.

O formato tipo-J é o utilizado nas instruções de salto para um endereço absoluto, no qual apenas 6 bits são usados para especificar a operação e os restantes 26 para especificar o endereço.

• Pseudo-instruções

A estrutura interna da maioria dos processadores RISC permite reduzir ainda mais o n.º de instruções do seu instruction set através da utilização específica de outras instruções e da imposição de uma restrição a um dos seus 32 registos: um deles é apenas de leitura e contém o valor 0 (no MIPS é o Reg 0). Com esta característica não se torna necessário, por exemplo, incluir uma instrução que mova o conteúdo de um registo para outro (normalmente representado por "move a,b"), pois essa mesma operação pode ser implementada com a operação "add Rdest, Rfonte, Reg0"). Há no entanto vantagem em que o assembler suporte esta pseudo-instrução para simplificação da programação em assembly. Muitas outras instruções deste tipo serão identificadas ao longo do curso.

 

  1. Instruções para tomada de decisões

• Saltos condicionais e incondicionais

A execução de qualquer programa pressupõe normalmente a tomada de decisões quanto à próxima instrução a executar. As estruturas de controlo presentes nas linguagens HLL incluem essencialmente o "if...then...else" e os ciclos. As instruções em linguagem máquina que suportam estas estruturas são de nível mais baixo: apenas executam testes que poderão ser seguidos de saltos condicionais ou incondicionais para uma determinada localização de memória, onde se encontre o bloco de instruções para executar. Os exemplos na secção 3.5 ilustram instruções de salto condicionais disponibilizadas pelo MIPS (beq e bne), bem como as instruções de salto incondicional (j, jr).