12 KiB
Aula 1 – Arquitetura de computadores
- Objetivos
- Modelo de von Neumann
- Arquiteturas x86
- Componentes de uma CPU x86_64
- Principais registradores e seus propósitos (64 bits)
- Primeiro exemplo em Assembly x86_64
- Exercícios sugeridos
- Referências
Objetivos
- Compreender os principais componentes de um computador sob o modelo de von Neumann.
- Reconhecer os registradores da arquitetura x86_64.
- Entender a relação entre hardware e código Assembly.
- Executar o primeiro programa Assembly com uma chamada de sistema.
Modelo de von Neumann
Um computador possui:
- Unidade de processamento (ALU + Controladora)
- Memória (armazenamento de instruções e dados)
- Dispositivos de entrada/saída
O modelo de Von Neumann é uma arquitetura de computadores em que a unidade central de processamento (CPU) e a memória compartilham um único espaço de armazenamento, tanto para dados quanto para instruções de programa. Isso significa que o processador acessa a memória de forma sequencial para buscar dados e instruções, utilizando um único barramento para ambas as operações.
No modelo de Von Neumann:
- Instruções e dados compartilham o mesmo espaço de memória.
- A CPU executa o ciclo: busca → decodifica → executa.
Como era antes:
- Instruções e dados armazenados em memórias separadas.
- A CPU executa o ciclo: busca → decodifica → executa, mas pode realizar a busca de dados e instruções em paralelo.
Influência nas arquiteturas modernas
O modelo de Von Neumann influenciou profundamente as arquiteturas modernas de computadores, estabelecendo a base para a maioria dos designs de sistemas computacionais atuais. Algumas das principais influências incluem:
- Memória unificada
- A ideia de compartilhar a mesma memória para dados e instruções se manteve como o padrão em muitas arquiteturas modernas, simplificando o design dos sistemas, embora existam variações: como a memória cache, que separa dados e instruções em níveis mais próximos ao processador.
- Ciclo de busca, decodificação e execução
- O modelo de Von Neumann introduziu o ciclo básico de execução de instruções, que ainda é fundamental em CPUs modernas. As arquiteturas atuais, como x86 e ARM, seguem esse ciclo de maneira semelhante, embora com otimizações como a pipelining, onde múltiplas fases do ciclo podem ser realizadas em paralelo.
- Programação e flexibilidade
- O modelo permite que os programas sejam tratados como dados, o que possibilita a criação de sistemas que podem ser facilmente modificados e adaptados. Isso contribui para o desenvolvimento de linguagens de programação de alto nível, sistemas operacionais e aplicativos dinâmicos.
- Simplicidade e custo
- O modelo de Von Neumann simplificou o design de computadores ao integrar a memória de instruções e dados. Isso contribuiu para a redução de custos de hardware, tornando os sistemas mais acessíveis e facilitando o desenvolvimento de sistemas comerciais e pessoais.
Nota: A pipelining (do conceito de "linha de montagem") é uma técnica de execução paralela em que múltiplas instruções são processadas simultaneamente em diferentes estágios do ciclo de execução para aumentar o desempenho da CPU. Isso difere do conceito geral de paralelismo, onde tarefas completas, e não estágios do processamento, são executadas simultaneamente.
Gargalo de Von Neumann
O gargalo de Von Neumann é uma limitação de desempenho causada pelo fato de que a CPU e a memória compartilham o mesmo barramento para acessar instruções e dados.
Isso significa que:
- A CPU não pode buscar uma instrução e acessar dados ao mesmo tempo.
- O tempo de espera entre operações aumenta, especialmente em programas que exigem muitos acessos à memória.
- A largura de banda do barramento se torna um fator crítico para o desempenho.
Esse gargalo levou ao desenvolvimento de soluções como:
- Memória cache (para reduzir acessos à RAM)
- Execução paralela e pipelines
- Arquiteturas modificadas (como o modelo Harvard modificado)
Nota: A arquitetura Harvard modificada é uma variação do modelo de Von Neumann que usa memórias separadas internamente (como em caches) para dados e instruções, mantendo um espaço de memória unificado do ponto de vista do programador.
Arquiteturas x86
A arquitetura x86 é uma família de conjuntos de instruções (ISA – Instruction Set Architecture) baseada no modelo de Von Neumann e desenvolvida originalmente pela Intel a partir do processador 8086.
Assim como no modelo de Von Neumann:
- Dados e instruções compartilham o mesmo espaço de memória.
- A CPU segue o ciclo: busca → decodifica → executa.
Nota: A transição da arquitetura x86 de 32 para 64 bits foi liderada pela AMD com a criação da AMD64 em 2003. Essa extensão manteve compatibilidade com o conjunto de instruções x86 original (IA-32), mas adicionou registradores de 64 bits e suporte a endereçamento ampliado. Posteriormente, a Intel adotou essa mesma arquitetura sob o nome Intel 64 (anteriormente chamada EM64T), e o termo x86-64 passou a ser usado de forma genérica para se referir à arquitetura compatível com AMD64. Assim, AMD64 é a origem técnica da arquitetura x86 de 64 bits utilizada na maioria dos sistemas modernos.
Características
- ISA complexa (CISC – Complex Instruction Set Computing), com centenas de instruções e modos de endereçamento.
- Suporte a múltiplos tamanhos de palavra (16, 32 e 64 bits nas versões modernas).
- Registradores de uso geral (AX, BX, CX, etc.) e segmentados (CS, DS, SS…, não utilizados no Linux), herdados de versões mais antigas.
- Ampla compatibilidade com versões anteriores (retrocompatibilidade).
- Utilizada em desktops, laptops e servidores, sendo a base da maioria dos PCs atuais.
Nota: Embora a arquitetura x86 inclua registradores segmentados (como CS, DS, ES, SS), o Linux não faz uso da segmentação de memória no modo protegido. Em vez disso, ele utiliza o chamado endereçamento plano, tratando toda a memória como um único espaço contínuo. A segmentação é mantida apenas em um nível mínimo para atender exigências da arquitetura (como troca de contexto e proteção básica), mas a segmentação lógica, como era usada no MS-DOS, é totalmente evitada.
Otimizações em relação ao modelo de Von Neumann
A arquitetura x86 é uma evolução prática do modelo de Von Neumann, com otimizações como:
- Uso extensivo de memória cache.
- Execução fora de ordem (out-of-order execution).
- Pipelines e paralelismo interno.
Comparativo com outras arquiteturas
Todas as arquiteturas modernas seguem, em maior ou menor grau, os princípios do modelo de Von Neumann. No entanto, diferem na forma como organizam e executam instruções. Veja o comparativo:
x86 (CISC – Complex Instruction Set Computing):
- Conjunto de instruções extenso e complexo.
- Instruções de vários tamanhos e com múltiplos modos de endereçamento.
- Maior consumo de energia, mas com alta compatibilidade e maior desempenho bruto.
- Retrocompatibilidade com código legado.
- Comum em PCs, laptops e servidores.
ARM (RISC – Reduced Instruction Set Computing)
- Conjunto de instruções reduzido e regular.
- Foco em simplicidade, baixa energia e eficiência.
- Desempenho por watt muito superior ao x86.
- Predominante em dispositivos móveis (smartphones, tablets) e embarcados.
- ARM64 (AArch64) é a versão de 64 bits moderna.
RISC-V (RISC e open source):
- ISA aberta, modular e extensível.
- Sem royalties: qualquer um pode implementar.
- Design limpo e simples, adequado para pesquisa, educação e sistemas customizados.
- Crescimento em sistemas embarcados e processadores personalizados.
Resumo comparativo:
Arquitetura | Tipo | Complexidade | Consumo | Uso comum |
---|---|---|---|---|
x86 | CISC | Alta | Alto | PCs, laptops, servidores |
ARM | RISC | Média | Baixo | Celulares, IoT, Apple M1+ |
RISC-V | RISC | Baixa | Baixo | Pesquisa, sistemas embarcados |
Componentes de uma CPU x86_64
- Unidade de Controle (Control Unit - CU)
- Gerencia o fluxo de dados e as instruções dentro da CPU, coordenando as operações de execução.
- Unidade Lógica e Aritmética (ALU – Arithmetic and Logic Unit)
- Responsável pela execução de operações aritméticas (soma, subtração, etc.) e lógicas (AND, OR, NOT, etc.).
- Registradores de uso geral
- Utilizados para armazenar dados temporários durante a execução de instruções (ex.: RAX, RBX, RCX, etc.).
- Registradores de propósito específico
- Como o ponteiro de pilha (RSP), ponteiro de instrução (RIP) e flags (como EFLAGS).
- Registradores de segmentos
- Armazenam endereços de segmentos de memória para código (CS), dados (DS) e pilha (SS), além dos registradores de segmentos adicionais para dados (ES, FS e GS).
- Cache
- Memória de acesso ultrarrápido usada para armazenar dados frequentemente acessados, visando reduzir o tempo de acesso à memória principal. Normalmente dividida em L1, L2 e, em algumas CPUs, L3.
- Barramentos
- Conjunto de trilhas de comunicação que transportam dados entre a CPU e outros componentes, como a memória, dispositivos de entrada/saída e outros núcleos.
- Unidade de Execução (Execution Unit – EU)
- Responsável por executar as instruções. Em CPUs modernas, pode haver múltiplas unidades de execução para executar diferentes tipos de operações em paralelo.
- Decodificador de Instruções
- Interpreta as instruções da linguagem de máquina (bytecode) e as converte para operações que podem ser executadas pela ALU ou outras unidades de execução.
- Unidade de carga e armazenamento (Load-Store Unit - LSU)
- Controla o carregamento e armazenamento de dados na memória, realizando operações de leitura e escrita.
- Unidade de Endereçamento (Address Generation Unit - AGU)
- Calcula endereços de memória, especialmente no contexto de operações de acesso à memória e cálculo de ponteiros.
- Controlador de Interrupções (Interrupt Controller)
- Responsável por lidar com interrupções externas e internas, gerenciando a prioridade e o tratamento adequado das interrupções no sistema.
Principais registradores e seus propósitos (64 bits)
RAX
: acumulador/propósito geralRBX
: base/propósito geralRCX
: contador/propósito geralRDX
: dados/propósito geralRSI
: índice de origemRDI
: índice de destinoRSP
: ponteiro da pilhaRBP
: base da pilhaRIP
: ponteiro de instruçãoRFLAGS
: sinalizações diversas
A arquitetura x86_64 ainda inclui oito registradores de propósito geral, de R8
a R15
.
Primeiro exemplo em Assembly x86_64
Arquivo exit42.asm
; Retorna 42 como estado de término
section .text
global _start
_start:
mov rax, 60 ; syscall: exit
mov rdi, 42 ; código de saída
syscall
Compilação e execução (no terminal)
:~$ nasm -f elf64 -o exit42.o exit42.asm :~$ ld -o exit42 exit42.o :~$ ./exit42 :~$ echo $? 42
Exercícios sugeridos
- Modifique o programa Assembly para retornar "sucesso".
- Desmonte (
objdump -d
) os binários gerados e compare os códigos de máquina. - Use
strace ./exit42
para verificar a chamada de sistema realizada.