Capítulo 2: Instruções: A linguagem do Computador
2.1 Introdução
Apresenta o conceito de linguagem máquina, onde cada instrução é uma "palavra" e o conjunto de todas constitui o conjunto de instruções (ISA). É introduzido o RISC-V como ISA base do livro, comparando-o com o MIPS e o x86, mostrando a importância de um design simples, eficaz e de fácil implementação para hardware e compiladores.
2.2 Operações do Hardware do Computador
Explica os tipos de instruções básicas: aritméticas, lógicas, de transferência de dados e de controlo de fluxo: add
, sub
, lw
, sw
, e beq
.
2.3 Operandos do Hardware do Computador
Discute os registos (e.g., x0 a x31 no RISC-V), usados para armazenar operandos, e a razão para a sua limitação (tipicamente 32 registos): menor complexidade e maior velocidade.
2.4 Números com e sem sinal
Aborda a representação de números inteiros com sinal (signed) usando complemento para dois, e sem sinal (unsigned). Explica as diferenças nas instruções e como o hardware as interpreta.
2.5 Representar Instruções no Computador
Mostra como as instruções RISC-V são codificadas em binário, detalhando os campos opcode
, rd
, rs1
, rs2
, funct3
e funct7
. Apresenta os formatos R, I, S, B, U e J.
2.6 Operações Lógicas
Explora as instruções lógicas como and
, or
, xor
, sll
, srl
, sra
, etc. Mostra como são úteis em manipulação de bits, máscaras e operações de baixo nível.
2.7 Instruções para Tomada de Decisão
Introduz as instruções condicionais como beq
, bne
, blt
, bge
, etc. Usa exemplos de condições e ciclos (if, while) para mostrar a sua tradução para assembly.
2.8 Suporte a Procedimentos no Hardware
Explica a chamada e retorno de procedimentos (jal
, jalr
, ret
), a passagem de parâmetros (x10
, x11
, ...), o uso da stack (sp
) e a preservação de registos (ra
, s0-s11
), incluindo o prólogo e epílogo das funções.
2.9 Comunicação com Pessoas
Descreve input/output em baixo nível, abordando syscalls, o uso de ecall
no RISC-V, e o papel do sistema operativo para fornecer serviços como impressão no ecrã ou leitura do teclado.
2.10 Endereçamento RISC-V para Imediatos e Endereços Longos
Discute os desafios de representar constantes grandes (imediatos) e endereços longos, e como o RISC-V usa instruções como lui
, auipc
, combinadas com outras (addi
, jalr
) para construir valores de 32 bits.
2.11 Paralelismo e Instruções: Sincronização
Apresenta o conceito de sincronização em multiprocessadores com instruções como lr.w
(load reserved) e sc.w
(store conditional), fundamentais para evitar condições de corrida (race conditions) e implementar locks.
2.12 Traduzir e Iniciar um Programa
Explica as etapas de tradução de um programa C: compilador → assembly → objeto → ligação (linking) → carregamento (loading). Introduz as ferramentas envolvidas (e.g., assembler, linker, loader) e os tipos de ficheiros (.c, .s, .o, .exe).
2.13 Exemplo de Ordenação em C: Tudo Junto
Fornece um exemplo completo de ordenar um array em C, a sua tradução para assembly RISC-V, e a análise do desempenho. Mostra como os ciclos for
e chamadas a funções são representadas em assembly.
2.14 Arrays vs Ponteiros
Compara o uso de arrays com o uso de ponteiros em C, tanto a nível de sintaxe como de geração de código assembly. Mostra que os ponteiros podem gerar código mais compacto e rápido, dependendo da optimização.
2.15 Compilação de C e Interpretação de Java
Apresenta técnicas de compilação e optimização em C, como propagação de constantes e alocação de registos, e compara com a execução de bytecode Java numa Java Virtual Machine (JVM), incluindo métodos, objectos, garbage collection, etc.
2.16 ARMv8: Material Real
Compara o RISC-V com o conjunto de instruções ARMv8 (64 bits), destacando diferenças e semelhanças, tais como o número de registos, formatos de instruções e modos de endereçamento.
2.17 x86-64: Material Real
Explora a complexidade da ISA x86-64, mostrando como lida com instruções variáveis em tamanho (1 a 15 bytes), modos de endereçamento avançados, e a sua longa história de compatibilidade com versões anteriores.
2.18 Falácias e Armadilhas
Lista ideias erradas comuns em design de instruções e hardware, como “mais instruções = melhor desempenho” ou “hardware complexo é sempre mais rápido”, explicando por que estas ideias são enganadoras.
2.19 Considerações Finais
Resume os principais conceitos do capítulo, reforçando a ligação entre linguagens de alto nível, linguagem de máquina e execução no hardware. Destaca a importância de compreender a base para construir sistemas eficientes.
2.20 Perspectiva Histórica e Referências
Apresenta a evolução dos conjuntos de instruções desde os primeiros computadores até aos dias de hoje, mencionando marcos como o IBM 701, o PDP-11, o MIPS, e os princípios que guiaram o design moderno de ISAs.
2.21 Tudo Junto: Multiplicação de Matrizes em C
Aplica os conhecimentos do capítulo numa tarefa prática: multiplicação de matrizes, analisando o impacto do código, do compilador e da ISA no desempenho.
2.22 Falácias e Armadilhas
Reforça e detalha falhas de raciocínio comuns, com exemplos concretos de como certas decisões de design podem parecer vantajosas mas serem prejudiciais.
2.23 Observações Finais
Conclui o capítulo com um reforço da ideia central: compreender a linguagem do computador é essencial para todos os programadores, pois permite otimizar desempenho, detectar problemas e compreender o funcionamento interno dos sistemas.