A maior parte do conteúdo desta resposta provinha originalmente de esta resposta (escrita antes dessa outra pergunta foi marcada como um duplicado). Então discuto a utilização de valores de 8 bits (apesar desta pergunta ser feita sobre valores de 32 bits), mas não faz mal porque os valores de 8 bits são mais simples de compreender conceptualmente, e os mesmos conceitos aplicam-se a valores maiores como a aritmética de 32 bits.
Quando se adicionam dois números que são de 8 bits, o maior número que se pode obter (0xFF + 0xFF = 1FE). De facto, se multiplicar dois números que são 8 bits, o maior número que consegue obter (0xFF * 0xFF = 0xFE01) é ainda 16 bits, duas vezes de 8 bits.
Agora, pode estar a assumir que um processador x-bit só consegue manter um registo de x bits. (Por exemplo, um processador de 8 bits só pode controlar 8 bits.) Isso não é exacto. O processador de 8 bits recebe dados em pedaços de 8 bits. (Estes “pedaços” têm normalmente um termo formal: uma “palavra”. Num processador de 8 bits, são utilizadas palavras de 8 bits. Num processador de 64 bits, podem ser utilizadas palavras de 64 bits)
Byte #1: a instrução MUL
Byte #2: os bytes de ordem elevada (por exemplo, 0xA5)
Byte #3: os bytes de ordem inferior (por exemplo, 0xCB)
O computador pode gerar um resultado que é superior a 8 bits. O CPU pode gerar resultados como este:
0100 0000 0100 0010 xxxx xxxx xxxx xxxx xxxx 1101 0111
a.k.a.:
0x4082xxxxxxD7
Agora, deixe-me interpretar que para si:
0x significa apenas que os seguintes dígitos são hexadecimais.
Discutirei o “40” em mais pormenor momentaneamente.
82 faz parte do registo “A”, que é uma série de 8 bits.
xx e xx fazem parte de dois outros registos, denominados registo “B” e registo “C”. A razão pela qual não enchi esses bits com zeros ou uns é que uma instrução “ADD” (enviada para o CPU) pode resultar em que esses bits não sejam alterados pela instrução (enquanto a maioria dos outros bits que uso neste exemplo podem ser alterados, excepto alguns dos bits de bandeira).
D7 caberiam em mais bits, chamado registo “D”.
Um registo é apenas um pedaço de memória. Os registos são incorporados nas CPUs, para que a CPU possa aceder aos registos sem precisar de interagir com a memória num stick RAM.
Então o resultado matemático de 0xA5 vezes 0xCB é 0x82D7.
Agora, porque é que os bits foram divididos nos registos A e D em vez dos registos A e B, ou nos registos C e D? Bem, mais uma vez, este é um cenário de amostra que estou a utilizar, destinado a ser bastante semelhante em conceito a uma verdadeira linguagem Assembly (Intel x86 16 bits, tal como utilizado pelos Intel 8080 e 8088 e por muitas CPUs mais recentes). Pode haver algumas regras comuns, tais como o registo “C” ser tipicamente utilizado como um índice para operações de contagem (típico para loops), e o registo “B” ser utilizado para manter o registo de offsets que ajudam a especificar a localização da memória. Assim, “A” e “D” podem ser mais comuns para algumas das funções aritméticas comuns.
Cada instrução de CPU deve ter alguma documentação, utilizada por pessoas que programam em Assembly. Essa documentação deve especificar quais os registos que são utilizados por cada instrução. (Assim, a escolha dos registos a utilizar é frequentemente especificada pelos designers da CPU, não pelos programadores da linguagem Assembly. Embora possa haver alguma flexibilidade)
Agora, voltando ao “40” no exemplo acima: isto é uma série de bits, muitas vezes chamados de “registo de bandeiras”. Cada bit no registo de bandeiras tem um nome. Por exemplo, existe um bit de “overflow” que a CPU pode definir se o resultado for maior que o espaço que pode armazenar um byte dos resultados. (O bit “overflow” pode ser frequentemente referido pelo nome abreviado de “OF”. Isso é um o maiúsculo, não um zero). O software pode verificar o valor desta bandeira e reparar no “problema”. Trabalhar com este bit é muitas vezes tratado invisivelmente por linguagens de nível superior, por isso os programadores principiantes muitas vezes não aprendem como interagir com as bandeiras da CPU. No entanto, os programadores Assembly podem normalmente aceder a algumas destas flags de uma forma muito semelhante a outras variáveis.
Por exemplo, pode ter múltiplas instruções ADD. Uma instrução ADD pode armazenar 16 bits de resultados no registo A e o registo D, enquanto outra instrução pode apenas armazenar os 8 bits baixos no registo A, ignorar o registo D, e especificar o bit de sobrecarga. Depois, mais tarde (após armazenar os resultados do registo A na RAM principal), poderá utilizar outra instrução ADD que armazena apenas os 8 bits altos num registo (possivelmente o registo A.) Se necessitará de utilizar uma bandeira de sobrecarga pode depender da instrução de multiplicação que utiliza.
(Também existe normalmente uma flag de “overflow”, caso subtraia demasiado para caber no resultado desejado)
Só para lhe mostrar como as coisas ficaram complicadas:
O Intel 4004 era um CPU de 4 bits
O Intel 8008 era um CPU de 8 bits. Tinha registos de 8 bits chamados A, B, C, e D.
O Intel 8086 era um CPU de 16 bits. Tinha registos de 16 bits denominados AX, BX, CX, e DX.
A Intel 80386 era uma CPU de 32 bits. Tinha registos de 32 bits denominados EAX, EBX, ECX e EDX.
As CPUs Intel x64 têm registos de 64 bits denominados RAX, RBX, RCX e RDX. Os chips x64 podem executar código de 16 bits (em alguns modos de operação), e podem interpretar instruções de 16 bits. Ao fazê-lo, os bits que constituem o registo AX são metade dos bits que constituem o registo EAX, que são metade dos bits que constituem o registo RAX. Assim, sempre que se altera o valor do AX, também se altera a EAX e o RAX, porque os bits utilizados pelo AX fazem parte dos bits utilizados pelo RAX. (Se você alterar EAX por um valor que é um múltiplo de 65.536, então os baixos 16 bits são inalterados para que AX não mude. Se alterar EAX por um valor que não seja um múltiplo de 65.536, então isso afectaria AX também.)
Existem mais bandeiras e registos do que apenas os que mencionei. Eu simplesmente escolhi algumas das mais usadas para dar um exemplo conceptual simples.
Agora, se estiver num CPU de 8 bits, quando escreve na memória, pode encontrar algumas restrições sobre poder referir-se a um endereço de 8 bits, e não a um endereço de 4 bits ou 16 bits. Os detalhes irão variar com base na CPU, mas se tiver tais restrições, então a CPU pode estar a lidar com palavras de 8 bits, razão pela qual a CPU é mais comummente referida como uma “CPU de 8 bits”.