Introdução à Arquitetura de Computadores/As Operações da Unidade Lógica Aritmética

Computadores são máquinas de calcular. Logo, é fundamental que eles sejam capazes de realizar operações básicas como adição, subtração, divisão e multiplicação. Vamos ver agora como tais operações são implementadas dentro da Unidade Lógica Aritmética de um Processador (ULA).

A Adição e Subtração

editar

A Adição é uma das operações mais simples. Um computador realiza ela de uma maneira semelhante à usada por nós humanos. Ele começa somando os bits menos significativos. Caso tenha que somar "1" e "1", o resultado fica sendo "0" e passamos um "vai-um" para o bit à esquerda. Veja abaixo um desenho de um circuito capaz de somar dois números de 8 bits:

 

Embora a imagem mostre apenas um circuito que soma dois números de 8 bits, não é muito difícil perceber que a lógica para fazer um somador é a mesma, tanto para números com 8 como para 32 bits. Basta adicionar mais somadores. Perceba que o circuito também é capaz de detectar a presença de Overflow no caso de operações com números sem sinal.

Ele pode ser usado tanto para somar números com ou sem sinal. Graças à representação de números inteiros por complemento de dois, não é difícil conseguir isso.

O mesmo circuito acima também pode ser reaproveitado para realizar subtrações. Basta inverter antes todos os bits do segundo operando e somar 1 a ele. Com isso, estamos na verdade somando o primeiro operando com o negativo do segundo operando.

A Multiplicação

editar

Vamos agora estudar como construir um circuito capaz de realizar multiplicações. Primeiro vamos tentar realizar uma multiplicação pelo método convencional que usamos através de papel e caneta. Isso pode nos dar uma pista de como fazer uma operação de multiplicação. Vamos usar a base binária:

   1000
  x1001
   ----
   1000
  00000
 000000
1000000
-------
1001000

Perceba que a multiplicação é um conjunto de somas. Sempre estamos somando o valor 0 ou o valor do multiplicador após este passar por uma operação de SHIFT para a esquerda. O que determina se o que iremos somar é um 0 ou o valor do multiplicador após um SHIFT são os bits do multiplicando. Se o bit da posição n for um 0, somamos 0 e se for 1, somamos com o valor do multiplicando "shiftado" n vezes.

Um exemplo de um circuito seqüencial capaz de somar dois números de 4 bits é mostrado na imagem abaixo:

 

Note que multiplicando números de 4 bits, nós precisamos armazenar os 8 bits possíveis para o resultado. Afinal, o resultado de uma multiplicação é capaz de ter o número de bits igual à soma dos multiplicandos. Máquinas MIPS lidam com o problema dividindo o resultado pela metade. os bits mais significativos terminam em um registrador chamado Hi e os menos significativos acabam em um registrador chamado Lo.

Entretanto, o circuito conforme mostrado acima tem muitos problemas. O principal é que ele é muito complexo. Perceba que o circuito para multiplicar número de 4 bits é pelo menos 3 vezes mais complexo e lento que o usado para realizar a adição de 8 bits (afinal, o circuito de multiplicação precisa realizar a adição de 3 pares de valores de 8 bits). Um circuito destes para calcular a multiplicação de números com um valor ainda maior de bits seria ainda mais complexo que isso.

Com isso, chegamos à conclusão que a multiplicação é uma operação complexa demais para ser efetuada por meio de uma simples lógica combinacional de portas lógicas. Um circuito de multiplicação combinacional seria muito caro e esquentaria demais. Por isso, sua velocidade teria que ser sacrificada aumentando a distância dos transistores. Por isso, utilizam-se circuitos seqüenciais para realizar esta operação.

O diagrama abaixo mostra descreve o funcionamento de um circuito seqüencial capaz de realizar a multiplicação:

 

O que acontece no diagrama acima no caso de multiplicarmos dois números de 32 bits é o seguinte:

  • 1- O "Produto" é um registrador inicializado em 0.
  • 2- O produto e o multiplicando são passados para a ULA que soma os dois.
  • 3- O resultado (o valor do próprio multiplicando) pode ir para o registrador "Produto" ou não. Quem toma a decisão é o "Controle".
  • 4- Se o último bit do Multiplicador for "1", o Controle permite a escrita do registrador "Produto". Se for "0", ele impede.
  • 5- O Multiplicando sofre um shift para a esquerda e o Multiplicador um Shift para a direita.
  • 6- Se é a 32a vez que você chega à esta instrução, encerre. A multiplicação terminou. Caso contrário, volte ao passo 2.

O diagrama acima já é uma forma bem melhor de multiplicarmos. Mas ainda existem otimizaçãoes que podem ser feitas para acelerarmos ainda mias a multiplicação:

  • Podemos utilizar um único registrador de 64 bits para armazenar tanto o multiplicador como o produto. O multiplicador vem antes e o produto logo depois. Assim, cada vez que fazemos um shift para a direita no multiplicador, aproveitamos o espaço liberado mais à esquerda para colocar um novo bit do produto. Desta forma, não é necessário somar números de 32 bits, apenas somar o suficiente para descobrir qual o próximo bit do produto a ser colocado.
  • Compiladores substituem multiplicação por potências de 2 por operações de shift que são mais rápidas.

Para multiplicações envolvendo números negativos, basta invetermos os números transformando-os em positivos. Em seeguida, fazemos a multiplicação normalmente e observamos os sinais do multiplicador e multiplicando. Se forem iguais, masntemos os números como positivos. Caso contrário, convertemos o produto para negativo.