Operações Aritméticas e Lógicas
Vídeo da aula estará disponível em breve
Operandos Imediatos
Na aula anterior, todas as operações usavam dois registradores como fonte. Mas é muito comum operar com constantes: incrementar um contador, aplicar uma máscara de bits, comparar com um valor fixo. Para isso, MIPS oferece instruções com operando imediato — uma constante de 16 bits codificada diretamente na instrução.
# addi: soma com imediato
addi $t0, $s1, 5 # $t0 = $s1 + 5
addi $s3, $s3, 1 # $s3++ (incremento)
addi $s3, $s3, -1 # $s3-- (decremento, imediato negativo)
# andi: AND com imediato
andi $t0, $s1, 0xFF # $t0 = byte menos significativo de $s1
# Máscara: 0000...11111111
# ori: OR com imediato
ori $t0, $s1, 0x01 # Liga o bit 0 de $s1
# slti: set on less than immediate
slti $t0, $s1, 100 # $t0 = ($s1 < 100) ? 1 : 0
addi com valor negativo faz a mesma coisa. addi $t0, $s1, -5 equivale a subtrair 5. MIPS evita instruções redundantes — princípio de simplicidade.
Operandos imediatos são limitados a 16 bits (valores de -32768 a 32767 para addi/slti, ou 0 a 65535 para andi/ori). Para carregar constantes de 32 bits, usamos a combinação lui + ori:
# Carregar a constante 0x003D0900 em $s0
# 0x003D0900 = 0000 0000 0011 1101 0000 1001 0000 0000
# ───── upper 16 ───── ───── lower 16 ────
lui $s0, 0x003D # $s0 = 0x003D0000 (carrega nos 16 bits superiores)
ori $s0, $s0, 0x0900 # $s0 = 0x003D0900 (preenche os 16 bits inferiores)
# A pseudo-instrução "li" faz isso automaticamente:
li $s0, 0x003D0900 # O assembler gera lui + ori
Operações de Deslocamento (Shift)
Deslocamentos movem os bits de um registrador para a esquerda ou direita. São fundamentais para multiplicação/divisão por potências de 2 e para manipulação de campos de bits.
# sll: Shift Left Logical (desloca à esquerda, preenche com 0)
sll $t0, $s1, 4 # $t0 = $s1 << 4 (multiplica por 16)
# R-type: shamt = 4
# Exemplo visual:
# $s1 = 0000 0000 0000 0000 0000 0000 0000 1011 (= 11)
# sll $t0, $s1, 4:
# $t0 = 0000 0000 0000 0000 0000 0000 1011 0000 (= 176 = 11 × 16)
# srl: Shift Right Logical (desloca à direita, preenche com 0)
srl $t0, $s1, 2 # $t0 = $s1 >> 2 (divide por 4, sem sinal)
# sra: Shift Right Arithmetic (desloca à direita, preserva o sinal)
sra $t0, $s1, 2 # $t0 = $s1 >> 2 (divide por 4, com sinal)
# Diferença entre srl e sra:
# $s1 = 1111 1111 1111 1111 1111 1111 1111 0000 (= -16 em complemento a 2)
# srl $t0, $s1, 2:
# $t0 = 0011 1111 1111 1111 1111 1111 1111 1100 (= +1073741820, ERRADO!)
# sra $t0, $s1, 2:
# $t0 = 1111 1111 1111 1111 1111 1111 1111 1100 (= -4, CORRETO!)
Multiplicação e Divisão
Multiplicar dois números de 32 bits pode gerar um resultado de até 64 bits. MIPS lida com isso usando dois registradores especiais: HI e LO.
# mult: multiplicação com sinal
# Resultado de 64 bits vai para HI:LO
mult $s1, $s2 # HI:LO = $s1 × $s2
# Para pegar o resultado:
mflo $t0 # $t0 = LO (32 bits inferiores do resultado)
mfhi $t1 # $t1 = HI (32 bits superiores do resultado)
# Se o resultado cabe em 32 bits, basta usar mflo.
# Se HI ≠ 0 (e HI ≠ -1 para negativos), houve overflow.
# multu: multiplicação sem sinal
multu $s1, $s2 # HI:LO = $s1 × $s2 (tratados como unsigned)
# Exemplo numérico:
# $s1 = 100, $s2 = 200
# mult $s1, $s2
# LO = 20000 (100 × 200), HI = 0
# mflo $t0 → $t0 = 20000
# div: divisão inteira com sinal
div $s1, $s2 # LO = $s1 / $s2 (quociente)
# HI = $s1 % $s2 (resto)
mflo $t0 # $t0 = quociente
mfhi $t1 # $t1 = resto
# divu: divisão sem sinal
divu $s1, $s2 # LO = quociente, HI = resto (unsigned)
# Exemplo:
# $s1 = 17, $s2 = 5
# div $s1, $s2
# LO = 3 (17 / 5), HI = 2 (17 % 5)
# CUIDADO: divisão por zero é undefined behavior no MIPS!
# O hardware NÃO gera exceção automaticamente.
# O programador deve verificar antes de dividir.
Operações Lógicas Bit a Bit
Operações lógicas manipulam bits individuais. São a base de mascaramento, extração de campos e criptografia.
# Tabela verdade das operações:
# A B | AND | OR | XOR | NOR
# ──────┼─────┼─────┼─────┼─────
# 0 0 | 0 | 0 | 0 | 1
# 0 1 | 0 | 1 | 1 | 0
# 1 0 | 0 | 1 | 1 | 0
# 1 1 | 1 | 1 | 0 | 0
# AND: extrai bits (mascaramento)
and $t0, $s1, $s2 # $t0 = $s1 AND $s2
andi $t0, $s1, 0x0F # Extrai os 4 bits inferiores de $s1
# OR: liga bits
or $t0, $s1, $s2 # $t0 = $s1 OR $s2
ori $t0, $s1, 0x80 # Liga o bit 7 de $s1
# XOR: inverte bits seletivamente
xor $t0, $s1, $s2 # $t0 = $s1 XOR $s2
xori $t0, $s1, 0xFF # Inverte os 8 bits inferiores de $s1
# NOR: NOT + OR (MIPS não tem NOT; usa NOR com $zero)
nor $t0, $s1, $zero # $t0 = NOT $s1 (inverte todos os bits)
# NOR(A, 0) = NOT(A OR 0) = NOT(A)
Exemplo Completo: Extraindo Campos de uma Palavra
Um cenário real: extrair um campo de bits de uma instrução MIPS. Suponha que $s0 contém uma instrução e queremos extrair o campo rs (bits 25 a 21):
# $s0 contém a instrução: 000000 10001 10010 01000 00000 100000
# Queremos extrair rs (bits 25-21) = 10001 = 17 ($s1)
# Passo 1: deslocar à direita para alinhar o campo
srl $t0, $s0, 21 # Move bits 25-21 para posição 4-0
# Passo 2: aplicar máscara para isolar 5 bits
andi $t0, $t0, 0x1F # 0x1F = 0001 1111 (máscara de 5 bits)
# $t0 agora contém 10001 = 17 (número do registrador $s1)
# ─────────────────────────────────────────────
# Outro exemplo: construir um byte a partir de 2 nibbles
# nibble_alto = $s1 (valor 0-15), nibble_baixo = $s2 (valor 0-15)
# Resultado: byte = (nibble_alto << 4) | nibble_baixo
sll $t0, $s1, 4 # Desloca nibble alto para posição 7-4
or $t0, $t0, $s2 # Combina com nibble baixo
# Se $s1 = 0xA (1010) e $s2 = 0x3 (0011):
# $t0 = 0xA3 = 10100011
No harness.os
Operações lógicas (AND/OR) mapeiam diretamente para regras de decisão no harness.os — condições compostas que controlam workflows.
Operação MIPS Equivalente no harness.os
────────────────────────────── ────────────────────────────────────
AND (condição composta) Regra: "SE projeto É build
AND fase É testing → executar QA"
Ambas as condições devem ser verdadeiras.
OR (condição alternativa) Regra: "SE status É blocked
OR prazo expirou → notificar"
Basta uma condição ser verdadeira.
XOR (decisão exclusiva) Workflow: "OU deploy staging
OU deploy production" (nunca ambos
simultaneamente).
NOT (negação) Regra: "SE NOT (testes passaram)
→ bloquear merge"
Shift (multiplicar contexto) Escalar: carregar N chunks de
knowledge = shift left no escopo
da context window. Cada bit extra
de contexto dobra a informação
disponível, mas custa tokens.
Homework
- Escreva código MIPS para calcular
$t0 = $s0 * 7usando apenas instruções de shift e add (sem usar mult). Dica: 7 = 8 - 1. - Dado que
$s0 = 0xABCD1234, escreva código MIPS para extrair: (a) o byte mais significativo (0xAB), (b) o nibble menos significativo (0x4), (c) os 16 bits inferiores (0x1234). - Explique a diferença entre
srlesraao deslocar o valor0xFFFFFFE0por 3 posições. Qual resultado cada instrução produz?
Resumo
- Instruções com imediato (addi, andi, ori, slti) codificam constantes de 16 bits diretamente na instrução
- Para constantes de 32 bits: lui (upper 16) + ori (lower 16)
- Shift left (sll) multiplica por 2^N; shift right arithmetic (sra) divide por 2^N preservando sinal
- Multiplicação (mult) e divisão (div) usam registradores especiais HI e LO
- Operações lógicas (and, or, xor, nor) manipulam bits individuais para mascaramento e extração de campos
- MIPS não tem NOT; usa NOR com $zero como equivalente
Verifique seu entendimento
Qual instrução MIPS você usaria para dividir um número com sinal por 8 de forma eficiente?