A unidade lógica e aritmética (ULA), em inglês Arithmetic Logic Unit (ALU), é um circuito digital que realiza operações de adição e booleana AND. A ULA é uma peça fundamental da unidade central de processamento (UCP), e até dos mais simples microprocessadores. É na verdade, uma "grande calculadora eletrônica" do tipo desenvolvido durante a II Guerra Mundial, e sua tecnologia já estava disponível quando os primeiros computadores modernos foram construídos.
O matemático John von Neumann propôs o conceito de ULA em 1945, quando escreveu um relatório sobre os fundamentos para um novo computador chamado EDVAC. Pesquisas sobre ULAs ainda são uma parte importante da ciência da computação
A tecnologia utilizada foi inicialmente relés, herança da telefonia, e posteriormente válvulas, herança da radiofonia. Com o aparecimento dos transistores, e depois dos circuitos integrados, os circuitos da unidade aritmética e lógica passaram a ser implementados com a tecnologia de semicondutores.
A ULA executa as principais operações lógicas e aritméticas do computador. Ela soma, subtrai, divide, determina se um número é positivo ou negativo ou se é zero. Além de executar funções aritméticas, uma ULA deve ser capaz de determinar se uma quantidade é menor ou maior que outra e quando quantidades são iguais. A ULA pode executar funções lógicas com letras e com números.
Primeiro desenvolvimento
No ano de 1946, von Neumann trabalhou com seus colegas no projeto de um computador para o Instituto de Estudos Avançados de Princeton (Princeton Institute of Advanced Studies -IAS). O computador IAS se tornara o protótipo de muitos computadores. Na proposta, von Neumann descreveu o que ele acreditava que seria preciso na sua máquina, incluindo uma ULA.
Von Neumann disse que a ULA era uma necessidade para o computador porque ela garantiria que o computador calcularia operações matemáticas básicas, incluindo adição, subtração, multiplicação, e divisão..[1] Ele então achava razoável que um computador contivesse um órgão especializado para essas operações.[1]
Sistemas numéricos
Uma ULA deve processar números usando o mesmo formato que o resto do circuito digital. Os processadores modernos utilizam em maioria a representação binária de complemento para dois. Os primeiros computadores usavam uma grande variedade de sistemas numéricos, incluindo os formatos complemento para um, sinal-magnitude e mesmo o sistema decimal.[carece de fontes]
Os sistemas numéricos de complemento para um e complemento para dois permitem que a subtração seja realizada pela adição do minuendo com o complemento do subtraendo, simplificando o circuito lógico. Uma vantagem do complemento para dois em relação aos outros sistemas é que a representação possui apenas um zero, não possuindo um "zero negativo".
Visão geral prática
Muitas das ações dos computadores são executadas pela ULA. Esta recebe dados dos registradores, que são processados e os resultados da operação são armazenados nos registradores de saída. Outros mecanismos movem os dados entre esses registradores e a memória.[2] Uma unidade de controle controla a ULA, através de circuitos que dizem que operações a ULA deve realizar.
Operações simples
Muitas ULAs podem realizar as seguintes operações:
- operações aritméticas com inteiros;
- operações lógicas bit a bit AND, NOT, OR, XOR;
- operações de deslocamento de bits (deslocamento, rotação por um número específico de bits para esquerda ou direita, com ou sem sinal); deslocamentos podem ser interpretados como multiplicações ou divisões por 2.
Operações complexas
Um engenheiro pode projetar uma ULA para calcular qualquer operação, no entanto isso gera complexidade; o problema é que quanto mais complexa a operação, mais cara é a ULA, mais espaço utiliza do processador e mais dissipa energia.
Então, engenheiros sempre calculam um compromisso entre o poder de processamento e a sua complexidade, satisfazendo aos requisitos do processador ou de outro circuito. Imagine um cenário, onde é preciso calcular a raiz quadrada. O engenheiro teria as seguintes opções:
- Projetar uma ULA extremamente complexa que calcula a raiz quadrada de qualquer número num único passo. Isso é chamado cálculo em passo-único de relógio.
- Projetar uma ULA bastante complexa que calcula a raiz quadrada de qualquer número em vários passos. Mas, existe um truque, os resultados intermediários vão através de uma série de circuitos arranjados em linha, como numa linha de produção. Que faz com que a ULA seja capaz de aceitar novos números para cálculo antes mesmo de terminar o cálculo dos anteriores. Isso faz com que a ULA seja capaz de produzir números tão rápido como cálculos em passo-único de relógio, com um atraso inicial até os números começarem a sair. Isso é chamado cálculo em segmentação de instruções (pipeline).
- Projetar uma ULA complexa que calcula a raiz quadrada através de vários passos. Isso é chamado de cálculo iterativo, e usualmente confia no controle de uma complexa unidade de controle com microcódigo.
- Projetar uma ULA simples no processador e vender separadamente um processador especializado e caro que o consumidor possa instalá-lo ao lado desse, realizando uma das opções acima. Isso é chamado de coprocessador.
- Dizer aos programadores que não há nenhum coprocessador e que não há nenhuma emulação, assim eles tem que escrever seus próprios algoritmos para calcular a raiz quadrada por software. Isso é chamado de bibliotecas de software.
- Emular a existência de um coprocessador, ou seja, sempre que um programa tenta realizar o cálculo da raiz quadrada, faz o processador verificar se há coprocessador presente e o utiliza se está ali; se não há, interrompe o programa e invoca o sistema operacional para realiza o cálculo da raiz através de algum algoritmo de software. Isso é chamado de emulação de software.
As opções acima vão desde a mais rápida e cara até a mais lenta e mais complicada. Então, enquanto o mais simples computador pode calcular a mais complexa fórmula, os computadores mais simples vão usualmente levar mais tempo fazendo isso porque levam vários passos para calcular a fórmula.
Processadores poderosos como Intel Core e AMD64 utilizam a opção #1 para as operações mais simples, #2 para as operações complexas mais comuns e #3 para as operações extremamente complexas. Isso é possível através da construção de ULAs muito complexas nesses processadores.
Entradas e saídas
As entradas para a ULA são os dados a serem operados (chamados operandos) e o código da unidade de controle indicando as operações para executar. As saídas são os resultados da computação.
Em muitos projetos a ULA também leva ou gera as entradas ou saídas de um conjunto de códigos de condições ou de um registrador de estado. Esses códigos são usados para indicar casos como vai-um (empresta-um), excesso (overflow), divisão-por-zero etc.[3]
ULA vs. UPF
Uma unidade de ponto flutuante (UPF) também realiza operações aritméticas entre dois valores, mas eles realizam isso com número em representação de ponto flutuante, que é muito mais complexa que a complemento para dois. Para fazer esses cálculos, uma UPF tem vários circuitos complexos, incluindo algumas ULAs internas.
Usualmente, engenheiros chamam uma ULA o circuito que realiza operações aritméticas com números inteiros em complemento para dois ou BCD, enquanto circuitos que calculam em formatos como ponto flutuante usualmente recebem esse ilustre nome.