A maior parte do conteúdo desta resposta veio originalmente dessa resposta (escrita antes dessa outra pergunta ter sido marcada como duplicada). Portanto, discuto o uso de valores de 8 bits (embora essa pergunta tenha sido feita sobre valores de 32 bits), mas tudo bem, porque os valores de 8 bits são mais simples de entender conceitualmente, e os mesmos conceitos se aplicam a valores maiores, como a aritmética de 32 bits.
Quando você adiciona dois números de 8 bits, o maior número possível (0xFF + 0xFF = 1FE). De fato, se você multiplicar dois números de 8 bits, o maior número possível (0xFF * 0xFF = 0xFE01) ainda será de 16 bits, duas vezes de 8 bits.
Agora, você pode estar assumindo que um processador x-bit pode acompanhar apenas x-bits. (Por exemplo, um processador de 8 bits pode acompanhar apenas 8 bits.) Isso não é exato. O processador de 8 bits recebe dados em pedaços de 8 bits. (Esses "pedaços" geralmente têm um termo formal: uma "palavra". Em um processador de 8 bits, são usadas palavras de 8 bits. Em um processador de 64 bits, podem ser usadas palavras de 64 bits.)
Portanto, quando você fornece 3 bytes ao computador:
Byte # 1: A instrução MUL
Byte # 2: os bytes de ordem superior (por exemplo, 0xA5)
Byte # 3: os bytes de ordem inferior (por exemplo, 0xCB)
O computador pode gerar um resultado que é mais do que 8 bits. A CPU pode gerar resultados como este:
0100 0000 0100 0010 xxxx xxxx xxxx xxxx 1101 0111
aka:
0x4082xxxxD7
Agora, deixe-me interpretar isso para você:
0x significa apenas que os seguintes dígitos são hexadecimais.
Discutirei momentaneamente o "40".
82 faz parte do registro "A", que é uma série de 8 bits.
xx e xx fazem parte de outros dois registradores, denominados registrador "B" e registrador "C". O motivo pelo qual não preenchi esses bits com zeros ou uns é que uma instrução "ADD" (enviada para a CPU) pode resultar na alteração desses bits pela instrução (enquanto a maioria dos outros bits que eu uso neste exemplo pode seja alterado, exceto por alguns dos bits da flag).
D7 caberia em mais bits, chamado de registro "D".
Um registro é apenas um pedaço de memória. Os registradores são incorporados às CPUs, para que a CPU possa acessar os registradores sem precisar interagir com a memória em um cartão de memória RAM.
Portanto, o resultado matemático de 0xA5 vezes 0xCB é 0x82D7.
Agora, por que os bits foram divididos nos registros A e D em vez dos registros A e B ou nos registros C e D? Bem, mais uma vez, este é um cenário de amostra que estou usando, cujo conceito é bastante semelhante a uma linguagem Assembly real (Intel x86 de 16 bits, conforme usado pelos Intel 8080 e 8088 e muitos CPUs mais recentes). Pode haver algumas regras comuns, como o registro "C" normalmente sendo usado como um índice para operações de contagem (típico para loops) e o registro "B" sendo usado para acompanhar as compensações que ajudam a especificar locais de memória. Portanto, "A" e "D" podem ser mais comuns para algumas das funções aritméticas comuns.
Cada instrução da CPU deve ter alguma documentação, usada por pessoas que programam no Assembly. Essa documentação deve especificar quais registros serão usados por cada instrução. (Portanto, a escolha sobre quais registradores usar é geralmente especificada pelos projetistas da CPU, não pelos programadores da linguagem Assembly. Embora possa haver alguma flexibilidade.)
Agora, voltando ao "40" no exemplo acima: isso é uma série de bits, geralmente chamada de "registro de sinalizadores". Cada bit no registro de sinalizadores tem um nome. Por exemplo, há um bit de "estouro" 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 frequentemente ser chamado pelo nome abreviado de "OF". Isso é o capital, não o zero.) O software pode verificar o valor desse sinalizador e observar o "problema". O trabalho com esse bit geralmente é tratado de forma invisível por linguagens de nível superior; portanto, os programadores iniciantes geralmente não aprendem sobre como interagir com os sinalizadores da CPU. No entanto, os programadores de montagem geralmente podem acessar alguns desses sinalizadores de maneira muito semelhante a outras variáveis.
Por exemplo, você pode ter várias instruções ADD. Uma instrução ADD pode armazenar 16 bits de resultados no registro A e no registro D, enquanto outra instrução pode apenas armazenar os 8 bits baixos no registro A, ignorar o registro D e especificar o bit de estouro. Então, mais tarde (depois de armazenar os resultados do registro A na RAM principal), você poderá usar outra instrução ADD que armazene apenas os 8 bits altos em um registro (possivelmente o registro A.) depende apenas de qual instrução de multiplicação você usa.
(Geralmente, também existe um sinalizador "underflow", caso você subtraia muito para caber no resultado desejado.)
Apenas para mostrar como as coisas ficaram complicadas:
o Intel 4004 era uma CPU de 4 bits
O Intel 8008 era uma CPU de 8 bits. Tinha registros de 8 bits denominados A, B, C e D.
O Intel 8086 era uma CPU de 16 bits. Tinha registros de 16 bits denominados AX, BX, CX e DX.
O Intel 80386 era uma CPU de 32 bits. Ele tinha registros de 32 bits chamados EAX, EBX, ECX e EDX.
As CPUs Intel x64 possuem registros 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 fazer isso, os bits que compõem o registro AX são metade dos bits que compõem o registro EAX, que são metade dos bits que compõem o registro RAX. Portanto, sempre que você altera o valor do AX, também altera o EAX e o RAX, porque esses bits usados pelo AX fazem parte dos bits usados pelo RAX. (Se você alterar o EAX por um valor múltiplo de 65.536, os 16 bits baixos não serão alterados para que o AX não seja alterado. Se você alterar o EAX por um valor que não seja múltiplo de 65.536, isso também afetaria o AX .)
Existem mais sinalizadores e registros do que os que eu mencionei. Simplesmente escolhi alguns usados para fornecer um exemplo conceitual simples.
Agora, se você estiver em uma CPU de 8 bits, ao gravar na memória, poderá encontrar algumas restrições sobre poder se referir a um endereço de 8 bits, não a um endereço de 4 bits ou 16 bits. Os detalhes variam de acordo com a CPU, mas se você tiver essas restrições, a CPU poderá lidar com palavras de 8 bits, e é por isso que a CPU é mais conhecida como "CPU de 8 bits".