28
Mais lidos
29
Mais lidos
35
Mais lidos
Organização estruturada
de computadores
Tanenbaum • Austin
6a
EDIÇÃO
Organização estruturada
de computadores
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Organização estruturada
de computadores
Tanenbaum • Austin
6a
EDIÇÃO
Tradução
DANIEL VIEIRA
Revisão técnica
PROF. DR. WAGNER LUIZ ZUCCHI
rofessor do Departamento de Sistemas Eletrônicos da Escola olitécnica
da Universidade de São aulo, do programa de ós-Graduação do Instituto de
esquisas Tecnológicas (IT) e da Universidade Nove de Julho. Colaborador
da revista RTI  Redes, Telecomunicações e Infraestrutura  e consultor de
diversas empresas na área de redes e telecomunicação digital
2013
Direitos exclusivos para a língua portuguesa cedidos à
Pearson Education do Brasil Ltda.,
uma empresa do grupo Pearson Education
Rua Nelson Francisco, 26
CEP 02712-100  São Paulo  SP  Brasil
Fone: 11 2178-8686  Fax: 11 2178-8688
vendas@pearson.com
Dados Internacionais de Catalogação na Publicação (CIP)
(Câmara Brasileira do Livro, SP, Brasil)
Tanenbaum, Andrew S.
Organização estruturada de computadores / Andrew S. Tanenbaum,
Todd Austin; tradução Daniel Vieira; revisão técnica Wagner Luiz
Zucchi. -- São Paulo : Pearson Prentice Hall, 2013.
Título original: Structured computer organization.
6 ed. norte-americana.
Bibliografia.
ISBN 978-85-4301-379-4
1. Organização de computador 2. Programação (Computadores)
I. Austin, Todd. II. Título.
13-04217 CDD-005.1
Índice para catálogo sistemático:
1. Organização estruturada de computadores:
Ciências da computação 005.1
©2013 by Andrew S. Tanenbaum e Todd Austin
Todos os direitos reservados. Nenhuma parte desta publicação poderá ser reproduzida ou
transmitida de qualquer modo ou por qualquer outro meio, eletrônico ou mecânico, incluindo
fotocópia, gravação ou qualquer outro tipo de sistema de armazenamento e transmissão de
informação, sem prévia autorização, por escrito, da Pearson Education do Brasil.
D    ú Roger Trimer
G  Kelly Tavares
S    Silvana Afonso
C   Danielle Sales
C    Sérgio Nascimento
C    Tatiane Romano
E  õ Vinícius Souza
E   Daniela Braz
E  Luiz Salla
P Christiane Colas
T Daniel Vieira
R  Wagner Luiz Zucchi
R Guilherme Summa
C Solange Rennó
(adaptação do projeto original)
P    Casa de Ideias
Suma
rio
PREFÁCIO 
EICRI 
1 INROUÇÃO 1
1.1 ORGANIZAÇÃO ESTRUTURADA DE COMPUTADOR 2
1.1.1 Linguagens, níveis e máquinas virtuais 2
1.1.2 Máquinas multiníveis contemporâneas 4
1.1.3 Evolução de máquinas multiníveis 6
1.2 MARCOS DA ARQUITETURA DE COMPUTADORES 10
1.2.1 A geração zero — computadores mecânicos (1642–1945) 10
1.2.2 A primeira geração — válvulas (1945–1955) 13
1.2.3 A segunda geração — transistores (1955–1965) 15
1.2.4 A terceira geração — circuitos integrados (1965–1980) 17
1.2.5 A quarta geração — integração em escala muito grande (1980–?) 18
1.2.6 A quinta geração — computadores de baixa potência e invisíveis 20
1.3 O ZOOLÓGICO DOS COMPUTADORES 22
1.3.1 Forças tecnológicas e econômicas 22
1.3.2 Tipos de computadores 23
1.3.3 Computadores descartáveis 24
1.3.4 Microcontroladores 26
1.3.5 Computadores móveis e de jogos 27
1.3.6 Computadores pessoais 28
1.3.7 Servidores 29
1.3.8 Mainframes 30
1.4 EXEMPLOS DE FAMÍLIAS DE COMPUTADORES 30
1.4.1 Introdução à arquitetura x86 31
1.4.2 Introdução à arquitetura ARM 35
1.4.3 Introdução à arquitetura AVR 37
1.5 UNIDADES MÉTRICAS 38
1.6 ESQUEMA DESTE LIVRO 39
2 ORGNIZÇÃO E SISEMS E COMPUORES 42
2.1 PROCESSADORES 42
2.1.1 Organização da CPU 43
2.1.2 Execução de instrução 44
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
VI
2.1.3 RISC versus CISC 47
2.1.4 Princípios de projeto para computadores modernos 49
2.1.5 Paralelismo no nível de instrução 50
2.1.6 Paralelismo no nível do processador 53
2.2 MEMÓRIA PRIMÁRIA 57
2.2.1 Bits 57
2.2.2 Endereços de memória 58
2.2.3 Ordenação de bytes 59
2.2.4 Códigos de correção de erro 60
2.2.5 Memória cache 64
2.2.6 Empacotamento e tipos de memória 66
2.3 MEMÓRIA SECUNDÁRIA 67
2.3.1 Hierarquias de memória 67
2.3.2 Discos magnéticos 68
2.3.3 Discos IDE 71
2.3.4 Discos SCSI 72
2.3.5 RAID 73
2.3.6 Discos em estado sólido 76
2.3.7 CD-ROMs 78
2.3.8 CDs graváveis 81
2.3.9 CDs regraváveis 83
2.3.10 DVD 83
2.3.11 Blu-ray 85
2.4 ENTRADA/SAÍDA 85
2.4.1 Barramentos 85
2.4.2 Terminais 88
2.4.3 Mouses 93
2.4.4 Controladores de jogos 94
2.4.5 Impressoras 96
2.4.6 Equipamento de telecomunicações 100
2.4.7 Câmeras digitais 106
2.4.8 Códigos de caracteres 108
2.5 RESUMO 111
3 O NÍVEL LGICO IGIL 115
3.1 PORTAS E ÁLGEBRA BOOLEANA 115
3.1.1 Portas 116
3.1.2 Álgebra booleana 117
3.1.3 Execução de funções booleanas 119
3.1.4 Equivalência de circuito 120
3.2 CIRCUITOS LÓGICOS DIGITAIS BÁSICOS 123
3.2.1 Circuitos integrados 124
S u m a
 r i o VII
3.2.2 Circuitos combinatórios 125
3.2.3 Circuitos aritméticos 127
3.2.4 Clocks 132
3.3 MEMÓRIA 133
3.3.1 Memórias de 1 bit 133
3.3.2 Flip-Flops 135
3.3.3 Registradores 137
3.3.4 Organização da memória 138
3.3.5 Chips de memória 140
3.3.6 RAMs e ROMs 142
3.4 CHIPS DE CPU E BARRAMENTOS 146
3.4.1 Chips de CPU 146
3.4.2 Barramentos de computador 147
3.4.3 Largura do barramento 149
3.4.4 Clock do barramento 151
3.4.5 Arbitragem de barramento 154
3.4.6 Operações de barramento 156
3.5 EXEMPLO DE CHIPS DE CPUs 158
3.5.1 O Intel Core i7 158
3.5.2 O sistema-em-um-chip Texas Instruments OMAP4430 164
3.5.3 O microcontrolador Atmel ATmega168 167
3.6 EXEMPLOS DE BARRAMENTOS 169
3.6.1 O barramento PCI 169
3.6.2 PCI Express 176
3.6.3 Barramento serial universal (USB) 180
3.7 INTERFACE 183
3.7.1 Interfaces de E/S 183
3.7.2 Decodificação de endereço 184
3.8 RESUMO 186
4 O NÍVEL E MICRORQUIEUR 190
4.1 UM EXEMPLO DE MICROARQUITETURA 190
4.1.1 O caminho de dados 191
4.1.2 Microinstruções 196
4.1.3 Controle de microinstrução: a Mic-1 198
4.2 EXEMPLO DE ISA: IJVM 201
4.2.1 Pilhas 201
4.2.2 O modelo de memória IJVM 203
4.2.3 Conjunto de instruções da IJVM 204
4.2.4 Compilando Java para a IJVM 208
4.3 EXEMPLO DE IMPLEMENTAÇÃO 209
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
VIII
4.3.1 Microinstruções e notação 209
4.3.2 Implementação de IJVM que usa a Mic-1 212
4.4 PROJETO DO NÍVEL DE MICROARQUITETURA 222
4.4.1 Velocidade versus custo 223
4.4.2 Redução do comprimento do caminho de execução 224
4.4.3 Projeto com busca antecipada: a Mic-2 229
4.4.4 Projeto com pipeline: a Mic-3 233
4.4.5 ipeline de sete estágios: a Mic-4 238
4.5 MELHORIA DE DESEMPENHO 241
4.5.1 Memória cache 241
4.5.2 Previsão de desvio 246
4.5.3 Execução fora de ordem e renomeação de registrador 250
4.5.4 Execução especulativa 254
4.6 EXEMPLOS DO NÍVEL DE MICROARQUITETURA 256
4.6.1 A microarquitetura da CPU Core i7 256
4.6.2 A microarquitetura da CPU OMAP4430 260
4.6.3 A microarquitetura do microcontrolador ATmega168 264
4.7 COMPARAÇÃO ENTRE i7, OMAP4430 E ATmega168 266
4.8 RESUMO 266
5 O NÍVEL E RQUIEUR O CONJUNO E INSRUÇÃO 270
5.1 VISÃO GERAL DO NÍVEL ISA 272
5.1.1 Propriedades do nível ISA 272
5.1.2 Modelos de memória 273
5.1.3 Registradores 275
5.1.4 Instruções 276
5.1.5 Visão geral do nível ISA do Core i7 276
5.1.6 Visão geral do nível ISA ARM do OMAP4430 278
5.1.7 Visão geral do nível ISA AVR do ATmega168 280
5.2 TIPOS DE DADOS 281
5.2.1 Tipos de dados numéricos 282
5.2.2 Tipos de dados não numéricos 282
5.2.3 Tipos de dados no Core i7 283
5.2.4 Tipos de dados na CPU ARM do OMAP4430 283
5.2.5 Tipos de dados na CPU AVR do ATmega168 284
5.3 FORMATOS DE INSTRUÇÃO 284
5.3.1 Critérios de projeto para formatos de instrução 285
5.3.2 Expansão de opcodes 287
5.3.3 Formatos de instruções do Core i7 289
5.3.4 Formatos de instruções da CPU ARM do OMAP4430 290
5.3.5 Formatos de instruções da CPU AVR do ATmega168 291
S u m a
 r i o IX
5.4 ENDEREÇAMENTO 292
5.4.1 Modos de endereçamento 292
5.4.2 Endereçamento imediato 292
5.4.3 Endereçamento direto 293
5.4.4 Endereçamento de registrador 293
5.4.5 Endereçamento indireto de registrador 293
5.4.6 Endereçamento indexado 294
5.4.7 Endereçamento de base indexado 296
5.4.8 Endereçamento de pilha 296
5.4.9 Modos de endereçamento para instruções de desvio 299
5.4.10 Ortogonalidade de opcodes e modos de endereçamento 300
5.4.11 Modos de endereçamento do Core i7 301
5.4.12 Modos de endereçamento da CPU ARM do OMAP4430 303
5.4.13 Modos de endereçamento da AVR do ATmega168 303
5.4.14 Discussão de modos de endereçamento 303
5.5 TIPOS DE INSTRUÇÃO 304
5.5.1 Instruções para movimento de dados 304
5.5.2 Operações diádicas 305
5.5.3 Operações monádicas 306
5.5.4 Comparações e desvios condicionais 307
5.5.5 Instruções de chamada de procedimento 309
5.5.6 Controle de laço 309
5.5.7 Entrada/Saída 310
5.5.8 Instruções do Core i7 313
5.5.9 Instruções da CPU ARM do OMAP4430 315
5.5.10 Instruções da CPU AVR do ATmega168 317
5.5.11 Comparação de conjuntos de instruções 319
5.6 FLUXO DE CONTROLE 319
5.6.1 Fluxo de controle sequencial e desvios 320
5.6.2 Procedimentos 320
5.6.3 Corrotinas 324
5.6.4 Exceções 326
5.6.5 Interrupções 327
5.7 UM EXEMPLO DETALHADO: AS TORRES DE HANÓI 330
5.7.1 As Torres de Hanói em linguagem de montagem do Core i7 330
5.7.2 As Torres de Hanói em linguagem de montagem da CPU ARM do OMAP4430 332
5.8 A ARQUITETURA IA-64 E O ITANIUM 2 333
5.8.1 O problema da ISA IA-32 333
5.8.2 O modelo IA-64: computação por instrução explicitamente paralela 334
5.8.3 Redução de referências à memória 335
5.8.4 Escalonamento de instruções 336
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
X
5.8.5 Redução de desvios condicionais: predicação 337
5.8.6 Cargas especulativas 339
5.9 RESUMO 340
6 O SISEM OPERCIONL 344
6.1 MEMÓRIA VIRTUAL 345
6.1.1 Paginação 346
6.1.2 Implementação de paginação 347
6.1.3 Paginação por demanda e o modelo de conjunto de trabalho 351
6.1.4 Política de substituição de página 351
6.1.5 Tamanho de página e fragmentação 353
6.1.6 Segmentação 354
6.1.7 Implementação de segmentação 357
6.1.8 Memória virtual no Core i7 359
6.1.9 Memória virtual na CPU ARM do OMAP4430 363
6.1.10 Memória virtual e caching 365
6.2 VIRTUALIZAÇÃO DO HARDWARE 365
6.2.1 Virtualização do hardware no Core i7 366
6.3 INSTRUÇÕES DE E/S DE NÍVEL OSM 367
6.3.1 Arquivos 367
6.3.2 Implementação de instruções de E/S de nível OSM 369
6.3.3 Instruções de gerenciamento de diretório 371
6.4 INSTRUÇÕES DE NÍVEL OSM PARA PROCESSAMENTO PARALELO 372
6.4.1 Criação de processo 373
6.4.2 Condições de disputa 374
6.4.3 Sincronização de processos usando semáforos 377
6.5 EXEMPLOS DE SISTEMAS OPERACIONAIS 380
6.5.1 Introdução 380
6.5.2 Exemplos de memória virtual 385
6.5.3 Exemplos de E/S virtual em nível de sistema operacional 388
6.5.4 Exemplos de gerenciamento de processos 397
6.6 RESUMO 402
7 O NÍVEL E LINGUGEM E MONGEM 407
7.1 INTRODUÇÃO À LINGUAGEM DE MONTAGEM 408
7.1.1 O que é uma linguagem de montagem? 408
7.1.2 Por que usar linguagem de montagem? 409
7.1.3 Formato de uma declaração em linguagem de montagem 409
7.1.4 Pseudoinstruções 411
7.2 MACROS 413
7.2.1 Definição, chamada e expansão de macro 413
S u m a
 r i o XI
7.2.2 Macros com parâmetros 415
7.2.3 Características avançadas 415
7.2.4 Implementação de um processador de macros em um assembler 416
7.3 O PROCESSO DE MONTAGEM 417
7.3.1 Assemblers de duas etapas 417
7.3.2 Passagem um 417
7.3.3 Passagem dois 421
7.3.4 Tabela de símbolos 422
7.4 LIGAÇÃO E CARREGAMENTO 423
7.4.1 Tarefas realizadas pelo ligador 424
7.4.2 Estrutura de um módulo-objeto 427
7.4.3 Tempo de vinculação e relocação dinâmica 428
7.4.4 Ligação dinâmica 430
7.5 RESUMO 433
8 RQUIEURS E COMPUORES PRLELOS 436
8.1 PARALELISMO NO CHIP 438
8.1.1 Paralelismo no nível da instrução 438
8.1.2 Multithreading no chip 443
8.1.3 Multiprocessadores com um único chip 448
8.2 COPROCESSADORES 453
8.2.1 Processadores de rede 453
8.2.2 Processadores de gráficos 459
8.2.3 Criptoprocessadores 461
8.3 MULTIPROCESSADORES DE MEMÓRIA COMPARTILHADA 462
8.3.1 Multiprocessadores versus multicomputadores 462
8.3.2 Semântica da memória 468
8.3.3 Arquiteturas de multiprocessadores simétricos UMA 471
8.3.4 Multiprocessadores NUMA 478
8.3.5 Multiprocessadores COMA 485
8.4 MULTICOMPUTADORES DE TROCA DE MENSAGENS 486
8.4.1 Redes de interconexão 487
8.4.2 MPPs — processadores maciçamente paralelos 490
8.4.3 Computação de cluster 497
8.4.4 Software de comunicação para multicomputadores 502
8.4.5 Escalonamento 503
8.4.6 Memória compartilhada no nível de aplicação 504
8.4.7 Desempenho 510
8.5 COMPUTAÇÃO EM GRADE 514
8.6 RESUMO 516
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
XII
9 BIBLIOGRFI 519
 NÚMEROS BINÁRIOS 525
A.1 NÚMEROS DE PRECISÃO FINITA 525
A.2 SISTEMAS DE NÚMEROS RAIZ, OU NÚMEROS DE BASE 527
A.3 CONVERSÃO DE UMA BASE PARA OUTRA 529
A.4 NÚMEROS BINÁRIOS NEGATIVOS 531
A.5 ARITMÉTICA BINÁRIA 532
B NÚMEROS E PONO FLUUNE 534
B.1 PRINCÍPIOS DE PONTO FLUTUANTE 534
B.2 PADRÃO DE PONTO FLUTUANTE IEEE 754 537
C PROGRMÇÃO EM LINGUGEM E MONGEM 542
C.1 VISÃO GERAL 543
C.1.1 Linguagem de montagem 543
C.1.2 Um pequeno programa em linguagem de montagem 543
C.2 O PROCESSADOR 8088 544
C.2.1 O ciclo do processador 545
C.2.2 Os registradores gerais 546
C.2.3 Registradores de ponteiros 547
C.3 MEMÓRIA E ENDEREÇAMENTO 548
C.3.1 Organização da memória e segmentos 548
C.3.2 Endereçamento 549
C.4 O CONJUNTO DE INSTRUÇÕES DO 8088 552
C.4.1 Mover, copiar, efetuar aritmética 552
C.4.2 Operações lógicas, de bit e de deslocamento 555
C.4.3 Operações de laço e cadeias repetitivas 555
C.4.4 Instruções Jump e Call 556
C.4.5 Chamadas de sub-rotina 557
C.4.6 Chamadas de sistema e sub-rotinas de sistema 558
C.4.7 Observações finais sobre o conjunto de instruções 560
C.5 O ASSEMBLER 561
C.5.1 Introdução 561
C.5.2 O assembler as88, baseado em ACK 561
C.5.3 Algumas diferenças com outros assemblers 8088 564
C.6 O RASTREADOR 565
C.6.1 Comandos do rastreador 566
C.7 COMO ACESSAR 568
C.8 EXEMPLOS 568
C.8.1 Exemplo de Hello World 568
S u m a
 r i o XIII
C.8.2 Exemplo de registradores gerais 570
C.8.3 Comando de chamada e registradores de ponteiros 571
C.8.4 Depuração de um programa de impressão de vetores 574
C.8.5 Manipulação de cadeia e instruções de cadeia 576
C.8.6 Tabelas de despacho 579
C.8.7 Acesso a arquivo com buffer e aleatório 580
ÍNICE 584
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Prefa
cio
A
s cinco primeiras edições deste livro foram baseadas na ideia de que um computador pode ser considerado
uma hierarquia de níveis, cada um realizando alguma função bem definida. Esse conceito fundamental é
válido tanto hoje quanto na época da primeira edição, de modo que foi mantido como base para a sexta
edição. Assim como nas cinco primeiras edições, o nível lógico digital, o nível de microarquitetura, o nível de arqui-
tetura do conjunto de instruções, o nível de máquina do sistema operacional e o nível da linguagem de montagem
são todos discutidos com detalhes.
Embora a estrutura básica tenha sido mantida, esta edição contém muitas mudanças, pequenas e grandes,
que a mantém atualizada na área da computação, que muda tão rapidamente. Por exemplo, os modelos de
máquinas usados foram atualizados. Os exemplos atuais são ntel Core i7, Texas nstrument OMAP4430 e Atmel
ATmega168. O Core i7 é um exemplo de CPU popular usada em laptops, desktops e servidores. O OMAP4430 é
um tipo de CPU popular baseada em ARM, muito usada em smartphones e tablets.
Mesmo que você talvez nunca tenha ouvido falar do microcontrolador ATmega168, provavelmente já terá
interagido muitas vezes com um deles. O microcontrolador ATmega168 baseado no AR é encontrado em diversos
sistemas embutidos, variando desde rádios-relógios até fornos de micro-ondas. O interesse em sistemas embutidos
é cada vez maior, e o ATmega168 é muito usado poo seu custo baixíssimo (centavos), sua grande quantidade de
software e periféricos para ele e o grande número de programadores disponíveis. A quantidade de ATmega168s no
mundo decerto é maior que a de CPUs Pentium e Core i3, i5 e i7 por algumas ordens de grandeza. O ATmega168s
também é o processador encontrado no computador embutido Arduino de placa única, um sistema popular pro-
jetado em uma universidade italiana para custar menos que um jantar em uma pizzaria.
Ao longo dos anos, muitos professores que adotaram este livro solicitaram repetidas vezes material sobre
programação em linguagem de montagem (assembly). Com a sexta edição, esse material agora está disponível
na Sala irtual (veja adiante), onde pode ser expandido com facilidade e mantido de modo perene. A linguagem
de montagem escolhida é a do 8088, pois é uma versão reduzida do conjunto de instruções iA32 extremamente
popular, usado no processador Core i7. Poderíamos ter usado os conjuntos de instruções ARM ou AR, ou alguma
outra SA da qual quase ninguém ouviu falar, mas, como uma ferramenta de motivação, o 8088 é uma escolha
melhor, pois muitos alunos possuem uma CPU compatível com o 8088 em casa. O Core i7 completo é muito
complexo para os alunos entenderem com detalhes. O 8088 é semelhante, porém muito mais simples.
Além disso, o Core i7, que é abordado com detalhes nesta edição do livro, é capaz de executar programas 8088.
Porém, como a depuração do código de montagem é muito difícil, oferecemos um conjunto de ferramentas para
aprendizado da programação em linguagem de montagem, incluindo um assembler 8088, um simulador e um
rastreador. Essas ferramentas estão disponíveis para Windows, Solaris UN, e Linux, na Sala irtual.
O livro tornou-se mais extenso com o passar dos anos (a primeira edição tinha 443 páginas; esta tem 624
páginas). Essa expansão foi inevitável, tendo em vista que um assunto se desenvolve e há mais a saber sobre ele.
Como resultado, quando se resolve adotá-lo em um curso, nem sempre é possível terminá-lo em um único curso
(por exemplo, quando o curso é trimestral). Uma alternativa possível seria estudar, como um mínimo essencial,
os Capítulos 1, 2 e 3, a primeira parte do Capítulo 4 (até, e inclusive, a Seção 4.4) e o Capítulo 5. O tempo que
sobrar poderia ser utilizado com o restante do Capítulo 4 e partes dos Capítulos 6, 7 e 8, dependendo do interesse
do professor e dos alunos.
Em seguida apresentamos, capítulo por capítulo, uma resenha das principais mudanças desde a quinta edi-
ção. O Capítulo 1 ainda contém uma revisão histórica da arquitetura de computador, que mostra como chegamos
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
XVI
onde estamos hoje e quais foram os marcos ao longo do percurso. Muitos alunos ficarão surpresos ao descobrir
que os computadores mais poderosos do mundo na década de 1960, que custavam milhões de dólares america-
nos, tinham muito menos de 1% do poder de computação de seus smartphones. Discutimos também o espectro
ampliado dos computadores atuais, incluindo FGPAs, smartphones, tablets e consoles de jogos. Discutimos tam-
bém nossas três novas arquiteturas de exemplo (Core i7, OMAP4430 e ATmega168).
No Capítulo 2, o material sobre estilos de processamento foi expandido para incluir processadores paralelos
de dados, incluindo unidades de processamento gráfico (GPUs). O panorama do armazenamento foi expandido
para incluir os dispositivos de armazenamento baseados em memória flash, cada vez mais populares. Um material
novo foi acrescentado à seção de entrada/saída, que detalha os controladores de jogos modernos, incluindo o Wiimote
e o Kinect, além de telas sensíveis ao toque, usadas em smartphones e tablets.
O Capítulo 3 passou por uma revisão em diversas partes. Ele ainda começa no básico, explicando como
funcionam os transistores, e parte disso para que até mesmo os alunos sem qualquer base em hardware possam
entender, em princípio, como funciona um computador moderno. Oferecemos material novo sobre FPGAs (Field-
-Programmable Gate Arrays), fábricas de hardware programáveis, que levam os verdadeiros custos do projeto no
nível de porta em grande escala para onde eles são muito usados hoje, a sala de aula. Os três novos exemplos de
arquiteturas são descritos aqui em um nível mais alto.
O Capítulo 4 sempre foi benquisto por explicar como um computador realmente funciona, portanto a maior
parte dele não sofreu alterações desde a quinta edição. Contudo, há novas seções que discutem o nível de micro-
arquitetura do Core i7, do OMAP4430 e do ATmega168.
Os Capítulos 5 e 6 foram atualizados com base nos novos exemplos de arquitetura, particularmente com
novas seções descrevendo os conjuntos de instruções ARM e AR. O Capítulo 6 utiliza Windows 7 em vez do
Windows P como exemplo.
O Capítulo 7, sobre programação em linguagem de montagem, não teve muita alteração desde a quinta edição.
O Capítulo 8 sofreu muitas revisões, para refletir novos desenvolvimentos na área de computação paralela.
Foram incluídos mais detalhes sobre a arquitetura do multiprocessador Core i7, e a arquitetura GPU de uso geral
NDA Fermi é descrita com detalhes. Por fim, as seções sobre os supercomputadores BlueGene e Red Storm
foram atualizadas para refletir as atualizações recentes nessas enormes máquinas.
O Capítulo 9 mudou. As leituras sugeridas passaram para a Sala irtual, de modo que o novo texto contém
apenas as referências citadas no livro, muitas delas novas. A organização do computador é um campo dinâmico.
Os Apêndices A e B não foram atualizados desde a última vez. Números binários e números de ponto
flutuante não mudaram muito nos últimos anos. O Apêndice C, sobre programação em linguagem de montagem,
foi escrito pelo dr. Evert Wattel da rije Universiteit, Amsterdã. O dr. Wattel leciona há muitos anos e tem
ensinado seus alunos a usar essas ferramentas. Agradecemos a ele por ter escrito esse apêndice. Ele não mudou
muito desde a quinta edição, mas as ferramentas agora estão na Sala irtual.
Além das ferramentas para linguagem de montagem, a Sala irtual também contém um simulador grá-
fico a ser usado junto com o Capítulo 4. Esse simulador foi escrito pelo professor Richard Salter, do Oberlin
College, e pode ser usado pelos estudantes para ajudá-los a compreender os princípios discutidos nesse capítulo.
Agradecemos muito a ele por ter fornecido esse software.
Muitas pessoas leram partes do original e contribuíram com sugestões úteis ou ajudaram de diversas manei-
ras. Gostaríamos de agradecer, em particular, a ajuda prestada por Anna Austin, Mark Austin, Livio Bertacco,
aleria Bertacco, Debapriya Chatterjee, Jason Clemons, Andrew DeOrio, Joseph Greathouse e Andrea Pellegrini.
As pessoas citadas a seguir revisaram o original e sugeriram mudanças: Jason D. Bakos (University of South
Carolina), Bob Brown (Southern Polytechnic State University), Andrew Chen (Minnesota State University,
Moorhead), J. Archer Harris (James Madison University), Susan Krucke (James Madison University), A. Yavuz
Oruc (University of Maryland), Frances Marsh (Jamestown Community College) e Kris Schindler (University at
Buffalo). Somos muito gratos a eles.
P r e f a
 c i o XVII
árias pessoas ajudaram a criar novos exercícios. São elas: Byron A. Jeff (Clayton University), Laura W.
McFall (DePaul University), Taghi M. Mostafavi (University of North Carolina at Charlotte) e James Nystrom
(Ferris State University). Novamente, somos muito gratos por sua ajuda.
Nossa editora, Tracy Johnson, foi muito útil de diversas maneiras, grandes e pequenas, além de ser muito
paciente conosco. Somos muito gratos pelo auxílio de Carole Snyder na coordenação de várias pessoas envolvidas
no projeto. Bob Englehardt realizou um ótimo trabalho de produção.
Eu (AST) gostaria de agradecer mais uma vez a Suzanne por seu amor e paciência, que nunca se esgotaram,
nem mesmo após 21 livros. Barbara e Marvin são sempre uma alegria e agora sabem o que os professores fazem
para ganhar a vida. Aron pertence à próxima geração: crianças que são usuários intensos do computador, antes
mesmo de entrarem no jardim de infância. Nathan ainda não chegou a esse ponto, mas, depois que descobrir
como andar, o iPad será o próximo.
Por fim, eu (TA) gostaria de usar esta oportunidade para agradecer à minha sogra Roberta, que me ajudou a
reservar algum tempo para trabalhar neste livro. Sua mesa da sala de jantar em Bassano Del Grappa, tália, provi-
denciou a dose certa de isolamento, abrigo e vinho para realizar essa importante tarefa.
ANDREW S. TANENBAUM
TODD AUSTIN
Agradecimentos  Edic
a
o brasileira
Agradecemos a todos os profissionais envolvidos na produção deste livro, em especial ao Prof. Dr. Wagner
Luiz Zucchi (Escola Politécnica da USP
, nstituto de Pesquisas Tecnológicas – PT – e Universidade Nove de
Julho), pela dedicação e empenho na revisão técnica do conteúdo.
Material adicional
A Sala irtual do livro (<sv.pearson.com.br>) oferece recursos adicionais que auxiliarão professores
e alunos na exposição das aulas e no processo de aprendizagem.
Para o professor:
• Manual de soluções (em inglês)
• Apresentações em Power Point
Para o aluno:
• Download de aplicativos (assembler e tracer)
• Simulador gráfico para aplicações do Capítulo 4
• Sugestões de leitura para aprofundamento
O material dos professores é protegido por senha. Para ter acesso a eles, os professores que adotam o livro
devem entrar em contato com o seu representante Pearson ou enviar e-mail para universitarios@pearson.com.
AST: Para Suzanne, Barbara, Marvin, Aron e Nathan.
TA: Para Roberta, que criou espaço (e tempo) para eu terminar este projeto.
Introduc
a
o
capítulo 1
U
m computador digital é uma máquina que pode resolver problemas para as pessoas, executando ins-
truções que lhe são dadas. Uma sequência de instruções descrevendo como realizar determinada tarefa
é chamada de programa. Os circuitos eletrônicos de cada computador podem reconhecer e executar
diretamente um conjunto limitado de instruções simples, para o qual todos os programas devem ser converti-
dos antes que possam ser executados. Essas instruções básicas raramente são muito mais complicadas do que
Some dois números.
erifique se um número é zero.
Copie dados de uma parte da memória do computador para outra.
Juntas, as instruções primitivas de um computador formam uma linguagem com a qual as pessoas podem se
comunicar com ele. Essa linguagem é denominada linguagem de máquina. Quem projeta um novo computador
deve decidir quais instruções incluir em sua linguagem de máquina. De modo geral, os projetistas tentam tor-
nar as instruções primitivas as mais simples possíveis, coerentes com os requisitos de utilização e desempenho
idealizados para o computador e seus requisitos de desempenho, a fim de reduzir a complexidade e o custo dos
circuitos eletrônicos necessários. Como a maioria das linguagens de máquina é muito simples, sua utilização
direta pelas pessoas é difícil e tediosa.
Com o passar do tempo, essa observação simples tem levado a uma forma de estruturar os computadores
como uma sequência de abstrações, cada uma baseada naquela abaixo dela. Desse modo, a complexidade pode ser
dominada e os sistemas de computação podem ser projetados de forma sistemática e organizada. Denominamos
essa abordagem organização estruturada de computadores – foi esse o nome dado a este livro. Na seção seguin-
te, descreveremos o que significa esse termo. Logo após, comentaremos alguns desenvolvimentos históricos, o
estado atual da tecnologia e exemplos importantes.
Introduc
a
o
1
Cap
tulo
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
2
1.1 Organizac
a
o estruturada de computadores
Como já mencionamos, existe uma grande lacuna entre o que é conveniente para as pessoas e o que é conve-
niente para computadores. As pessoas querem fazer X, mas os computadores só podem fazer Y, o que dá origem
a um problema. O objetivo deste livro é explicar como esse problema pode ser resolvido.
1.1.1 Linguagens, n
veis e ma
quinas virtuais
O problema pode ser abordado de duas maneiras, e ambas envolvem projetar um novo conjunto de ins-
truções que é mais conveniente para as pessoas usarem do que o conjunto embutido de instruções de máquina.
Juntas, essas novas instruções também formam uma linguagem, que chamaremos de L1, assim como as instru-
ções de máquina embutidas formam uma linguagem, que chamaremos de L0. As duas técnicas diferem no modo
como os programas escritos em L1 são executados pelo computador que, afinal, só pode executar programas
escritos em sua linguagem de máquina, L0.
Um método de execução de um programa escrito em L1 é primeiro substituir cada instrução nele por uma
sequência equivalente de instruções em L0. O programa resultante consiste totalmente em instruções L0. O com-
putador, então, executa o novo programa L0 em vez do antigo programa L1. Essa técnica é chamada de tradução.
A outra técnica é escrever um programa em L0 que considere os programas em L1 como dados de entrada
e os execute, examinando cada instrução por sua vez, executando diretamente a sequência equivalente de ins-
truções L0. Essa técnica não requer que se gere um novo programa em L0. Ela é chamada de interpretação, e o
programa que a executa é chamado de interpretador.
Tradução e interpretação são semelhantes. Nos dois métodos, o computador executa instruções em L1
executando sequências de instruções equivalentes em L0. A diferença é que, na tradução, o programa L1 inteiro
primeiro é convertido para um L0, o programa L1 é desconsiderado e depois o novo L0 é carregado na memória
do computador e executado. Durante a execução, o programa L0 recém-gerado está sendo executado e está no
controle do computador.
Na interpretação, depois que cada instrução L1 é examinada e decodificada, ela é executada de imediato.
Nenhum programa traduzido é gerado. Aqui, o interpretador está no controle do computador. Para ele, o progra-
ma L1 é apenas dados. Ambos os métodos e, cada vez mais, uma combinação dos dois, são bastante utilizados.
Em vez de pensar em termos de tradução ou interpretação, muitas vezes é mais simples imaginar a existência
de um computador hipotético ou máquina virtual cuja linguagem seja L1. amos chamar essa máquina virtual de
M1 (e de M0 aquela correspondente a L0). Se essa máquina pudesse ser construída de forma barata o suficiente, não
seria preciso de forma alguma ter a linguagem L0 ou uma máquina que executou os programas em L0. As pessoas
poderiam simplesmente escrever seus programas em L1 e fazer com que o computador os executasse diretamente.
Mesmo que a máquina virtual cuja linguagem é L1 seja muito cara ou complicada de construir com circuitos ele-
trônicos, as pessoas ainda podem escrever programas para ela. Esses programas podem ser ou interpretados ou tra-
duzidos por um programa escrito em L0 que, por si só, consegue ser executado diretamente pelo computador real.
Em outras palavras, as pessoas podem escrever programas para máquinas virtuais, como se realmente existissem.
Para tornar prática a tradução ou a interpretação, as linguagens L0 e L1 não deverão ser “muito” diferentes.
Tal restrição significa quase sempre que L1, embora melhor que L0, ainda estará longe do ideal para a maioria
das aplicações. Esse resultado talvez seja desanimador à luz do propósito original da criação de L1 – aliviar o
trabalho do programador de ter que expressar algoritmos em uma linguagem mais adequada a máquinas do que
a pessoas. Porém, a situação não é desesperadora.
A abordagem óbvia é inventar outro conjunto de instruções que seja mais orientado a pessoas e menos
orientado a máquinas que a L1. Esse terceiro conjunto também forma uma linguagem, que chamaremos de L2 (e
com a máquina virtual M2). As pessoas podem escrever programas em L2 exatamente como se de fato existisse
uma máquina real com linguagem de máquina L2. Esses programas podem ser traduzidos para L1 ou executados
por um interpretador escrito em L1.
C a p 
t u l o 1 I n t r o d u c
 a
 o 3
A invenção de toda uma série de linguagens, cada uma mais conveniente que suas antecessoras, pode pros-
seguir indefinidamente, até que, por fim, se chegue a uma adequada. Cada linguagem usa sua antecessora como
base, portanto, podemos considerar um computador que use essa técnica como uma série de camadas ou níveis,
um sobre o outro, conforme mostra a Figura 1.1. A linguagem ou nível mais embaixo é a mais simples, e a lin-
guagem ou nível mais em cima é a mais sofisticada.
Figura 1.1 Ma
quina multin
vel.
Nível n
Nível 3
Nível 2
Nível 1
Nível 0
Máquina virtual Mn, com
linguagem de máquina Ln
Máquina virtual M3, com
linguagem de máquina L3
Máquina virtual M2, com
linguagem de máquina L2
Máquina virtual M1, com
linguagem de máquina L1
Computador real M0, com
linguagem de máquina L0
Programas em Ln são interpretados
por um interpretador rodando em
uma máquina de nível inferior ou
são traduzidos para a linguagem de
máquina de uma máquina de nível
inferior
Programas em L2 são interpretados
por interpretadores rodando em M1 ou
M0, ou são traduzidos para L1 ou L0
Programas em L1 são interpretados
por um interpretador rodando em M0,
ou são traduzidos para L0
Programas em L0 podem ser
executados diretamente pelos
circuitos eletrônicos
Há uma relação importante entre uma linguagem e uma máquina virtual. Cada máquina tem uma linguagem
de máquina, consistindo em todas as instruções que esta pode executar. Com efeito, uma máquina define uma
linguagem. De modo semelhante, uma linguagem define uma máquina – a saber, aquela que pode executar todos
os programas escritos na linguagem. Claro, pode ser muito complicado e caro construir a máquina definida por
determinada linguagem diretamente pelos circuitos eletrônicos, mas, apesar disso, podemos imaginá-la. Uma
máquina que tivesse C ou C++ ou Java como sua linguagem seria de fato complexa, mas poderia ser construída
usando a tecnologia de hoje. Porém, há um bom motivo para não construir tal computador: ele não seria econô-
mico em comparação com outras técnicas. O mero fato de ser factível não é bom o suficiente: um projeto prático
também precisa ser econômico.
De certa forma, um computador com n níveis pode ser visto como n diferentes máquinas virtuais, cada uma
com uma linguagem de máquina diferente. Usaremos os termos “nível” e “máquina virtual” para indicar a mesma
coisa. Apenas programas escritos na linguagem L0 podem ser executados diretamente pelos circuitos eletrônicos,
sem a necessidade de uma tradução ou interpretação intervenientes. Os programas escritos em L1, L2, ..., Ln
devem ser interpretados por um interpretador rodando em um nível mais baixo ou traduzidos para outra lingua-
gem correspondente a um nível mais baixo.
Uma pessoa que escreve programas para a máquina virtual de nível n não precisa conhecer os interpretadores
e tradutores subjacentes. A estrutura de máquina garante que esses programas, de alguma forma, serão execu-
tados. Não há interesse real em saber se eles são executados passo a passo por um interpretador que, por sua
vez, também é executado por outro interpretador, ou se o são diretamente pelos circuitos eletrônicos. O mesmo
resultado aparece nos dois casos: os programas são executados.
Quase todos os programadores que usam uma máquina de nível n estão interessados apenas no nível
superior, aquele que menos se parece com a linguagem de máquina do nível mais inferior. Porém, as pessoas
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
4
interessadas em entender como um computador realmente funciona deverão estudar todos os níveis. Quem pro-
jeta novos computadores ou novos níveis também deve estar familiarizado com outros níveis além do mais alto.
Os conceitos e técnicas de construção de máquinas como uma série de níveis e os detalhes dos próprios níveis
formam o assunto principal deste livro.
1.1.2 Ma
quinas multin
veis contempora
neas
A maioria dos computadores modernos consiste de dois ou mais níveis. Existem máquinas com até seis
níveis, conforme mostra a Figura 1.2. O nível 0, na parte inferior, é o hardware verdadeiro da máquina. Seus
circuitos executam os programas em linguagem de máquina do nível 1. Por razões de precisão, temos que men-
cionar a existência de outro nível abaixo do nosso nível 0. Esse nível, que não aparece na Figura 1.2 por entrar
no domínio da engenharia elétrica (e, portanto, estar fora do escopo deste livro), é chamado de nível de dispo-
sitivo. Nele, o projetista vê transistores individuais, que são os primitivos de mais baixo nível para projetistas de
computador. Se alguém quiser saber como os transistores funcionam no interior, isso nos levará para o campo
da física no estado sólido.
Figura 1.2 Um computador com seis n
veis. O me
todo de suporte para cada n
vel e
 indicado abaixo dele (junto com o nome do programa
que o suporta).
Nível 5
Nível 4
Nível 3
Nível 2
Nível 1
Nível 0
Nível de linguagem orientada a problema
Tradução (compilador)
Nível de linguagem Assembly
Tradução (assembler)
Nível de máquina do sistema operacional
Interpretação parcial (sistema operacional)
Nível de arquitetura do conjunto de instrução
Interpretação (microprograma) ou execução direta
Nível de microarquitetura
Hardware
Nível lógico digital
No nível mais baixo que estudaremos, o nível lógico digital, os objetos interessantes são chamados de por-
tas (ou gates). Embora montadas a partir de componentes analógicos, como transistores, podem ser modeladas
com precisão como dispositivos digitais. Cada porta tem uma ou mais entradas digitais (sinais representando 0
ou 1) e calcula como saída alguma função simples dessas entradas, como AND (E) ou OR (OU). Cada porta é
composta de no máximo alguns transistores. Um pequeno número de portas podem ser combinadas para formar
uma memória de 1 bit, que consegue armazenar um 0 ou um 1. As memórias de 1 bit podem ser combinadas
em grupos de (por exemplo) 16, 32 ou 64 para formar registradores. Cada registrador pode manter um único
número binário até algum máximo. As portas também podem ser combinadas para formar o próprio mecanismo
de computação principal. Examinaremos as portas e o nível lógico digital com detalhes no Capítulo 3.
C a p 
t u l o 1 I n t r o d u c
 a
 o 5
O próximo nível acima é o nível de microarquitetura. Aqui, vemos uma coleção de (em geral) 8 a 32 regis-
tradores que formam uma memória local e um circuito chamado UL  Unidade Lógica e rtitmética (em inglês
rithmetic Logic Unit), que é capaz de realizar operações aritméticas simples. Os registradores estão conectados
à ULA para formar um caminho de dados, sobre o qual estes fluem. A operação básica do caminho de dados con-
siste em selecionar um ou dois registradores, fazendo com que a ULA opere sobre eles (por exemplo, somando-
-os) e armazenando o resultado de volta para algum registrador.
Em algumas máquinas, a operação do caminho de dados é controlada por um programa chamado micro-
programa. Em outras, o caminho de dados é controlado diretamente pelo hardware. Nas três primeiras edições
deste livro, chamamos esse nível de “nível de microprogramação”, pois no passado ele quase sempre era um
interpretador de software. Como o caminho de dados agora quase sempre é (em parte) controlado diretamente
pelo hardware, mudamos o nome na quarta edição.
Em máquinas com controle do caminho de dados por software, o microprograma é um interpretador para
as instruções no nível 2. Ele busca, examina e executa instruções uma por vez, usando o caminho de dados. Por
exemplo, para uma instrução ADD, a instrução seria buscada, seus operandos localizados e trazidos para registra-
dores, a soma calculada pela ULA e, por fim, o resultado retornado para o local a que pertence. Em uma máquina
com controle do caminho de dados por hardware, haveria etapas semelhantes, mas sem um programa armazenado
explícito para controlar a interpretação das instruções desse nível.
Chamaremos o nível 2 de nível de arquitetura do conjunto de instrução, ou nível IS (Instruction Set
rchitecture). Os fabricantes publicam um manual para cada computador que vendem, intitulado “Manual
de Referência da Linguagem de Máquina”, ou “Princípios de Operação do Computador Western Wombat
Modelo 100”, ou algo semelhante. Esses manuais, na realidade, referem-se ao nível SA, e não aos subjacen-
tes. Quando eles explicam o conjunto de instruções da máquina, na verdade estão descrevendo as instruções
executadas de modo interpretativo pelo microprograma ou circuitos de execução do hardware. Se um fabri-
cante oferecer dois interpretadores para uma de suas máquinas, interpretando dois níveis SA diferentes, ele
precisará oferecer dois manuais de referência da “linguagem de máquina”, um para cada interpretador.
O próximo nível costuma ser híbrido. A maior parte das instruções em sua linguagem também está no nível
SA. (Não há motivo pelo qual uma instrução que aparece em um nível não possa estar presente também em
outros.) Além disso, há um conjunto de novas instruções, uma organização de memória diferente, a capacidade
de executar dois ou mais programas simultaneamente e diversos outros recursos. Existe mais variação entre os
projetos de nível 3 do que entre aqueles no nível 1 ou no nível 2.
As novas facilidades acrescentadas no nível 3 são executadas por um interpretador rodando no nível 2, o
qual, historicamente, tem sido chamado de sistema operacional. Aquelas instruções de nível 3 que são idênticas às
do nível 2 são executadas direto pelo microprograma (ou controle do hardware), e não pelo sistema operacional.
Em outras palavras, algumas das instruções de nível 3 são interpretadas pelo sistema operacional e algumas o são
diretamente pelo microprograma. É a isso que chamamos de nível “híbrido”. No decorrer deste livro, nós o
chamaremos de nível de máquina do sistema operacional.
Há uma quebra fundamental entre os níveis 3 e 4. Os três níveis mais baixos não servem para uso do progra-
mador do tipo mais comum. Em vez disso, eles são voltados principalmente para a execução dos interpretadores e
tradutores necessários para dar suporte aos níveis mais altos. Esses interpretadores e tradutores são escritos pelos
programadores de sistemas, profissionais que se especializam no projeto e execução de novas máquinas virtuais.
Os níveis 4 e acima são voltados para o programador de aplicações, que tem um problema para solucionar.
Outra mudança que ocorre no nível 4 é o método de suporte dos níveis mais altos. Os níveis 2 e 3 são sempre
interpretados. Em geral, mas nem sempre, os níveis 4, 5 e acima são apoiados por tradução.
Outra diferença entre níveis 1, 2 e 3, por um lado, e 4, 5 e acima, por outro, é a natureza da linguagem for-
necida. As linguagens de máquina dos níveis 1, 2 e 3 são numéricas. Os programas nessas linguagens consistem
em uma longa série de números, muito boa para máquinas, mas ruim para as pessoas. A partir do nível 4, as
linguagens contêm palavras e abreviações cujo significado as pessoas entendem.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
6
O nível 4, o da linguagem de montagem (assembly), na realidade é uma forma simbólica para uma das lin-
guagens subjacentes. Esse nível fornece um método para as pessoas escreverem programas para os níveis 1, 2 e
3 em uma forma que não seja tão desagradável quanto às linguagens de máquina virtual em si. Programas em
linguagem de montagem são primeiro traduzidos para linguagem de nível 1, 2 ou 3, e em seguida interpretados
pela máquina virtual ou real adequada. O programa que realiza a tradução é denominado assembler.
O nível 5 normalmente consiste em linguagens projetadas para ser usadas por programadores de aplica-
ções que tenham um problema a resolver. Essas linguagens costumam ser denominadas linguagens de alto
nível. Existem literalmente centenas delas. Algumas das mais conhecidas são C, C++, Java, Perl, Python e PHP.
Programas escritos nessas linguagens em geral são traduzidos para nível 3 ou nível 4 por tradutores conhecidos
como compiladores, embora às vezes sejam interpretados, em vez de traduzidos. Programas em Java, por exem-
plo, costumam ser primeiro traduzidos para uma linguagem semelhante à SA denominada código de bytes Java,
ou bytecode Java, que é então interpretada.
Em alguns casos, o nível 5 consiste em um interpretador para o domínio de uma aplicação específica, como
matemática simbólica. Ele fornece dados e operações para resolver problemas nesse domínio em termos que pes-
soas versadas nele possam entendê-lo com facilidade.
Resumindo, o aspecto fundamental a lembrar é que computadores são projetados como uma série de níveis,
cada um construído sobre seus antecessores. Cada nível representa uma abstração distinta na qual estão presen-
tes diferentes objetos e operações. Projetando e analisando computadores desse modo, por enquanto podemos
dispensar detalhes irrelevantes e assim reduzir um assunto complexo a algo mais fácil de entender.
O conjunto de tipos de dados, operações e características de cada nível é denominado arquitetura. Ela trata
dos aspectos que são visíveis ao usuário daquele nível. Características que o programador vê, como a quantidade
de memória disponível, são parte da arquitetura. Aspectos de implementação, como o tipo da tecnologia usada
para executar a memória, não são parte da arquitetura. O estudo sobre como projetar as partes de um sistema de
computador que sejam visíveis para os programadores é denominado arquitetura de computadores. Na prática,
contudo, arquitetura de computadores e organização de computadores significam basicamente a mesma coisa.
1.1.3 Evoluc
a
o de ma
quinas multin
veis
Para colocar as máquinas multiníveis em certa perspectiva, examinaremos rapidamente seu desenvolvimento
histórico, mostrando como o número e a natureza dos níveis evoluíram com o passar dos anos. Programas escri-
tos em uma verdadeira linguagem de máquina (nível 1) de um computador podem ser executados diretamente
pelos circuitos eletrônicos (nível 0) do computador, sem qualquer interpretador ou tradutor interveniente. Esses
circuitos eletrônicos, junto com a memória e dispositivos de entrada/saída, formam o hardware do computador.
Este consiste em objetos tangíveis – circuitos integrados, placas de circuito impresso, cabos, fontes de alimenta-
ção, memórias e impressoras – em vez de ideias abstratas, algoritmos ou instruções.
Por outro lado, o software consiste em algoritmos (instruções detalhadas que dizem como fazer algo) e suas
representações no computador – isto é, programas. Eles podem ser armazenados em disco rígido, CD-ROM, ou
outros meios, mas a essência do software é o conjunto de instruções que compõe os programas, e não o meio
físico no qual estão gravados.
Nos primeiros computadores, a fronteira entre hardware e software era nítida. Com o tempo, no entanto,
essa fronteira ficou bastante indistinta, principalmente por causa da adição, remoção e fusão de níveis à medida
que os computadores evoluíam. Hoje, muitas vezes é difícil distingui-la (ahid, 2003). Na verdade, um tema
central deste livro é
Hardware e software são logicamente equivalentes.
Qualquer operação executada por software também pode ser embutida diretamente no hardware, de preferên-
cia após ela ter sido suficientemente bem entendida. Como observou Karen Panetta: “Hardware é apenas software
petrificado”. Claro que o contrário é verdadeiro: qualquer instrução executada em hardware também pode ser
simulada em software. A decisão de colocar certas funções em hardware e outras em software é baseada em fatores
C a p 
t u l o 1 I n t r o d u c
 a
 o 7
como custo, velocidade, confiabilidade e frequência de mudanças esperadas. Existem poucas regras rigorosas e
imutáveis para determinar que  deva ser instalado no hardware e Y deva ser programado explicitamente. Essas
decisões mudam com as tendências econômicas, com a demanda e com a utilização de computadores.
A invenc
a
o da microprogramac
a
o
Os primeiros computadores digitais, na década de 1940, tinham apenas dois níveis: o nível SA, no qual era
feita toda a programação, e o nível lógico digital, que executava esses programas. Os circuitos do nível lógico
digital eram complicados, difíceis de entender e montar, e não confiáveis.
Em 1951, Maurice Wilkes, pesquisador da Universidade de Cambridge, sugeriu projetar um computador de
três níveis para simplificar de maneira drástica o hardware e assim reduzir o número de válvulas (pouco confiá-
veis) necessárias (Wilkes, 1951). Essa máquina deveria ter um interpretador embutido, imutável (o micropro-
grama), cuja função fosse executar programas de nível SA por interpretação. Como agora o hardware só teria de
executar microprogramas, que tinham um conjunto limitado de instruções, em vez de programas de nível SA,
cujos conjuntos de instruções eram muito maiores, seria necessário um número menor de circuitos eletrônicos.
Uma vez que, na época, os circuitos eletrônicos eram compostos de válvulas eletrônicas, tal simplificação pro-
metia reduzir o número de válvulas e, portanto, aumentar a confiabilidade (isto é, o número de falhas por dia).
Poucas dessas máquinas de três níveis foram construídas durante a década de 1950. Outras tantas foram
construídas durante a década de 1960. Em torno de 1970, a ideia de interpretar o nível SA por um micropro-
grama, em vez de diretamente por meios eletrônicos, era dominante. Todas as principais máquinas da época a
usavam.
A invenc
a
o do sistema operacional
Naqueles primeiros anos, grande parte dos computadores era “acessível a todos”, o que significava que o
programador tinha de operar a máquina pessoalmente. Ao lado de cada máquina havia uma planilha de utiliza-
ção. Um programador que quisesse executar um programa assinava a planilha e reservava um período de tempo,
digamos, quarta-feira, das 3 às 5 da manhã (muitos programadores gostavam de trabalhar quando a sala onde
a máquina estava instalada ficava tranquila). Quando chegava seu horário, o programador se dirigia à sala da
máquina com um pacote de cartões perfurados de 80 colunas (um meio primitivo de entrada de dados) em uma
das mãos e um lápis bem apontado na outra. Ao chegar à sala do computador, ele gentilmente levava até a porta
o programador que lá estava antes dele e tomava posse da máquina.
Se quisesse executar um programa em FORTRAN, o programador devia seguir estas etapas:
1. Ele1
se dirigia ao armário onde era mantida a biblioteca de programas, retirava o grande maço verde
rotulado “compilador FORTRAN”, colocava-o na leitora de cartões e apertava o botão START.
2. Então, colocava seu programa FORTRAN na leitora de cartões e apertava o botão CONTNUE. O pro-
grama era lido pela máquina.
3. Quando o computador parava, ele lia seu programa FORTRAN em um segundo momento. Embora
alguns compiladores exigissem apenas uma passagem pela entrada, muitos demandavam duas ou mais.
Para cada passagem, era preciso ler um grande maço de cartões.
4. Por fim, a tradução se aproximava da conclusão. Era comum o programador ficar nervoso perto do
fim porque, se o compilador encontrasse um erro no programa, ele teria de corrigi-lo e começar
todo o processo novamente. Se não houvesse erro, o compilador perfurava em cartões o programa
traduzido para linguagem de máquina.
5. Então, o programador colocava o programa em linguagem de máquina na leitora de cartões, junto com
o maço da biblioteca de sub-rotina, e lia ambos.
1 “Ele” deve ser entendido como “ele ou ela” em todo este livro.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
8
6. O programa começava a executar. Quase sempre não funcionava e parava de repente no meio. Em geral,
o programador mexia um pouco nas chaves de controle e observava as luzes do console durante alguns
instantes. Se tivesse sorte, conseguiria descobrir qual era o problema e corrigir o erro. Em seguida,
voltava ao armário onde estava guardado o grande e verde compilador FORTRAN e começava tudo de
novo. Se não tivesse tanta sorte, imprimia o conteúdo da memória, denominado de dump de memória,
e o levava para casa a fim de estudá-lo.
Esse procedimento, com pequenas variações, foi o normal em muitos centros de computação durante
anos. Ele forçava os programadores a aprender como operar a máquina e o que fazer quando ela parava, o
que acontecia com frequência. A máquina costumava ficar ociosa enquanto as pessoas carregavam cartões
pela sala afora ou coçavam a cabeça tentando descobrir por que seus programas não estavam funcionando
adequadamente.
Por volta de 1960, as pessoas tentaram reduzir o desperdício de tempo automatizando o trabalho do opera-
dor. Um programa denominado sistema operacional era mantido no computador o tempo todo. O programador
produzia certos cartões de controle junto com o programa, que eram lidos e executados pelo sistema operacional.
A Figura 1.3 apresenta uma amostra de serviço (job) para um dos primeiros sistemas operacionais de ampla uti-
lização, o FMS (FORTRAN Monitor System), no BM 709.
Figura 1.3 Amostra de servic
o (job) para o sistema operacional FMS.
Programa
FORTRAN
Cartões
de dados
*JOB, 5494, BARBARA
*XEQ
*FORTRAN
*DATA
*END
O sistema operacional lia o cartão *JOB e usava a informação nele contida para fins de contabilidade. (O
asterisco era usado para identificar cartões de controle, para que eles não fossem confundidos com cartões de
programa e de dados.) Depois, o sistema lia o cartão *FORTRAN, que era uma instrução para carregar o com-
pilador FORTRAN a partir de uma fita magnética. Então, o programa era lido para a máquina e compilava pelo
programa FORTRAN. Quando o compiladorterminava, ele devolvia o controle ao sistema operacional, que então
lia o cartão *DATA. sso era uma instrução para executar o programa traduzido, usando como dados os cartões
que vinham após o cartão *DATA.
Embora o sistema operacional fosse projetado para automatizar o trabalho do operador (daí seu nome), foi
também o primeiro passo para o desenvolvimento de uma nova máquina virtual. O cartão *FORTRAN podia ser
considerado uma instrução virtual “compilar programa”. De modo semelhante, o cartão *DATA podia ser con-
siderado uma instrução virtual “executar programa”. Um nível que contivesse apenas duas instruções não era lá
um grande nível, mas já era um começo.
Nos anos seguintes, os sistemas operacionais tornaram-se cada vez mais sofisticados. Novas instruções, facili-
dades e características foram adicionadas ao nível SA até que ele começou a parecer um novo nível. Algumas das
C a p 
t u l o 1 I n t r o d u c
 a
 o 9
instruções desse novo nível eram idênticas às do nível SA, mas outras, em particular as de entrada/saída, eram
completamente diferentes. As novas instruções começaram a ficar conhecidas como macros de sistema operacio-
nal ou chamadas do supervisor. Agora, o termo mais comum é chamada do sistema.
Sistemas operacionais também se desenvolveram de outras maneiras. Os primeiros liam maços de cartões e
imprimiam a saída na impressora de linha. Essa organização era conhecida como sistema batch. Em geral, havia
uma espera de várias horas entre o momento em que um programa entrava na máquina e o horário em que os
resultados ficavam prontos. Era difícil desenvolver software em tais circunstâncias.
No início da década de 1960, pesquisadores do Dartmouth College, do MT e de outros lugares desenvol-
veram sistemas operacionais que permitiam a vários programadores se comunicarem diretamente com o com-
putador. Esses sistemas tinham terminais remotos conectados ao computador central por linhas telefônicas. O
computador era compartilhado por muitos usuários. Um programador podia digitar um programa e obter os
resultados impressos quase de imediato em seu escritório, na garagem de sua casa ou onde quer que o terminal
estivesse localizado. Esses sistemas eram denominados sistemas de tempo compartilhado (ou timesharing).
Nosso interesse em sistemas operacionais está nas partes que interpretam as instruções e características pre-
sentes no nível 3 e que não estão presentes no nível SA, em vez de nos aspectos de compartilhamento de tempo.
Embora não venhamos a destacar o fato, você sempre deve estar ciente de que os sistemas operacionais fazem
mais do que apenas interpretar características adicionadas ao nível SA.
Migrac
a
o de funcionalidade para microco
digo
Assim que a microprogramação se tornou comum (por volta de 1970), os projetistas perceberam que podiam
acrescentar novas instruções simplesmente ampliando o microprograma. Em outras palavras, eles podiam acrescentar
“hardware” (novas instruções de máquina) por programação. Essa revelação levou a uma explosão virtual de conjun-
tos de instruções de máquina, pois os projetistas competiam uns com os outros para produzir conjuntos de ins-
truções maiores e melhores. Muitas delas não eram essenciais considerando que seu efeito podia ser conseguido
com facilidade pelas instruções existentes, embora às vezes fossem um pouco mais velozes do que uma sequência
já existente. Por exemplo, muitas máquinas tinham uma instrução NC (NCrement) que somava 1 a um número.
Como essas máquinas também tinham uma instrução geral ADD, não era necessário ter uma instrução especial
para adicionar 1 (ou 720, se fosse o caso). Contudo, NC normalmente era um pouco mais rápida que ADD, e
por isso foi inserida.
Por essa razão, muitas outras instruções foram adicionadas ao microprograma. Entre elas, as mais frequentes
eram:
1. nstruções para multiplicação e divisão de inteiros.
2. nstruções aritméticas para ponto flutuante.
3. nstruções para chamar e sair de procedimentos.
4. nstruções para acelerar laços (looping).
5. nstruções para manipular cadeias de caracteres.
Além do mais, assim que os projetistas de máquinas perceberam como era fácil acrescentar novas instruções,
começaram a procurar outras características para adicionar aos seus microprogramas. Alguns exemplos desses
acréscimos são:
1. Características para acelerar cálculos que envolvessem vetores (indexação e endereçamento indireto).
2. Características para permitir que os programas fossem movidos na memória após o início da execução
(facilidades de relocação).
3. Sistemas de interrupção que avisavam o computador tão logo uma operação de entrada ou saída
estivesse concluída.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
10
4. Capacidade para suspender um programa e iniciar outro com um pequeno número de instruções
(comutação de processos).
5. nstruções especiais para processar arquivos de áudio, imagem e multimídia.
Diversas outras características e facilidades também foram acrescentadas ao longo dos anos, em geral para
acelerar alguma atividade particular.
Eliminac
a
o da microprogramac
a
o
Os microprogramas engordaram durante os anos dourados da microprogramação (décadas de 1960 e 1970)
e também tendiam a ficar cada vez mais lentos à medida que se tornavam mais volumosos. Por fim, alguns pes-
quisadores perceberam que, eliminando o microprograma, promovendo uma drástica redução no conjunto de
instruções e fazendo com que as restantes fossem executadas diretamente (isto é, controle do caminho de dados
por hardware), as máquinas podiam ficar mais rápidas. Em certo sentido, o projeto de computadores fechou um
círculo completo, voltando ao modo como era antes que Wilkes inventasse a microprogramação.
Mas a roda continua girando. Processadores modernos ainda contam com a microprogramação para tradu-
zir instruções complexas em microcódigo interno, que pode ser executado diretamente no hardware preparado
para isso.
O objetivo dessa discussão é mostrar que a fronteira entre hardware e software é arbitrária e muda cons-
tantemente. O software de hoje pode ser o hardware de amanhã, e vice-versa. Além do mais, as fronteiras
entre os diversos níveis também são fluidas. Do ponto de vista do programador, o modo como uma instrução
é implementada não é importante, exceto, talvez, no que se refere à sua velocidade. Uma pessoa que esteja
programando no nível SA pode usar sua instrução de “multiplicar” como se fosse uma instrução de hardware
sem ter de se preocupar com ela ou até mesmo sem saber se ela é, na verdade, uma instrução de hardware. O
hardware de alguém é o software de outrem. oltaremos a todos esses tópicos mais adiante neste livro.
1.2 Marcos da arquitetura de computadores
Durante a evolução do computador digital moderno, foram projetados e construídos centenas de diferentes
tipos de computadores. Grande parte já foi esquecida há muito tempo, mas alguns causaram um impacto sig-
nificativo sobre as ideias modernas. Nesta seção, vamos apresentar um breve esboço de alguns dos principais
desenvolvimentos históricos, para entender melhor como chegamos onde estamos agora. Nem é preciso dizer que
esta seção apenas passa por alto os pontos de maior interesse e deixa muita coisa de fora. A Figura 1.4 apresenta
algumas máquinas que marcaram época e que serão discutidas nesta seção. Slater (1987) é uma boa referência de
consulta para quem quiser material histórico adicional sobre as pessoas que inauguraram a era do computador.
Biografias curtas e belas fotos em cores, de autoria de Louis Fabian Bachrach, de alguns dos principais fundadores
da era do computador são apresentadas no livro de arte de Morgan (1997).
1.2.1 A gerac
a
o zero  computadores meca
nicos (16421945)
A primeira pessoa a construir uma máquina de calcular operacional foi o cientista francês Blaise Pascal
(1623–1662), em cuja honra a linguagem Pascal foi batizada. Esse dispositivo, construído em 1642, quando
Pascal tinha apenas 19 anos, foi projetado para ajudar seu pai, um coletor de impostos do governo francês. Era
inteiramente mecânico, usava engrenagens e funcionava com uma manivela operada à mão.
C a p 
t u l o 1 I n t r o d u c
 a
 o 11
Figura 1.4 Alguns marcos no desenvolvimento do computador digital moderno.
Ano Nome Construído por Comentários
1834 Máquina analítica Babbage Primeira tentativa de construir um computador digital
1936 Z1 Zuse Primeira máquina de calcular com relés
1943 COLOSSUS Governo britânico Primeiro computador eletrônico
1944 Mark I Aiken Primeiro computador norte-americano de uso geral
1946 ENIAC Eckert/Mauchley A história moderna dos computadores começa aqui
1949 EDSAC Wilkes Primeiro computador com programa armazenado
1951 Whirlwind I MIT Primeiro computador de tempo real
1952 IAS von Neumann A maioria das máquinas atuais usa esse projeto
1960 PDP-1 DEC Primeiro minicomputador (50 vendidos)
1961 1401 IBM Máquina para pequenos negócios, com enorme popularidade
1962 7094 IBM Dominou computação científica no início da década de 1960
1963 B5000 Burroughs Primeira máquina projetada para uma linguagem de alto nível
1964 360 IBM Primeira linha de produto projetada como uma família
1964 6600 CDC Primeiro supercomputador científico
1965 PDP-8 DEC Primeiro minicomputador de mercado de massa (50 mil vendidos)
1970 PDP-11 DEC Dominou os minicomputadores na década de 1970
1974 8080 Intel Primeiro computador de uso geral de 8 bits em um chip
1974 CRAY-1 Cray Primeiro supercomputador vetorial
1978 VAX DEC Primeiro superminicomputador de 32 bits
1981 IBM PC IBM Deu início à era moderna do computador pessoal
1981 Osborne-1 Osborne Primeiro computador portátil
1983 Lisa Apple Primeiro computador pessoal com uma GUI
1985 386 Intel Primeiro ancestral de 32 bits da linha Pentium
1985 MIPS MIPS Primeira máquina comercial RISC
1985 XC2064 Xilinx Primeiro FPGA (Field-Programmable Gate Array)
1987 SPARC Sun Primeira estação de trabalho RISC baseada em SPARC
1989 GridPad Grid Systems Primeiro computador tablet comercial
1990 RS6000 IBM Primeira máquina superescalar
1992 Alpha DEC Primeiro computador pessoal de 64 bits
1992 Simon IBM Primeiro smartphone
1993 Newton Apple Primeiro computador palmtop (PDA)
2001 POWER4 IBM Primeiro multiprocessador com chip dual core
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
12
A máquina de Pascal podia efetuar apenas operações de adição e subtração, mas 30 anos mais tarde o grande
matemático alemão, barão Gottfried Wilhelm von Leibniz (1646–1716), construiu uma outra máquina mecânica
que também podia multiplicar e dividir. Na verdade, Leibniz construiu o equivalente a uma calculadora de bolso
de quatro operações três séculos atrás.
Durante 150 anos nada de muito importante aconteceu, até que um professor de matemática da Universidade
de Cambridge, Charles Babbage (1792–1871), o inventor do velocímetro, projetou e construiu sua primeira máqui-
na diferencial. Esse dispositivo mecânico que, assim como o de Pascal, só podia somar e subtrair, foi projetado para
calcular tabelas de números úteis para a navegação marítima. Toda a construção da máquina foi projetada para exe-
cutar um único algoritmo, o método de diferenças finitas que usava polinômios. A característica mais interessante
dessa máquina era seu método de saída: ela perfurava seus resultados sobre uma chapa de gravação de cobre com
uma punção de aço, prenunciando futuros meios de escrita única como cartões perfurados e CD-ROMs.
Embora o dispositivo funcionasse razoavelmente bem, Babbage logo se cansou dessa máquina que só podia exe-
cutar um único algoritmo. Ele começou a gastar quantidades cada vez maiores de seu tempo e da fortuna da família
(sem falar nas 17 mil libras do governo) no projeto e na construção de uma sucessora denominada máquina ana-
lítica. A máquina analítica tinha quatro componentes: a armazenagem (memória), o moinho (unidade de cálculo),
a seção de entrada (leitora de cartões perfurados) e a seção de saída (saída perfurada e impressa). A armazenagem
consistia em 1.000 palavras de 50 algarismos decimais, cada uma usada para conter variáveis e resultados. O moinho
podia aceitar operandos da armazenagem e então os somava, subtraía, multiplicava ou dividia e, por fim, devolvia o
resultado à armazenagem. Assim como a máquina diferencial, ela era inteiramente mecânica.
O grande avanço da máquina analítica era ser de uso geral. Lia instruções de cartões perfurados e as execu-
tava. Algumas instruções mandavam a máquina buscar dois números na armazenagem, trazê-los até o moinho,
efetuar uma operação com eles (por exemplo, adição) e enviar o resultado de volta para a armazenagem. Outras
podiam testar um número e desviá-lo condicionalmente, dependendo se ele era positivo ou negativo. Perfurando
um programa diferente nos cartões de entrada, era possível fazer com que a máquina analítica realizasse cálculos
diversos, o que não acontecia com a máquina diferencial.
isto que a máquina analítica era programável em uma linguagem de montagem simples, ela precisava de
software. Para produzi-lo, Babbage contratou uma jovem de nome Ada Augusta Lovelace, que era filha do famoso
poeta britânico Lord Byron. Assim, Ada Lovelace foi a primeira programadora de computadores do mundo. A
linguagem de programação Ada tem esse nome em sua homenagem.
nfelizmente, assim como muitos projetistas modernos, Babbage nunca conseguiu depurar o hardware por
completo. O problema era que ele precisava de milhares e milhares de dentes e rodas e engrenagens produzidos com
um grau de precisão que a tecnologia do século  não podia oferecer. Ainda assim, suas ideias estavam muito à
frente de sua época e, até hoje, a maioria dos computadores modernos tem uma estrutura muito semelhante à da
máquina analítica; portanto, é mais do que justo dizer que Babbage foi avô do computador digital moderno.
O próximo desenvolvimento importante ocorreu no final da década de 1930, quando um estudante de enge-
nharia alemão chamado Konrad Zuse construiu uma série de máquinas calculadoras automáticas usando relés
eletromagnéticos. Ele não conseguiu financiamento do governo após o início da guerra porque os burocratas
governamentais esperavam ganhar a guerra tão rapidamente que a nova máquina só estaria pronta após o término
do conflito. Zuse não conhecia o trabalho de Babbage, e suas máquinas foram destruídas pelo bombardeio aliado
de Berlim em 1944, portanto, seu trabalho não teve influência alguma sobre as máquinas subsequentes. Mesmo
assim, ele foi um dos pioneiros da área.
Um pouco mais tarde, nos Estados Unidos, duas pessoas também projetaram calculadoras, John Atanasoff no
owa State College e George Stibbitz no Bell Labs. A máquina de Atanasoff era surpreendentemente avançada para
sua época. Usava aritmética binária e a memória era composta de capacitores recarregados periodicamente para
impedir fuga de carga, um processo que ele denominou “sacudir a memória”. Os chips modernos de memória
dinâmica (DRAM) funcionam desse mesmo modo. nfelizmente, a máquina nunca se tornou operacional de fato.
De certo modo, Atanasoff era como Babbage: um visionário que acabou derrotado pela tecnologia de hardware
inadequada que existia em seu tempo.
C a p 
t u l o 1 I n t r o d u c
 a
 o 13
O computador de Stibbitz, embora mais primitivo do que o de Atanasoff, funcionou de verdade. Stibbitz fez
uma grande demonstração pública de sua máquina durante uma conferência no Dartmouth College em 1940.
Uma dos presentes era John Mauchley, desconhecido professor de física da Universidade da Pensilvânia. Mais
tarde, o mundo da computação ouviria mais a respeito do professor Mauchley.
Enquanto Zuse, Stibbitz e Atanasoff projetavam calculadoras automáticas, um jovem chamado Howard
Aiken remoía tediosos cálculos numéricos à mão como parte de sua pesquisa de doutorado em Harvard. Depois
de concluído o doutorado, Aiken reconheceu a importância de fazer cálculos à máquina. Foi à biblioteca, desco-
briu o trabalho de Babbage e decidiu construir com relés o computador de uso geral que ele não tinha conseguido
construir com rodas dentadas.
A primeira máquina de Aiken, a Mark , foi concluída em Harvard em 1944. Tinha 72 palavras de 23 algaris-
mos decimais cada e um tempo de instrução de 6 s. A entrada e a saída usavam fita de papel perfurada. Quando
Aiken concluiu o sucessor dessa máquina, a Mark , os computadores de relés já eram obsoletos. A era eletrônica
tinha começado.
1.2.2 A primeira gerac
a
o  va
lvulas (19451955)
O estímulo para o computador eletrônico foi a Segunda Guerra Mundial. Durante a fase inicial do conflito,
submarinos alemães causavam estragos em navios britânicos. As instruções de comando dos almirantes em Berlim
eram enviadas aos submarinos por rádio, as quais os britânicos podiam interceptar – e interceptavam. O problema
era que as mensagens eram codificadas usando um dispositivo denominado ENIGM, cujo antecessor foi proje-
tado pelo inventor amador e outrora presidente dos Estados Unidos, Thomas Jefferson.
Logo no início da guerra, a inteligência britânica conseguiu adquirir uma máquina ENGMA da inteligência polo-
nesa, que a tinha roubado dos alemães2
. Contudo, para decifrar uma mensagem codificada era preciso uma quantidade
enorme de cálculos e, para a mensagem ser de alguma utilidade, era necessário que esse cálculo fosse concluído logo
depois de ela ter sido interceptada. Para decodificar essas mensagens, o governo britânico montou um laboratório
ultrassecreto que construiu um computador eletrônico denominado COLOSSUS. O famoso matemático britânico Alan
Turing ajudou a projetar essa máquina. Esse computador funcionava desde 1943, mas, uma vez que o governo britâ-
nico guardou praticamente todos os aspectos do projeto como segredo militar durante 30 anos, a linha COLOSSUS foi
um beco sem saída. Só vale a pena citá-lo por ter sido o primeiro computador digital eletrônico do mundo.
Além de destruir as máquinas de Zuse e estimular a construção do COLOSSUS, a guerra também afetou
a computação nos Estados Unidos. O exército precisava de tabelas de alcance visando sua artilharia pesada, e
as produzia contratando centenas de mulheres para fazer os cálculos necessários com calculadoras de mão (as
mulheres eram consideradas mais precisas que os homens). Ainda assim, o processo era demorado e surgiam
erros com frequência.
John Mauchley, que conhecia o trabalho de Atanasoff, bem como o de Stibbitz, sabia que o exército estava
interessadoemcalculadorasmecânicas.Comomuitoscientistasdacomputaçãoquevieramdepoisdele,Mauchley
montou uma proposta solicitando ao exército financiamento para a construção de um computador eletrônico. A
proposta foi aceita em 1943, e Mauchley e seu aluno de pós-graduação, J. Presper Eckert, passaram a construir
um computador eletrônico, ao qual deram o nome de ENIC (Electronic Numerical Integrator nd Computer 
integrador e computador numérico eletrônico). O ENAC consistia em 18 mil válvulas e 1.500 relés, pesava
30 toneladas e consumia 140 kw de energia. Em termos de arquitetura, a máquina tinha 20 registradores,
cada um com capacidade para conter um número decimal de 10 algarismos. (Um registrador decimal é uma
memória muito pequena que pode conter desde um número até outro número máximo de casas decimais,
mais ou menos como o odômetro, que registra quanto um carro rodou em seu tempo de vida útil.) O ENAC
era programado com o ajuste de até 6 mil interruptores multiposição e com a conexão de uma imensa quan-
tidade de soquetes com uma verdadeira floresta de cabos de interligação.
2 N. do RT: Antes da guerra, os alemães vendiam uma versão comercial da ENIGMA com três engrenagens, modelo igual ao que os poloneses
passaram aos ingleses. A versão militar possuía quatro engrenagens. Em: Stephen Budiansky. Battle of Wits  The complete story of codebreaking
in World War II. Penguin Books Ltd.: Londres, 2000.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
14
A construção da máquina só foi concluída em 1946, tarde demais para ser de alguma utilidade em relação
a seu propósito original. Todavia, como a guerra tinha acabado, Mauchley e Eckert receberam permissão para
organizar um curso de verão para descrever seu trabalho para seus colegas cientistas. Aquele curso de verão foi o
início de uma explosão de interesse na construção de grandes computadores digitais.
Após aquele curso de verão histórico, outros pesquisadores se dispuseram a construir computadores ele-
trônicos. O primeiro a entrar em operação foi o EDSAC (1949), construído na Universidade de Cambridge por
Maurice Wilkes. Entre outros, figuravam JOHNNAC, da Rand Corporation; o LLAC, da Universidade de
llinois; o MANAC, do Los Alamos Laboratory; e o WEZAC, do Weizmann nstitute em srael.
Eckert e Mauchley logo começaram a trabalhar em um sucessor, o EVC (Electronic iscrete
Variable utomatic Computer). Contudo, o projeto ficou fatalmente comprometido quando eles deixaram a
Universidade da Pensilvânia para fundar uma empresa nova, a Eckert-Mauchley Computer Corporation, na
Filadélfia. (O ale do Silício ainda não tinha sido inventado.) Após uma série de fusões, a empresa se tornou
a moderna Unisys Corporation.
Como um aporte legal, Eckert e Mauchley solicitaram uma patente alegando que haviam inventado o compu-
tador digital. Em retrospecto, possuir essa patente não seria nada mau. Após anos de litígio, o tribunal decidiu que
a patente de Eckert-Mauchley era inválida e que John Atanasoff tinha inventado o computador digital, embora
nunca o tivesse patenteado, colocando efetivamente a invenção em domínio público.
Enquanto Eckert e Mauchley trabalhavam no EDAC, uma das pessoas envolvidas no projeto ENAC,
John von Neumann, foi para o nstitute of Advanced Studies de Princeton para construir sua própria versão do
EDAC, a máquina IS. on Neumann era um gênio, da mesma estirpe de Leonardo da inci. Falava muitos
idiomas, era especialista em ciências físicas e matemática e guardava na memória tudo o que já tinha ouvido, visto
ou lido. Conseguia citar sem consulta, palavra por palavra, o texto de livros que tinha lido anos antes. Na época
em que se interessou por computadores, já era o mais eminente matemático do mundo.
Uma das coisas que logo ficou óbvia para ele foi que programar computadores com quantidades imensas de
interruptores e cabos era uma tarefa lenta, tediosa e inflexível. Ele percebeu que o programa podia ser represen-
tado em forma digital na memória do computador, junto com os dados. Também viu que a desajeitada aritmética
decimal serial usada pelo ENAC, com cada dígito representado por 10 válvulas (1 acesa e 9 apagadas), podia ser
substituída por aritmética binária paralela, algo que Atanasoff tinha percebido anos antes.
O projeto básico, o primeiro que ele descreveu, agora é conhecido como máquina de von Neumann. Ela foi
usada no EDSAC, o primeiro computador de programa armazenado, e agora, mais de meio século depois, ainda é
a base de quase todos os computadores digitais. Esse projeto – e a máquina AS, construída em colaboração com
Herman Goldstine – teve uma influência tão grande que vale a pena descrevê-lo rapidamente. Embora o nome
de von Neumann esteja sempre ligado a esse projeto, Goldstine e outros também lhe deram grande contribuição.
Um esboço da arquitetura é dado na Figura 1.5.
Figura 1.5 Ma
quina original de von Neumann.
Memória
Unidade de
controle
Unidade de
lógica e aritmética
Acumulador
Entrada
Saída
C a p 
t u l o 1 I n t r o d u c
 a
 o 15
A máquina de von Neumann tinha cinco partes básicas: a memória, a unidade de lógica e aritmética, a
unidade de controle e o equipamento de entrada e saída. A memória consistia em 4.096 palavras, uma palavra
contendo 40 bits, cada bit sendo 0 ou 1. Cada palavra continha ou duas instruções de 20 bits ou um inteiro de
40 bits com sinal. As instruções tinham 8 bits dedicados a identificar o tipo da instrução e 12 bits para especificar
uma das 4.096 palavras de memória. Juntas, a unidade de lógica e aritmética e a unidade de controle formavam
o “cérebro” do computador. Em computadores modernos, elas são combinadas em um único chip, denominado
CPU (Central Processing Unit  unidade central de processamento).
Dentro da unidade de lógica e aritmética havia um registrador interno especial de 40 bits, denominado acu-
mulador. Uma instrução típica adicionava uma palavra de memória ao acumulador ou armazenava o conteúdo
deste na memória. A máquina não tinha aritmética de ponto flutuante porque von Neumann achava que qualquer
matemático competente conseguiria acompanhar o ponto decimal (na verdade, o ponto binário) de cabeça.
Mais ou menos ao mesmo tempo em que von Neumann construía sua máquina AS, pesquisadores do MT
também estavam construindo um computador. Diferente do AS, do ENAC e de outras máquinas desse tipo, cujas
palavras tinham longos comprimentos e eram destinadas a cálculos numéricos pesados, a máquina do MT, a
Whirlwind , tinha uma palavra de 16 bits e era projetada para controle em tempo real. Esse projeto levou à inven-
ção da memória de núcleo magnético por Jay Forrester e, depois, por fim, ao primeiro minicomputador comercial.
Enquanto tudo isso estava acontecendo, a BM era uma pequena empresa dedicada ao negócio de produzir
perfuradoras de cartões e máquinas mecânicas de classificação de cartões. Embora tenha contribuído para o finan-
ciamento de Aiken, a BM não estava muito interessada em computadores até que produziu o 701 em 1953, muito
tempo após a empresa de Eckert e Mauchley ter alcançado o posto de número um no mercado comercial, com
seu computador UNAC. O 701 tinha 2.048 palavras de 36 bits, com duas instruções por palavra. Foi o primeiro
de uma série de máquinas científicas que vieram a dominar o setor dentro de uma década. Três anos mais tarde,
apareceu o 704 que, de início, tinha 4.096 palavras de memória de núcleos, instruções de 36 bits e uma inovação:
hardware de ponto flutuante. Em 1958, a BM começou a produzir sua última máquina de válvulas, a 709, que
era basicamente um 704 incrementado.
1.2.3 A segunda gerac
a
o  transistores (19551965)
O transistor foi inventado no Bell Labs em 1948 por John Bardeen, Walter Brattain e William Shockley, pelo
qual receberam o Prêmio Nobel de física de 1956. Em dez anos, o transistor revolucionou os computadores e, ao
final da década de 1950, os computadores de válvulas estavam obsoletos. O primeiro computador transistorizado
foi construído no Lincoln Laboratory do MT, uma máquina de 16 bits na mesma linha do Whirlwind . Recebeu
o nome de X-0 (ransistorized eXperimental computer 0  computador transistorizado experimental 0), e a
intenção era usá-la apenas como dispositivo para testar o muito mais elegante T-2.
O T-2 nunca foi um grande sucesso, mas um dos engenheiros que trabalhava no laboratório, Kenneth
Olsen, fundou uma empresa, a Digital Equipment Corporation (DEC), em 1957, para fabricar uma máquina
comercial muito parecida com o T-0. Quatro anos se passaram antes que tal máquina, o PDP-1, aparecesse,
principalmente porque os investidores de risco que fundaram a DEC estavam convictos de que não havia merca-
do para computadores. Afinal, T. J. Watson, antigo presidente da BM, certa vez dissera que o mercado mundial
de computadores correspondia a cerca de quatro ou cinco unidades. Em vez de computadores, a DEC vendia
pequenas placas de circuitos.
Quando o PDP-1 finalmente apareceu em 1961, tinha 4.096 palavras de 18 bits e podia executar 200 mil ins-
truções por segundo. Esse desempenho era a metade do desempenho do BM 7090, o sucessor transistorizado do
709 e o computador mais rápido do mundo na época. O PDP-1 custava 120 mil dólares; o 7090 custava milhões.
A DEC vendeu dezenas de PDP-1s, e nascia a indústria de minicomputadores.
Um dos primeiros PDP-1s foi dado ao MT, onde logo atraiu a atenção de alguns novos gênios em aprimo-
ramento tão comuns ali. Uma das muitas inovações do PDP-1 era um visor e a capacidade de plotar pontos em
qualquer lugar de sua tela de 512 por 512. Em pouco tempo, os estudantes já tinham programado o PDP-1 para
jogar Spacewar, e o mundo teria ganhado seu primeiro videogame.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
16
Alguns anos mais tarde, a DEC lançou o PDP-8, que era uma máquina de 12 bits, porém muito mais barata
que o PDP-1 (16 mil dólares). O PDP-8 tinha uma importante inovação: um barramento único, o omnibus, con-
forme mostra a Figura 1.6. Um barramento é um conjunto de fios paralelos usados para conectar os componen-
tes de um computador. Essa arquitetura foi uma ruptura importante em relação à arquitetura da máquina AS,
centrada na memória, e, desde então, foi adotada por quase todos os computadores de pequeno porte. A DEC
alcançou a marca de 50 mil PDP-8 vendidos, o que a consolidou como a líder no negócio de minicomputadores.
Figura 1.6 Barramento omnibus do PDP-8.
CPU Memória
Terminal
de console
E/S de fita
de papel
Outra E/S
Omnibus
Enquanto isso, a reação da BM ao transistor foi construir uma versão transistorizada do 709, o 7090, como
já mencionamos, e, mais tarde, o 7094. Esse último tinha um tempo de ciclo de 2 microssegundos e 32.768 pala-
vras de 36 bits de memória de núcleos. O 7090 e o 7094 marcaram o final das máquinas do tipo ENAC, mas
dominaram a computação científica durante anos na década de 1960.
Ao mesmo tempo em que se tornava uma grande força na computação científica com o 7094, a BM estava
ganhando muito dinheiro com a venda de uma pequena máquina dirigida para empresas, denominada 1401. Essa
máquina podia ler e escrever fitas magnéticas, ler e perfurar cartões, além de imprimir saída de dados quase tão
rapidamente quanto o 7094, e por uma fração do preço dele. Era terrível para a computação científica, mas per-
feita para manter registros comerciais.
O 1401 era fora do comum porque não tinha nenhum registrador, nem mesmo um comprimento de palavra
fixo. Sua memória tinha 4 mil bytes de 8 bits, embora modelos posteriores suportassem até incríveis 16 mil bytes.
Cada byte continha um caractere de 6 bits, um bit administrativo e um bit para indicar o final da palavra. Uma
instrução MOE, por exemplo, tinha um endereço-fonte e um endereço-destino, e começava a transferir bytes da
fonte ao destino até encontrar um bit de final com valor 1.
Em 1964, uma minúscula e desconhecida empresa, a Control Data Corporation (CDC), lançou a 6600, uma
máquina que era cerca de uma ordem de grandeza mais rápida do que a poderosa 7094 e qualquer outra existente
na época. Foi amor à primeira vista para os calculistas, e a CDC partiu a caminho do sucesso. O segredo de sua
velocidade e a razão de ser tão mais rápida do que a 7094 era que, dentro da CPU, havia uma máquina com alto
grau de paralelismo. Ela tinha diversas unidades funcionais para efetuar adições, outras para efetuar multiplica-
ções e ainda mais uma para divisão, e todas elas podiam funcionar em paralelo. Embora extrair o melhor dessa
máquina exigisse cuidadosa programação, com um pouco de trabalho era possível executar dez instruções ao
mesmo tempo.
Como se não bastasse, a 6600 tinha uma série de pequenos computadores internos para ajudá-la, uma espé-
cie de “Branca de Neve e as Sete Pessoas erticalmente Prejudicadas”. sso significava que a CPU podia gastar
todo o seu tempo processando números, deixando todos os detalhes de gerenciamento de jobs e entrada/saída
para os computadores menores. Em retrospecto, a 6600 estava décadas à frente de sua época. Muitas das ideias
fundamentais encontradas em computadores modernos podem ser rastreadas diretamente até ela.
O projetista da 6600, Seymour Cray, foi uma figura legendária, da mesma estatura de von Neumann. Ele
dedicou sua vida inteira à construção de máquinas cada vez mais rápidas, denominadas então de supercomputa-
dores, incluindo a 6600, 7600 e Cray-1. Também inventou o famoso algoritmo para comprar carros: vá à conces-
C a p 
t u l o 1 I n t r o d u c
 a
 o 17
sionária mais próxima de sua casa, aponte para o carro mais próximo da porta e diga: “ou levar aquele”. Esse
algoritmo gasta o mínimo de tempo em coisas sem importância (como comprar carros) para deixar o máximo de
tempo livre para fazer coisas importantes (como projetar supercomputadores).
Havia muitos outros computadores nessa época, mas um se destaca por uma razão bem diferente e que
vale a pena mencionar: o Burroughs B5000. Os projetistas de máquinas como PDP-1, 7094 e 6600 estavam
totalmente preocupados com o hardware, seja para que ficassem mais baratos (DEC) ou mais rápidos (BM e
CDC). O software era praticamente irrelevante. Os projetistas do B5000 adotaram uma linha de ação diferente.
Construíram uma máquina com a intenção específica de programá-la em linguagem Algol 60, uma precursora
da C e da Java, e incluíram muitas características no hardware para facilitar a tarefa do compilador. Nascia a
ideia de que o software também era importante. nfelizmente, ela foi esquecida quase de imediato.
1.2.4 A terceira gerac
a
o  circuitos integrados (19651980)
A invenção do circuito integrado de silício por Jack Kilby e Robert Noyce (trabalhando independentemente)
em 1958 permitiu que dezenas de transistores fossem colocados em um único chip. Esse empacotamento possi-
bilitava a construção de computadores menores, mais rápidos e mais baratos do que seus precursores transistori-
zados. Alguns dos computadores mais significativos dessa geração são descritos a seguir.
Em 1964, a BM era a empresa líder na área de computadores e tinha um grande problema com suas duas
máquinas de grande sucesso, a 7094 e a 1401: elas eram tão incompatíveis quanto duas máquinas podem ser.
Uma era uma processadora de números de alta velocidade, que usava aritmética binária em registradores de 36
bits; a outra, um processador de entrada/saída avantajado, que usava aritmética decimal serial sobre palavras de
comprimento variável na memória. Muitos de seus clientes empresariais tinham ambas e não gostavam da ideia
de ter dois departamentos de programação sem nada em comum.
Quando chegou a hora de substituir essas duas séries, a BM deu um passo radical. Lançou uma única linha
de produtos, a linha System/360, baseada em circuitos integrados e projetada para computação científica e tam-
bém comercial. A linha System/360 continha muitas inovações, das quais a mais importante era ser uma família
de uma meia dúzia de máquinas com a mesma linguagem de montagem e tamanho e capacidade crescentes. Uma
empresa poderia substituir seu 1401 por um 360 Modelo 30 e seu 7094 por um 360 Modelo 75. O Modelo 75
era maior e mais rápido (e mais caro), mas o software escrito para um deles poderia, em princípio, ser executado
em outro. Na prática, o programa escrito para um modelo pequeno seria executado em um modelo grande sem
problemas. Porém, a recíproca não era verdadeira. Quando transferido para uma máquina menor, o programa
escrito para um modelo maior poderia não caber na memória. Ainda assim, era uma importante melhoria em
relação à situação do 7094 e do 1401. A ideia de famílias de máquinas foi adotada de pronto e, em poucos anos,
a maioria dos fabricantes de computadores tinha uma família de máquinas comuns que abrangiam uma ampla
faixa de preços e desempenhos. Algumas características da primeira família 360 são mostradas na Figura 1.7. Mais
tarde, foram lançados outros modelos.
Figura 1.7 Oferta inicial da linha de produtos IBM 360.
Propriedade Modelo 30 Modelo 40 Modelo 50 Modelo 65
Desempenho relativo 1 3,5 10 21
Tempo de ciclo (em bilionésimos de segundo) 1.000 625 500 250
Memória máxima (bytes) 65.536 262.144 262.144 524.288
Bytes lidos por ciclo 1 2 4 16
Número máximo de canais de dados 3 3 4 6
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
18
Outra importante inovação da linha 360 era a multiprogramação, com vários programas na memória ao
mesmo tempo, de modo que, enquanto um esperava por entrada/saída para concluir sua tarefa, outro podia exe-
cutar, o que resultava em uma utilização mais alta da CPU.
A 360 também foi a primeira máquina que podia emular (simular) outros computadores. Os modelos meno-
res podiam emular a 1401, e os maiores podiam emular a 7094, de maneira que os clientes podiam continuar a
executar seus antigos programas binários sem modificação durante a conversão para a 360. Alguns modelos exe-
cutavam programas 1401 com uma rapidez tão maior que a própria 1401 que muitos clientes nunca converteram
seus programas.
A emulação era fácil na 360 porque todos os modelos iniciais e grande parte dos que vieram depois eram
microprogramados. Bastava que a BM escrevesse três microprogramas: um para o conjunto nativo de instruções
da 360, um para o conjunto de instruções da 1401 e outro para o conjunto de instruções da 7094. Essa flexibili-
dade foi uma das principais razões para a introdução da microprogramação na 360. É lógico que a motivação de
Wilkes para reduzir a quantidade de válvulas não importava mais, pois a 360 não tinha válvula alguma.
A 360 resolveu o dilema “binária paralela” versus “decimal serial” com uma solução conciliatória: a máquina
tinha 16 registradores de 32 bits para aritmética binária, mas sua memória era orientada para bytes, como a da 1401.
Também tinha instruções seriais no estilo da 1401 para movimentar registros de tamanhos variáveis na memória.
Outra característica importante da 360 era (para a época) um imenso espaço de endereçamento de 224
(16.777.216) bytes. Como naquele tempo a memória custava vários dólares por byte, esse tanto de memória
parecia uma infinidade. nfelizmente, a série 360 foi seguida mais tarde pelas séries 370, 4300, 3080, 3090, 390
e a série z, todas usando basicamente a mesma arquitetura. Em meados da década de 1980, o limite de memória
tornou-se um problema real e a BM teve de abandonar a compatibilidade em parte, quando mudou para endere-
ços de 32 bits necessários para endereçar a nova memória de 232
bytes.
Com o benefício de uma percepção tardia, podemos argumentar que, uma vez que de qualquer modo tinham
palavras e registros de 32 bits, provavelmente também deveriam ter endereços de 32 bits, mas na época ninguém podia
imaginar uma máquina com 16 milhões de bytes de memória. Embora a transição para endereços de 32 bits tenha sido
bem-sucedida para a BM, essa mais uma vez foi apenas uma solução temporária para o problema do endereçamento de
memória, pois os sistemas de computação logo exigiriam a capacidade de endereçar mais de 232
(4.294.967.296) bytes
de memória. Dentro de mais alguns anos, entrariam em cena os computadores com endereços de 64 bits.
O mundo dos minicomputadores também avançou um grande passo na direção da terceira geração quando a
DEC lançou a série PDP-11, um sucessor de 16 bits do PDP-8. Sob muitos aspectos, a série PDP-11 era como um
irmão menor da série 360, tal como o PDP-1 era um irmãozinho da 7094. Ambos, 360 e PDP-11, tinham registra-
dores orientados para palavras e uma memória orientada para bytes, e ambos ocupavam uma faixa que abrangia
uma considerável relação preço/desempenho. O PDP-11 teve enorme sucesso, em especial nas universidades, e
deu continuidade à liderança da DEC sobre os outros fabricantes de minicomputadores.
1.2.5 A quarta gerac
a
o  integrac
a
o em escala muito grande (1980?)
Na década de 1980, a VLSI (Very Large Scale Integration  integração em escala muito grande) tinha pos-
sibilitado colocar primeiro dezenas de milhares, depois centenas de milhares e, por fim, milhões de transistores
em um único chip. Esse desenvolvimento logo levou a computadores menores e mais rápidos. Antes do PDP-1,
os computadores eram tão grandes e caros que empresas e universidades tinham de ter departamentos especiais
denominados centrais de computação para usá-los. Com a chegada do minicomputador, cada departamento
podia comprar sua própria máquina. Em 1980, os preços caíram tanto que era viável um único indivíduo ter seu
próprio computador. Tinha início a era do computador pessoal.
Computadores pessoais eram utilizados de modo muito diferente dos computadores grandes. Eram usados
para processar textos, montar planilhas e para numerosas aplicações de alto grau de interação (como os jogos)
que as máquinas maiores não manipulavam bem.
Os primeiros computadores pessoais costumavam ser vendidos como kits. Cada kit continha uma placa de
circuito impresso, um punhado de chips, que em geral incluía um ntel 8080, alguns cabos, uma fonte de energia
C a p 
t u l o 1 I n t r o d u c
 a
 o 19
e talvez um disco flexível de 8 polegadas. Juntar essas partes para montar um computador era tarefa do com-
prador. O software não era fornecido. Se quisesse algum, você mesmo teria de escrevê-lo. Mais tarde, o sistema
operacional CP/M, escrito por Gary Kildall, tornou-se popular nos 8080s. Era um verdadeiro sistema operacional
em disco flexível, com um sistema de arquivo e comandos de usuário digitados no teclado e enviados a um pro-
cessador de comandos (shell).
Outro computador pessoal era o Apple, e mais tarde o Apple , projetados por Steve Jobs e Steve Wozniak
na tão falada garagem. Essa máquina gozava de enorme popularidade entre usuários domésticos e em escolas, e
fez da Apple uma participante séria no mercado quase da noite para o dia.
Depois de muito deliberar e observar o que as outras empresas estavam fazendo, a BM, que então era a
força dominante na indústria de computadores, por fim decidiu que queria entrar no negócio de computadores
pessoais. Em vez de projetar toda a máquina partindo do zero, usando somente peças da BM, o que levaria tempo
demasiado, fez algo que não lhe era característico. Deu a Philip Estridge, um de seus executivos, uma grande mala
de dinheiro e disse-lhe que fosse para bem longe dos acionistas intrometidos da sede da empresa em Armonk,
Nova York, e só voltasse quando tivesse um computador pessoal em funcionamento. Estridge se estabeleceu a
dois mil km da sede, em Boca Raton, Flórida, escolheu o ntel 8088 como sua CPU, e construiu o BM Personal
Computer com componentes encontrados na praça. Foi lançado em 1981 e logo se tornou o maior campeão de
vendas de computadores da história. Quando o PC alcançou 30 anos, foram publicados diversos artigos sobre sua
história, incluindo os de Bradley (2011), Goth (2011), Bride (2011) e Singh (2011).
A BM também fez algo que não lhe era característico e de que mais tarde viria a se arrepender. Em vez de
manter o projeto da máquina em total segredo (ou ao menos protegido por uma patente), como costumava fazer,
a empresa publicou os planos completos, incluindo todos os diagramas de circuitos, em um livro vendido por 49
dólares. A ideia era possibilitar a fabricação, por outras empresas, de placas de expansão (plug-in) para o BM PC,
a fim de aumentar sua flexibilidade e popularidade. nfelizmente para a BM, uma vez que o projeto se tornara
totalmente público e era fácil obter todas as peças no mercado, inúmeras outras empresas começaram a fabricar
clones do PC, muitas vezes por bem menos do que a BM estava cobrando. Assim, começava toda uma indústria.
Embora outras empresas fabricassem computadores pessoais usando CPUs não fornecidas pela ntel, entre
elas Commodore, Apple e Atari, o impulso adquirido pela indústria do BM PC era tão grande que os outros foram
esmagados por esse rolo compressor. Apenas uns poucos sobreviveram, em nichos de mercado.
Um dos que sobreviveram, embora por um triz, foi o Macintosh da Apple. O Macintosh foi lançado em 1984
como o sucessor do malfadado Lisa, o primeiro computador que vinha com uma GUI (Graphical User Interface 
interface gráfica de usuário), semelhante à agora popular interface Windows. O Lisa fracassou porque era muito
caro, mas o Macintosh de menor preço lançado um ano depois foi um enorme sucesso e inspirou amor e paixão
entre seus muitos admiradores.
Esse primeiro mercado do computador pessoal também levou ao desejo até então inaudito por computadores
portáteis. Naquele tempo, um computador portátil fazia tanto sentido quanto hoje faz um refrigerador portátil.
O primeiro verdadeiro computador pessoal portátil foi o Osborne-1 que, com 11 quilos, era mais um computa-
dor “arrastável” do que portátil. Ainda assim, era prova de que a ideia de um computador portátil era possível.
O Osborne-1 foi um sucesso comercial modesto, mas um ano mais tarde a Compaq lançou seu primeiro clone
portátil do BM PC e logo se estabeleceu como a líder no mercado de computadores portáteis.
A versão inicial do BM PC vinha equipada com o sistema operacional MS-DOS fornecido pela então minús-
cula Microsoft Corporation. Assim como a ntel conseguia produzir CPUs cada vez mais potentes, a BM e a
Microsoft conseguiram desenvolver um sucessor do MS-DOS, denominado OS/2, que apresentava uma interface
gráfica de usuário semelhante à do Apple Macintosh. Ao mesmo tempo, a Microsoft também desenvolvia seu
próprio sistema operacional, o Windows, que rodava sobre o MS-DOS caso o OS/2 não pegasse. Para encurtar
a história, o OS/2 não pegou, a BM e a Microsoft tiveram uma ruptura notavelmente pública e a Microsoft foi
adiante e transformou o Windows em um enorme sucesso. O modo como a minúscula ntel e a mais insignifi-
cante ainda Microsoft conseguiram destronar a BM, uma das maiores, mais ricas e mais poderosas corporações
da história mundial, é uma parábola sem dúvida relatada com grandes detalhes nas escolas de administração de
empresas de todo o mundo.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
20
Com o sucesso do 8088 em mãos, a ntel continuou fazendo versões maiores e melhores dele.
Particularmente digno de nota foi o 80386, lançado em 1985, que tinha uma CPU de 32 bits. Este foi segui-
do por uma versão melhorada, naturalmente denominada 80486. As versões seguintes receberam os nomes
Pentium e Core. Esses chips são usados em quase todos os PCs modernos. O nome genérico que muita gente
usa para descrever a arquitetura desses processadores é x86. Os chips compatíveis, fabricados pela AMD, tam-
bém são denominados x86s.
Em meados da década de 1980, um novo desenvolvimento denominado RSC (discutido no Capítulo 2)
começou a se impor, substituindo complicadas arquiteturas (CSC) por outras bem mais simples, embora mais
rápidas. Na década de 1990, começaram a aparecer CPUs superescalares. Essas máquinas podiam executar
várias instruções ao mesmo tempo, muitas vezes em ordem diferente da que aparecia no programa. amos
apresentar os conceitos de CSC, RSC e superescalar no Capítulo 2 e discuti-los em detalhes ao longo de todo
este livro.
Também em meados da década de 1980, Ross Freeman e seus colegas na ilinx desenvolveram uma técnica
inteligente para montar circuitos integrados, que não exigia uma fortuna ou o acesso a uma fábrica de silício. Esse
novo tipo de chip de computador, denominado FPG (Field-Programmable Gate rray), continha uma grande
quantidade de portas lógicas genéricas, que poderiam ser “programadas” em qualquer circuito que coubesse no
dispositivo. Essa extraordinária nova técnica de projeto tornou o hardware FPGA tão maleável quanto o software.
Usando FPGAs que custavam dezenas a centenas de dólares americanos, era possível montar sistemas de compu-
tação especializados para aplicações exclusivas, que serviam apenas a alguns usuários. Felizmente, as empresas de
fabricação de silício ainda poderiam produzir chips mais rápidos, com menor consumo de energia e mais baratos
para aplicações que precisavam de milhões de chips. Porém, para aplicações com apenas alguns poucos usuários,
como prototipagem, aplicações de projeto em baixo volume e educação, FPGAs continuam sendo uma ferramenta
popular para a construção do hardware.
Até 1992, computadores pessoais eram de 8, 16 ou 32 bits. Então, a DEC surgiu com o revolucioná-
rio Alpha de 64 bits, uma verdadeira máquina RSC de 64 bits cujo desempenho ultrapassava por grande
margem o de todos os outros computadores pessoais. Seu sucesso foi modesto, mas quase uma década se
passou antes que as máquinas de 64 bits começassem a ter grande sucesso e, na maior parte das vezes, como
servidores de topo de linha.
Durante a década de 1990, os sistemas de computação estavam se tornando cada vez mais rápidos
usando uma série de aperfeiçoamentos microarquitetônicos, e muitos deles serão examinados neste livro.
Os usuários desses sistemas eram procurados pelos vendedores de computador, pois cada novo sistema que
eles compravam executava seus programas muito mais depressa do que em seu antigo sistema. Porém, ao
final da década, essa tendência estava começando a desaparecer, devido a obstáculos importantes no projeto
do computador: os arquitetos estavam esgotando seus truques para tornar seus programas mais rápidos e
os processadores estavam ficando mais caros de resfriar. Desesperadas para continuar a montar processa-
dores mais rápidos, a maioria das empresas de computador começou a se voltar para arquiteturas paralelas
como um modo de obter mais desempenho do seu silício. Em 2001, a BM introduziu a arquitetura dual
core POWER4. Essa foi a primeira vez que uma CPU importante incorporava dois processadores no mesmo
substrato. Hoje, a maioria dos processadores da classe desktop e servidor, e até mesmo alguns processadores
embutidos, incorporam múltiplos processadores no chip. nfelizmente, o desempenho desses multiproces-
sadores tem sido menor que estelar para o usuário comum, pois (como veremos em outros capítulos) as
máquinas paralelas exigem que os programadores trabalhem explicitamente em paralelo, o que é difícil e
passível de erros.
1.2.6 A quinta gerac
a
o  computadores de baixa pote
ncia e invis
veis
Em 1981, o governo japonês anunciou que estava planejando gastar 500 milhões de dólares para ajudar
empresas a desenvolver computadores de quinta geração que seriam baseados em inteligência artificial e repre-
sentariam um salto quântico em relação aos computadores “burros” da quarta geração. Como já tinham visto
C a p 
t u l o 1 I n t r o d u c
 a
 o 21
empresas japonesas se apossarem do mercado em muitos setores, de máquinas fotográficas a aparelhos de som e
de televisão, os fabricantes de computadores americanos e europeus foram de zero a pânico total em um milisse-
gundo, exigindo subsídios do governo e outras coisas. A despeito do grande barulho, o projeto japonês da quinta
geração fracassou e foi abandonado sem alarde. Em certo sentido, foi como a máquina analítica de Babbage –
uma ideia visionária, mas tão à frente de seu tempo que nem se podia vislumbrar a tecnologia necessária para
realmente construí-la.
Não obstante, aquilo que poderia ser denominado a quinta geração na verdade aconteceu, mas de modo ines-
perado: os computadores encolheram. Em 1989, a Grid Systems lançou o primeiro tablet, denominado GridPad.
Ele consistia em uma pequena tela em que os usuários poderiam escrever com uma caneta especial, para controlar
o sistema. Sistemas como o GridPad mostraram que os computadores não precisam estar sobre uma mesa ou em
uma sala de servidores, mas poderiam ser colocados em um pacote fácil de carregar, com telas sensíveis ao toque
e reconhecimento de escrita, para torná-los ainda mais valiosos.
O Newton da Apple, lançado em 1993, mostrou que um computador podia ser construído dentro de um
invólucro não maior do que um tocador de fitas cassete portátil. Assim como o GridPad, o Newton usava escrita
à mão para entrada do usuário, o que provou ser um grande obstáculo, mas máquinas posteriores dessa classe,
agora denominadas Ps (Personal igital ssistants  assistentes digitais pessoais), aprimoraram as interfa-
ces de usuário e tornaram-se muito populares. Agora, elas evoluíram para smartphones.
Por fim, a interface de escrita do PDA foi aperfeiçoada por Jeff Hawkins, que criou uma empresa chamada
Palm para desenvolver um PDA de baixo custo para o mercado consumidor em massa. Hawkins era engenheiro
elétrico por treinamento, mas tinha um real interesse pela neurociência, que é o estudo do cérebro humano.
Ele observou que o reconhecimento da escrita à mão poderia se tornar mais confiável treinando-se os usuários
a escreverem de uma maneira mais legível pelos computadores, uma técnica de entrada que ele chamou de
“Graffiti”. Ela exigia um pouco de treinamento para o usuário, mas por fim levou a uma escrita mais rápida e mais
confiável, e o primeiro PDA da Palm, denominado Palm Pilot, foi um grande sucesso. Graffiti é um dos grandes
sucessos na computação, demonstrando o poder da mente humana de tirar proveito do poder da mente humana.
Os usuários de PDAs eram adeptos destes dispositivos, usando-os religiosamente para gerenciar seus com-
promissos e contatos. Quando os telefones celulares começaram a ganhar popularidade no início da década de
1990, a BM aproveitou a oportunidade para integrar o telefone celular com o PDA, criando o “smartphone”. O
primeiro, chamado Simon, usava uma tela sensível ao toque como entrada e dava ao usuário todas as capacidades
de um PDA mais telefone, jogos e e-mail. A redução no tamanho dos componentes e no custo por fim levou ao
grande uso de smartphones, incorporado nas populares plataformas Apple iPhone e Google Android.
Mas mesmo os PDAs e smartphones não são revolucionários de verdade. Ainda mais importantes são
os computadores “invisíveis”, embutidos em eletrodomésticos, relógios, cartões bancários e diversos outros
dispositivos (Bechini et al., 2004). Esses processadores permitem maior funcionalidade e custo mais baixo em
uma ampla variedade de aplicações. Considerar esses chips uma verdadeira geração é discutível (estão por aí
desde a década de 1970, mais ou menos), mas eles estão revolucionando o modo de funcionamento de milhares
de aparelhos e outros dispositivos. Já começaram a causar um importante impacto no mundo e sua influência
crescerá rapidamente nos próximos anos. Um aspecto peculiar desses computadores embutidos é que o hard-
ware e software costumam ser projetados em conjunto (Henkel et al., 2003). oltaremos a eles mais adiante
neste livro.
Se entendermos a primeira geração como máquinas a válvula (por exemplo, o ENAC), a segunda geração
como máquinas a transistores (por exemplo, o BM 7094), a terceira geração como as primeiras máquinas de
circuito integrado (por exemplo, o BM 360), e a quarta geração como computadores pessoais (por exemplo, as
CPUs ntel), a real quinta geração é mais uma mudança de paradigma do que uma nova arquitetura específica.
No futuro, computadores estarão por toda parte e embutidos em tudo – de fato, invisíveis. Eles serão parte da
estrutura da vida diária, abrindo portas, acendendo luzes, fornecendo cédulas de dinheiro e milhares de outras
coisas. Esse modelo, arquitetado pelo falecido Mark Weiser, foi denominado originalmente computação ubí-
qua, mas o termo computação pervasiva também é usado agora com frequência (Weiser, 2002). Ele mudará
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
22
o mundo com tanta profundidade quanto a Revolução ndustrial. Não o discutiremos mais neste livro, mas se
o leitor quiser mais informações sobre ele, deve consultar: Lyytinen e Yoo, 2002; Saha e Mukherjee, 2003 e
Sakamura, 2002.
1.3 O zoolo
gico dos computadores
Na seção anterior, apresentamos uma breve história dos sistemas de computação. Nesta, examinaremos o
presente e olharemos para o futuro. Embora computadores pessoais sejam os mais conhecidos, há outros tipos
de máquinas hoje, portanto, vale a pena dar uma pesquisada no que há mais por aí.
1.3.1 Forc
as tecnolo
gicas e econo
micas
A indústria de computadores está avançando como nenhuma outra. A força propulsora primária é a capaci-
dade dos fabricantes de chips de empacotar cada vez mais transistores por chip todo ano. Mais transistores, que
são minúsculos interruptores eletrônicos, significam memórias maiores e processadores mais poderosos. Gordon
Moore, cofundador e ex-presidente do conselho da ntel, certa vez disse, brincando, que, se a tecnologia da aviação
tivesse progredido tão depressa quanto a tecnologia de computadores, um avião custaria 500 dólares e daria uma
volta na Terra em 20 minutos com 20 litros de gasolina. Entretanto, seria do tamanho de uma caixa de sapatos.
Especificamente, ao preparar uma palestra para um grupo do setor, Moore observou que cada nova geração
de chips de memória estava sendo lançada três anos após a anterior. Uma vez que cada geração tinha quatro vezes
mais memória do que sua antecessora, ele percebeu que o número de transistores em um chip estava crescendo
a uma taxa constante e previu que esse crescimento continuaria pelas próximas décadas. Essa observação ficou
conhecida como lei de Moore. Hoje, a lei de Moore costuma ser expressa dizendo que o número de transistores
dobra a cada 18 meses. Note que isso equivale a um aumento de 60% no número de transistores por ano. Os
tamanhos dos chips de memória e suas datas de lançamento mostrados na Figura 1.8 confirmam que a lei de
Moore está valendo há mais de quatro décadas.
Figura 1.8 A lei de Moore preve
 um aumento anual de 60% no nu
mero de transistores que podem ser colocados em um chip.
Os dados pontuais informados nesta figura sa
o tamanhos de memo
rias em bits.
100G
10G
1G
100M
10M
1M
100K
10K
1K
100
10
1
1965 1970
1K
16K
4K
64K
256K
4M
1M
16M
64M
256M
512M
1G
2G
1975 1980 1985 1990 1995 2000 2005 2010
Claro que a lei de Moore não é uma lei real, mas uma simples observação empírica sobre quão rápido os
físicos do estado sólido e os engenheiros estão avançando o estado da arte e uma previsão de que eles continuarão
Número
de
transistores
Ano
C a p 
t u l o 1 I n t r o d u c
 a
 o 23
na mesma taxa no futuro. Alguns observadores do setor esperam que a lei de Moore continue válida ao menos
por mais uma década, talvez até por mais tempo. Outros observadores esperam que dissipação de energia, fuga
de corrente e outros efeitos apareçam antes e causem sérios problemas que precisam ser resolvidos (Bose, 2004;
Kim et al., 2003). Contudo, a realidade do encolhimento de transistores é que a espessura desses dispositivos logo
será de apenas alguns átomos. Nesse ponto, os transistores consistirão de muito poucos átomos para que sejam
confiáveis, ou simplesmente chegaremos a um ponto onde outras diminuições de tamanho exigirão blocos de
montagem subatômicos. (Como um conselho, recomenda-se que aqueles que trabalham em uma fábrica de silício
tirem folga no dia em que decidirem dividir o transistor de um átomo!) Apesar dos muitos desafios na extensão
das tendências da lei de Moore, existem tecnologias favoráveis no horizonte, incluindo os avanços na computação
quântica (Oskin et al., 2002) e nanotubos de carbono (Heinze et al., 2002), que podem criar oportunidades para
escalar a eletrônica além dos limites do silício.
A lei de Moore criou o que os economistas chamam de círculo virtuoso. Progressos na tecnologia (transisto-
res/chip) levam a melhores produtos e preços mais baixos. Preços mais baixos levam a novas aplicações (ninguém
estava fabricando videogames para computadores quando estes custavam 10 milhões de dólares cada, embora,
quando o preço caiu para 120 mil dólares, os alunos do MT aceitaram o desafio). Novas aplicações levam a
novos mercados e a novas empresas, que surgem para aproveitar as vantagens desses mercados. A existência de
todas essas empresas leva à concorrência que, por sua vez, cria demanda econômica por melhores tecnologias,
que substituirão as outras. Então, o círculo deu uma volta completa.
Outro fator que trouxe avanço tecnológico foi a primeira lei do software de Nathan (trata-se de Nathan
Myhrvold, antigo alto executivo da Microsoft). Diz a lei: “O software é um gás. Ele se expande até preencher o
recipiente que o contém”. Na década de 1980, processamento de textos era feito com programas como o troff
(ainda usado para este livro). O troff ocupa kilobytes de memória. Os modernos processadores de textos ocupam
megabytes de memória. Os futuros sem dúvida exigirão gigabytes de memória. (Por uma primeira aproximação,
os prefixos kilo, mega, giga e tera significam mil, milhão, bilhão e trilhão, respectivamente, mas veja a Seção 1.5
para outros detalhes.) O software que continua a adquirir características (não muito diferente dos celulares que
estão sempre adquirindo novas aplicações) cria uma demanda constante por processadores mais velozes, memó-
rias maiores e mais capacidade de E/S.
Enquanto os ganhos em transistores por chip tinham sido vultosos ao longo dos anos, os ganhos em outras
tecnologias não foram menores. Por exemplo, o BM PC/T foi lançado em 1982 com um disco rígido de 10 mega-
bytes. Trinta anos depois, discos rígidos de 1 terabyte eram comuns nos sucessores do PC/T. Esse avanço de cinco
ordens de grandeza em 30 anos representa um aumento de capacidade de 50% ao ano. Contudo, medir o avanço em
discos é mais enganoso, visto que há outros parâmetros além da capacidade, como taxas (de transferência) de dados,
tempo de busca e preço. Não obstante, quase qualquer método de medição mostrará que a razão preço/desempenho
aumentou desde 1982 pelo menos 50% ao ano. Esses enormes ganhos em desempenho do disco, aliados ao fato
de que o volume de dólares de discos despachados do ale do Silício ultrapassou o de chips de CPU, levaram Al
Hoagland a sugerir que o nome do local estava errado: deveria ser ale do Óxido de Ferro (já que é esse o mate-
rial de gravação utilizado em discos). Lentamente, essa tendência está se deslocando em favor do silício, enquanto
memórias flash baseadas em silício começam a substituir os discos giratórios tradicionais em muitos sistemas.
Outra área que teve ganhos espetaculares foi a de telecomunicações e redes. Em menos de duas décadas
fomos de modems de 300 bits/s para modems analógicos de 56 mil bits/s, e daí para redes de fibra ótica de 1012
bits/s. Os cabos de telefonia transatlânticos de fibra ótica, como o TAT-12/13, custam cerca de 700 milhões de
dólares, duram dez anos e podem transportar 300 mil ligações telefônicas simultâneas, o que se traduz em menos
do que 1 centavo de dólar para uma ligação telefônica intercontinental de dez minutos. Sistemas ópticos de
comunicação que funcionam a 1012
bits/s, a distâncias que passam de 100 km e sem amplificadores, mostraram
ser viáveis. Nem é preciso comentar aqui o crescimento exponencial da nternet.
1.3.2 Tipos de computadores
Richard Hamming, antigo pesquisador do Bell Labs, certa vez observou que uma mudança de uma ordem de
grandeza em quantidade causa uma mudança na qualidade. Assim, um carro de corrida que alcança 1.000 km/h
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
24
no deserto de Nevada é um tipo de máquina muito diferente de um carro normal que alcança 100 km/h em uma
rodovia. De modo semelhante, um arranha-céu de 100 andares não é apenas um edifício de apartamentos de
10 andares em escala maior. E, no que se refere a computadores, não estamos falando de fatores de 10, mas, no
decurso de três décadas, estamos falando de fatores na casa de milhão.
Os ganhos concedidos pela lei de Moore podem ser usados de vários modos por vendedores de chips. Um
deles é construir computadores cada vez mais poderosos a preço constante. Outra abordagem é construir o
mesmo computador por uma quantia de dinheiro cada vez menor a cada ano. A indústria fez ambas as coisas
e ainda mais, o que resultou na ampla variedade de computadores disponíveis agora. Uma categorização muito
aproximada dos computadores existentes hoje é dada na Figura 1.9.
Figura 1.9 Tipos de computador dispon
veis atualmente. Os prec
os devem ser vistos com certa condescende
ncia (cum grano salis).
Tipo Preço (US$) Exemplo de aplicação
Computador descartável 0,5 Cartões de felicitação
Microcontrolador 5 Relógios, carros, eletrodomésticos
Computador móvel e de jogos 50 Videogames domésticos e smartphones
Computador pessoal 500 Computador de desktop ou notebook
Servidor 5K Servidor de rede
Mainframe 5M Processamento de dados em bloco em um banco
Nas seções seguintes, examinaremos cada uma dessas categorias e discutiremos brevemente suas propriedades.
1.3.3 Computadores descarta
veis
Na extremidade inferior desse tipo encontramos um único chip colado na parte interna de um cartão de con-
gratulações, que toca “Feliz Aniversário” ou “Lá vem a noiva”, ou qualquer outra dessas musiquinhas igualmente
horrorosas. O autor ainda não encontrou um cartão de condolências que tocasse uma marcha fúnebre, mas, como
lançou essa ideia em público, espera encontrá-lo em breve. Para quem cresceu com mainframes de muitos milhões
de dólares, a ideia de computadores descartáveis faz tanto sentido quanto a de um avião descartável.
Contudo, os computadores descartáveis chegaram para ficar. Provavelmente, o desenvolvimento mais impor-
tante na área dos computadores descartáveis é o chip RFI (Radio Frequency Ientification  identificação por
radiofrequência). Agora é possível fabricar, por alguns centavos, chips RFD sem bateria com menos de 0,5 mm
de espessura, que contêm um minúsculo transponder de rádio e um único número de 128 bits embutido. Quando
pulsados por uma antena externa, são alimentados pelo sinal de rádio de entrada por tempo suficiente para trans-
mitir seu número de volta à antena. Embora os chips sejam minúsculos, suas implicações com certeza não são.
amos começar com uma aplicação corriqueira: acabar com os códigos de barras de produtos. Já foram feitos
testes experimentais nos quais o fabricante anexou chips RFD (em vez de códigos de barras) a seus produtos
à venda em lojas. O cliente escolhe as mercadorias, coloca-as em um carrinho de compras e apenas as leva para
fora da loja, sem passar pela caixa registradora. Na saída da loja, um leitor munido de uma antena envia um sinal
solicitando que cada produto se identifique, o que cada um faz por meio de uma curta transmissão sem fio. O
cliente também é identificado por um chip embutido em seu cartão bancário ou de crédito. No final do mês, a loja
envia ao cliente uma fatura, identificada por itens, referente às compras do mês. Se o cartão de banco ou cartão de
crédito RFD do cliente não for válido, um alarme é ativado. Esse sistema não só elimina a necessidade de caixas
e a correspondente espera na fila, mas também serve como método antifurto, porque de nada adianta esconder
um produto no bolso ou na sacola.
C a p 
t u l o 1 I n t r o d u c
 a
 o 25
Uma propriedade interessante desse sistema é que, embora os códigos de barra identifiquem o tipo de produ-
to, não identificam o item específico. Com 128 bits à disposição, os chips RFD fazem isso. Como consequência,
cada pacote de aspirina, por exemplo, em um supermercado, terá um código RFD diferente. sso significa que,
se um fabricante de medicamentos descobrir um defeito de fabricação em um lote de aspirinas após ele ter sido
despachado, poderá informar a todos os supermercados do mundo inteiro para que façam disparar o alarme
sempre que um cliente comprar qualquer pacote cujo número RFD esteja na faixa afetada, mesmo que a compra
aconteça em um país distante, meses depois. As cartelas de aspirina que não pertençam ao lote defeituoso não
farão soar o alarme.
Mas rotular pacotes de aspirina, de bolachas, de biscoitos para cachorro é só o começo. Por que parar nos bis-
coitos para cachorro quando você pode rotular o próprio cachorro? Donos de animais de estimação já estão pedindo
aos veterinários para implantar chips RFD em seus animais de modo que possam ser rastreados se forem roubados
ou perdidos. Fazendeiros também vão querer marcar seus rebanhos. O próximo passo óbvio é pais ansiosos pedirem
a seus pediatras que implantem chips RFD em seus filhos para o caso de eles se perderem ou serem sequestrados. Já
que estamos nisso, por que não fazer os hospitais identificarem todos os recém-nascidos para evitar troca de bebês?
E os governos e a polícia sem dúvida terão muitas boas razões para rastrear todos os cidadãos o tempo todo. Agora,
as “implicações” dos chips RFD a que aludimos anteriormente estão ficando um pouco mais claras.
Outra aplicação (um pouco menos controvertida) de chips RFD é o rastreamento de veículos. Quando uma
fila de automóveis com chips RFD embutidos estiver trafegando por uma rodovia e passarem por uma leitora, o
computador ligado à leitora terá uma lista dos carros que estiveram por ali. Esse sistema facilita o rastreamento
da localização de todos os veículos que passam por uma rodovia, o que ajuda fornecedores, seus clientes e as
rodovias. Um esquema semelhante pode ser aplicado a caminhões. No caso dos carros, a ideia já está sendo usada
para cobrar pedágio por meios eletrônicos (por exemplo, o sistema E-Z Pass).
Sistemas de transporte de bagagens aéreas e muitos outros sistemas de transporte de encomendas também
podem usar chips RFD. Um sistema experimental testado no aeroporto de Heathrow, em Londres, permitia que
os passageiros eliminassem a necessidade de carregar sua bagagem. As malas dos clientes que pagavam por esse
serviço recebiam um chip RFD, eram descarregadas em separado no aeroporto e entregues diretamente nos
hotéis dos passageiros em questão. Entre outras utilizações de chips RFD estão carros que chegam à seção de
pintura da linha de montagem com a cor que devem ter já especificada, estudo de migração de animais, roupas
que informam à máquina de lavar que temperatura usar e muitas mais. Alguns chips podem ser integrados com
sensores de modo que bits de baixa ordem possam conter temperatura, pressão e umidade correntes, ou outra
variável ambiental.
Chips RFD avançados também contêm armazenamento permanente. Essa capacidade levou o Banco Central
Europeu a tomar a decisão de incorporar chips RFD a notas de euros nos próximos anos. Os chips registrariam
por onde as cédulas teriam passado. sso não apenas tornaria a falsificação de notas de euros praticamente impos-
sível, mas também facilitaria muito o rastreamento e a possível invalidação remota de resgates de sequestros, do
produto de assaltos e de dinheiro lavado. Quando o dinheiro vivo não for mais anônimo, o futuro procedimento
padrão da polícia poderia ser verificar por onde o dinheiro do suspeito passou recentemente. Quem precisa
implantar chips em pessoas quando suas carteiras estão cheias deles? Mais uma vez, quando o público souber o
que os chips RFD podem fazer, é provável que surjam discussões públicas sobre o assunto.
A tecnologia usada em chips RFD está se desenvolvendo rapidamente. Os menores são passivos (não têm
alimentação interna) e podem apenas transmitir seus números exclusivos quando consultados. Todavia, os maio-
res são ativos, podem conter uma pequena bateria e um computador primitivo, e são capazes de fazer alguns
cálculos. Os smart cards usados em transações financeiras estão nessa categoria.
Chips RFD são diferentes não só por serem ativos ou passivos, mas também pela faixa de radiofrequências
à qual respondem. Os que funcionam em baixas frequências têm uma taxa de transferência de dados limitada,
mas podem ser captados a grandes distâncias por uma antena. Os que funcionam em altas frequências têm uma
taxa de transferência de dados mais alta e alcance mais reduzido. Os chips também diferem de outras formas
e estão sendo aperfeiçoados o tempo todo. A nternet está repleta de informações sobre chips RFD, e o site
<www.rfid.org> é um bom ponto de partida.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
26
1.3.4 Microcontroladores
No degrauseguinte da escada temos computadores que são embutidos em dispositivos que não são vendidos
como computadores. Os computadores embutidos, às vezes denominados microcontroladores, gerenciam os
dispositivos e manipulam a interface de usuário. São encontrados em grande variedade de aparelhos diferentes,
entre eles os seguintes. Alguns exemplos de cada categoria são dados entre parênteses.
1. Eletrodomésticos (rádio-relógio, máquina de lavar, secadora, forno de micro-ondas, alarme antifurto).
2. Aparelhos de comunicação (telefone sem fio, telefone celular, fax, pager).
3. Periféricos de computadores (impressora, scanner, modem, drive de CD-ROM).
4. Equipamentos de entretenimento (CR, DD, aparelhos de som, MP3 player, transdutores de T).
5. Aparelhos de reprodução de imagens (T, câmera digital, filmadora, lentes, fotocopiadora).
6. Equipamentos médicos (raio-x, RM – ressonância magnética, monitor cardíaco, termômetro digital).
7. Sistemas de armamentos militares (míssil teleguiado, MBC – míssil balístico intercontinental,
torpedo).
8. Dispositivos de vendas (máquina de venda automática, ATM – caixa eletrônico, caixa registradora).
9. Brinquedos (bonecas que falam, consoles de jogos, carro ou barco com radiocontrole).
Um carro de primeira linha poderia sem problema conter 50 microcontroladores que executam subsistemas,
como freios antitravamento, injeção de combustível, rádio e GPS. Um avião a jato poderia com facilidade ter 200
ou mais deles. Uma família poderia possuir facilmente centenas de computadores sem saber. Dentro de alguns
anos, quase tudo o que funciona por energia elétrica ou baterias conterá um microcontrolador. Os números de
microcontroladores vendidos todo ano deixam longe, por ordens de grandeza, todos os outros tipos de compu-
tadores, exceto os descartáveis.
Enquanto chips RFD são sistemas mínimos, minicontroladores são computadores pequenos, mas com-
pletos. Cada microcontrolador tem um processador, memória e capacidade de E/S. A capacidade de E/S inclui
detectar os botões e interruptores do aparelho e controlar suas luzes, monitores, sons e motores. Na maioria dos
casos, o software está incorporado no chip na forma de uma memória somente de leitura criada quando o micro-
controlador é fabricado. Os microcontroladores são de dois tipos gerais: propósito geral e propósito específico.
Os primeiros são apenas computadores pequenos, porém comuns; os últimos têm uma arquitetura e um conjunto
de instruções dirigido para alguma aplicação específica, como multimídia. Microcontroladores podem ter versões de
4, 8, 16 e 32 bits.
Contudo, mesmo os microcontroladores de uso geral apresentam importantes diferenças em relação aos PCs.
Primeiro, há a questão relacionada ao custo: uma empresa que compra milhões de unidades pode basear sua esco-
lha em diferenças de preços de 1 centavo por unidade. Essa restrição obriga os fabricantes de microcontroladores
a optar por arquiteturas muito mais com base em custos de fabricação do que em chips que custam centenas de
dólares. Os preços de microcontroladores variam muito dependendo de quantos bits eles têm, de quanta memó-
ria têm e de que tipo é a memória, além de outros fatores. Para dar uma ideia, um microcontrolador de 8 bits
comprado em volume grande o bastante pode custar apenas 10 centavos de dólar por unidade. Esse preço é o que
possibilita inserir um computador em um rádio-relógio de 9,95 dólares.
Segundo, quase todos os microcontroladores funcionam em tempo real. Eles recebem um estímulo e devem
dar uma resposta instantânea. Por exemplo, quando o usuário aperta um botão, em geral uma luz se acende e não
deve haver nenhuma demora entre pressionar o botão e a luz se acender. A necessidade de funcionar em tempo
real costuma causar impacto na arquitetura.
Terceiro, os sistemas embutidos muitas vezes têm limitações físicas relativas a tamanho, peso, consumo de
bateria e outras limitações elétricas e mecânicas. Os microcontroladores neles utilizados devem ser projetados
tendo essas restrições em mente.
C a p 
t u l o 1 I n t r o d u c
 a
 o 27
Uma aplicação particularmente divertida dos microcontroladores é na plataforma de controle embutida
Arduino, que foi projetada por Massimo Banzi e David Cuartielles em vrea, tália. Seu objetivo para o projeto
foi produzir uma plataforma de computação embutida completa, que custa menos que uma pizza grande com
cobertura extra, tornando-o facilmente acessível a alunos e curiosos. (Essa foi uma tarefa difícil, pois há muitas
pizzarias na tália, de modo que as pizzas são realmente baratas.) Eles alcaçaram seu objetivo muito bem: um
sistema Arduino completo custa menos de 20 dólares!
O sistema Arduino é um projeto de hardware de fonte aberta, o que significa que todos os seus detalhes são publi-
cados e gratuitos, de modo que qualquer um pode montar (e até mesmo vender) um sistema Arduino. Ele é baseado no
microprocessador RSC de 8 bits Atmel AR, e a maioria dos projetos de placa também inclui suporte básico para E/S.
A placa é programada usando uma linguagem de programação embutida, chamada Wiring, que tem embutidos todos
os balangandãs exigidos para controlar dispositivos em tempo real. O que torna a plataforma Arduino divertida de usar
é sua comunidade de desenvolvimento grande e ativa. Existem milhares de projetos publicados usando o Arduino,3
variando desde um farejador de poluentes eletrônico até uma jaqueta de ciclismo com sinais de seta, um detector de
umidade que envia e-mail quando uma planta precisa ser aguada e um avião autônomo não pilotado.
1.3.5 Computadores mo
veis e de jogos
Um nível acima estão as máquinas de videogame. São computadores normais, com recursos gráficos especiais
e capacidade de som, mas software limitado e pouca capacidade de extensão. Começaram como CPUs de baixo
valor para telefones simples e jogos de ação, como pingue-pongue em aparelhos de televisão. Com o passar dos
anos, evoluíram para sistemas muito mais poderosos, rivalizando com o desempenho de computadores pessoais
e até ultrapassando esse desempenho em certas dimensões.
Para ter uma ideia do que está dentro de um computador de jogos, considere a especificação de três produtos
populares. Primeiro, o Sony PlayStation 3. Ele contém uma CPU proprietária multicore de 3,2 GHz (denomina-
da microprocessador Cell), que é baseada na CPU RSC PowerPC da BM e sete Synergistic Processing Elements
(SPEs) de 128 bits. O PlayStation 3 também contém 512 MB de RAM, um chip gráfico Nvidia de 550 MHz fabricado
por encomenda e um player Blu-ray. Em segundo lugar, o Microsoft box 360. Ele contém uma CPU triple core
PowerPC da BM de 3,2 GHz com 512 MB de RAM, um chip gráfico AT de 500 MHz fabricado por encomenda,
um DD player e um disco rígido. Em terceiro lugar, o Samsung Galaxy Tablet (no qual este livro foi revisado). Ele
contém dois núcleos ARM de 1 GHz mais uma unidade de processamento gráfico (integrada ao sistema-em-um-
-chip Nvidia Tegra 2), 1 GB de RAM, duas câmeras, um giroscópio de 3 eixos e armazenamento com memória flash.
Embora essas máquinas não sejam tão poderosas quanto os computadores pessoais produzidos no mesmo
período de tempo, elas não ficam muito atrás e, em certos aspectos, estão à frente (por exemplo, a SPE de 128
bits do PlayStation 3 é maior do que a CPU de qualquer PC). A principal diferença entre essas máquinas de jogos
e um PC não está tanto na CPU, mas no fato de que máquinas de jogos são sistemas fechados. Os usuários não
podem expandir a CPU com cartões plug-in, embora às vezes sejam fornecidas interfaces USB ou FireWire. Além
disso, e talvez o mais importante, máquinas de jogos são cuidadosamente otimizadas para algumas poucas áreas
de aplicação: jogos de alta interatividade em 3D e saída de multimídia. Todo o resto é secundário. Essas restrições de
hardware e software, falta de extensibilidade, memórias pequenas, ausência de um monitor de alta resolução e disco
rígido pequeno (às vezes, ausente) possibilitam a construção e a venda dessas máquinas por um preço mais baixo
do que o de computadores pessoais. A despeito dessas restrições, são vendidas milhões dessas máquinas de jogos,
e a quantidade cresce o tempo todo.
Computadores móveis têm o requisito adicional de que utilizam o mínimo de energia possível para realizar
suas tarefas. Quanto menos energia eles usam, mais tempo irá durar sua bateria. Essa é uma tarefa de projeto
desafiadora, pois as plataformas móveis, como tablets e smartphones, devem reduzir seu uso de energia, mas,
ao mesmo tempo, os usuários desses dispositivos esperam capacidades de alto desempenho, como gráficos 3D,
processamento de multimídia de alta definição e jogos.
3 Para descobrir mais sobre o Arduino e começar a trabalhar com seus próprios projetos Arduino, visite <www.arduino.cc>.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
28
1.3.6 Computadores pessoais
Em seguida, chegamos aos computadores pessoais nos quais a maioria das pessoas pensa quando ouve o
termo “computador”. O termo “computadores pessoais” abrange os modelos de desktop e notebook. Costumam
vir equipados com gigabytes de memória e um disco rígido que contém terabytes de dados, um drive de CD-ROM/
DD/Blu-ray, placa de som, interface de rede, monitor de alta resolução e outros periféricos. Têm sistemas ope-
racionais elaborados, muitas opções de expansão e uma imensa faixa de softwares disponíveis.
O coração de todo computador pessoal é uma placa de circuito impresso que está no fundo ou na lateral da
caixa. Em geral, essa placa contém a CPU, memória, vários dispositivos de E/S (como um chip de som e possi-
velmente um modem), bem como interfaces para teclado, mouse, disco, rede etc., e alguns encaixes (slots) de
expansão. A Figura 1.10 mostra a foto de uma dessas placas de circuito.
Figura 1.10 A placa de circuito impresso esta
 no corac
a
o de cada computador pessoal. Essa e
 uma fotografia da placa Intel DQ67SW.
Direitos de reproduc
a
o da Intel Corporation, 2011, reproduc
a
o permitida.
Notebooks são basicamente PCs em uma embalagem menor e utilizam os mesmos componentes de
hardware, mas em tamanhos menores. Também executam os mesmos softwares que os PCs de desktop. Uma
vez que grande parte dos leitores deve conhecer computadores pessoais e notebooks muito bem, não será
preciso fazer uma apresentação introdutória mais detalhada.
Outra variante desse tema é o computador tablet, como o popular iPad. Esses dispositivos são apenas PCs
normais em um pacote menor, com um disco em estado sólido em vez de um disco rígido giratório, uma tela
sensível ao toque e uma CPU diferente do x86. Mas, do ponto de vista arquitetônico, os tablets são apenas note-
books com tamanho e forma diferentes.
C a p 
t u l o 1 I n t r o d u c
 a
 o 29
1.3.7 Servidores
Computadores pessoais reforçados ou estações de trabalho são muito usados como servidores de rede, tanto
em redes locais (em geral, dentro de uma única empresa) quanto na nternet. Os servidores vêm em configura-
ções com um único processador com múltiplos processadores, têm gigabytes de memória, centenas de gigabytes
de espaço de disco rígido e capacidade para trabalho em rede de alta velocidade. Alguns deles podem manipular
milhares de transações por segundo.
Em termos de arquitetura, contudo, um servidor com um único processador na verdade não é muito dife-
rente de um computador pessoal com um único processador. Apenas é mais rápido, maior e tem mais espaço de
disco, e possivelmente conexão de rede mais rápida. Servidores executam os mesmos sistemas operacionais que
os computadores pessoais, normalmente alguma variação de Unix ou Windows.
Clusters
Graças às melhorias quase contínuas na relação preço/desempenho dos servidores, nos últimos anos os
projetistas de sistemas começaram a conectar grandes números deles para formar clusters. Eles consistem em
sistemas padrão do tipo servidor, conectados por redes de gigabits/s e executam software especial que permite
a todas as máquinas trabalharem juntas em um único problema, muitas vezes científico ou de engenharia.
Normalmente, são o que se costuma denominar COS (Commodity Off he Shelf  mercadoria de prateleira),
computadores que qualquer um pode comprar de algum vendedor de PCs comuns. O principal acréscimo é
a capacidade de trabalho em rede de alta velocidade, mas às vezes isso também é uma placa de rede padrão
encontrada no mercado.
Grandes clusters costumam ser acomodados em salas de usuário especial ou prédios denominados data centers.
A escala desses data centers é muito grande, e vai desde um punhado de máquinas até milhares delas. Em geral,
o fator limitador é a verba disponível. Devido ao baixo preço por componente, agora departamentos individuais
podem ter essas máquinas para uso interno. Muitas pessoas utilizam os termos “cluster” e “data center” para indi-
car a mesma coisa, embora, tecnicamente, o primeiro seja a coleção de servidores e o outro seja a sala ou prédio
que os abriga.
Um uso comum para um cluster é como um servidor web. Quando um site espera milhares de solicitações
por segundo para suas páginas, a solução mais econômica normalmente é construir um data center com centenas
ou mesmo milhares de servidores. As solicitações que chegam são então espalhadas entre os servidores, para per-
mitir que sejam processadas em paralelo. Por exemplo, a Google tem data centers por todo o mundo, para atender
às solicitações de busca. O maior deles, em The Dalles, Oregon, é uma instalação com o tamanho de dois campos
de futebol americano. O local foi escolhido porque os data centers exigem grandes quantidades de energia elétrica,
e The Dalles é o local de uma represa hidrelétrica de 2 GW no rio Colúmbia, que pode fornecer essa energia. No
total, considera-se que a Google tenha mais de um milhão de servidores em seus data centers.
O negócio de computação é muito dinâmico, e as coisas mudam o tempo todo. Na década de 1960, a com-
putação era dominada por computadores mainframe gigantes (veja mais adiante), custando dezenas de milhões de
dólares, aos quais os usuários se conectavam usando terminais remotos. Esse era um modelo bastante centraliza-
do. Depois, na década de 1980, os computadores pessoais entraram em cena, milhões de pessoas os compraram,
e a computação tornou-se descentralizada.
Com o advento dos data centers, estamos começando a reviver o passado na forma de computação em
nuvens (cloud computing), que é a computação do mainframe versão 2.0. A ideia aqui é que todos terão um ou
mais dispositivos simples, incluindo PCs, notebooks, tablets e smartphones, que são basicamente interfaces do
usuário para a nuvem (ou seja, o data center), onde todas as fotos, vídeos, músicas e outros dados do usuário
são armazenados. Nesse modelo, os dados são acessíveis a partir de diferentes dispositivos em qualquer lugar e a
qualquer hora, sem que o usuário precise saber onde estão. Aqui, o data center cheio de servidores substituiu o
único grande computador centralizado, mas o paradigma retornou ao que era antes: os usuários têm terminais e
dados simples, e o poder da computação está centralizado em algum outro lugar.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
30
Quem sabe por quanto tempo esse modelo será popular? Poderia acontecer simplesmente que, em dez anos,
tantas pessoas tenham armazenado tantas músicas, fotos e vídeos na nuvem que a infraestrutura (sem fios) para
a comunicação com tudo isso se torne um gargalo. sso poderia levar a uma nova revolução: computadores pes-
soais, onde as pessoas armazenam seus próprios dados em suas próprias máquinas localmente, evitando assim o
engarrafamento no ar.
A mensagem “leve para casa” aqui é que o modelo de computação popular em determinado momento depen-
de muito da tecnologia, da economia e das aplicações disponíveis, e pode mudar quando esses fatores mudarem.
1.3.8 Mainframes
Agora chegamos aos mainframes: computadores que ocupam uma sala e nos fazem voltar à década de 1960.
Essas máquinas são as descendentes diretas dos mainframes BM 360 adquiridos há décadas. Em sua maior parte,
não são muito mais rápidas do que servidores de grande potência, mas sempre têm mais capacidade de E/S e cos-
tumam ser equipadas com vastas coleções de discos que contêm milhares de gigabytes de dados. Embora sejam
caras, é comum serem mantidas em funcionamento por causa do enorme investimento em software, dados, pro-
cedimentos operacionais e pessoal que representam. Muitas empresas acham mais barato pagar alguns milhões
de dólares de vez em quando na compra de uma nova do que sequer pensar no esforço exigido para reprogramar
todas as suas aplicações para máquinas menores.
É essa classe de computadores que levou ao infame problema do “Ano 2000”, causado pelos programadores
(principalmente COBOL) nas décadas de 1960 e 1970 porque representavam o ano com dois algarismos (dígitos)
decimais para economizar memória. Eles nunca imaginaram que seus softwares durariam três ou quatro décadas.
Embora o desastre previsto não tenha ocorrido graças ao imenso trabalho realizado para solucionar o problema,
muitas empresas repetiram o mesmo erro quando acrescentaram mais dois dígitos ao ano. O autor prevê aqui
o final da civilização que conhecemos à meia-noite de 31 de dezembro de 9999, quando 8 mil anos de velhos
programas COBOL falharem simultaneamente.
Além de sua utilização para executar software herdado de 40 anos de existência, nos últimos anos a nternet
deu um novo fôlego a esses mainframes. Ela achou um novo nicho, como poderosos servidores de nternet, por
exemplo, porque podem manipular quantidades maciças de transações de e-commerce por segundo, em particular
em empresas que exigem imensas bases de dados.
Até há pouco tempo havia outra categoria de computadores ainda mais poderosa que os mainframes: os super-
computadores. Eles tinham CPUs incrivelmente velozes, muitos gigabytes de memória principal e discos rígidos e
redes muito velozes. Eram usados para cálculos científicos e de engenharia maciços, como a simulação de galáxias
em colisão, síntese de novos medicamentos ou modelagem do fluxo de ar em torno da asa de um avião. Porém,
nos últimos anos, data centers construídos por componentes comerciais passaram a oferecer todo esse poder de
computação com preços muito mais baixos, e os verdadeiros supercomputadores agora são uma raça em extinção.
1.4 Exemplos de fam
lias de computadores
Neste livro, vamos analisar três arquiteturas de conjunto de instruções (SAs) populares: x86, ARM e AR.
A arquitetura x86 é encontrada em quase todos os sistemas de computadores pessoais (incluindo PCs Windows
e Linux e Macs) e servidores. Os computadores pessoais são de interesse porque todo leitor sem dúvida já usou
um. Os servidores são de interesse porque eles rodam todos os serviços na nternet. A arquitetura ARM domina
o mercado móvel. Por exemplo, a maioria dos smartphones e computadores tablet é baseada em processadores
ARM. Por fim, a arquitetura AR é empregada em microcontroladores de muito baixo custo, encontrados em
muitas aplicações de computação embutidas. Computadores embutidos são invisíveis aos seus usuários, mas
controlam carros, televisões, fornos de micro-ondas, máquinas de lavar e praticamente cada dispositivo elétrico
que custa mais de 50 dólares. Nesta seção, faremos uma breve introdução às três arquiteturas de conjunto de
instruções que serão usadas como exemplos no restante do livro.
C a p 
t u l o 1 I n t r o d u c
 a
 o 31
1.4.1 Introduc
a
o a
 arquitetura x86
Em 1968, Robert Noyce, inventor do circuito integrado de silício, Gordon Moore, aquele famoso pela lei de
Moore, e Arthur Rock, um capitalista de risco de São Francisco, formaram a ntel Corporation para fabricar chips
de memória. Em seu primeiro ano de operação, a ntel vendeu apenas 3 mil dólares de chips, mas desde então o
negócio melhorou (a ntel agora é o maior fabricante de chips de CPU do mundo).
No final da década de 1960, as calculadoras eram grandes máquinas eletromecânicas do tamanho de
uma moderna impressora a laser e pesavam 20 kg. Em setembro de 1969, uma empresa japonesa, a Busicom,
consultou a ntel sobre um pedido de fabricação de 12 chips sob encomenda para uma calculadora eletrônica
proposta. Ted Hoff, o engenheiro da ntel designado para esse projeto, analisou o plano e percebeu que podia
colocar uma CPU de uso geral de 4 bits em um único chip, que faria a mesma coisa e seria mais simples e tam-
bém mais barata. Assim, nascia, em 1970, a primeira CPU de um só chip com 2.300 transistores, denominada
4004 (Faggin et al., 1996).
ale a pena observar que nem a ntel nem a Busicom tinham a mínima ideia do que acabavam de fazer.
Quando a ntel decidiu que poderia valer a pena tentar usar a 4004 em outros projetos, propôs à Busicom comprar
de volta os direitos ao novo chip devolvendo os 60 mil dólares que aquela empresa pagara à ntel para desenvolvê-
-lo. A oferta foi aceita de pronto e então a ntel começou a trabalhar em uma versão de 8 bits do chip, o 8008,
lançado em 1972. A família ntel, que começou com o 4004 e o 8008, é mostrada na Figura 1.11, com a data de
introdução, taxa de clock, quantidade de transistores e memória.
Figura 1.11 Principais membros da fam
lia de CPUs da Intel. As velocidades de clock sa
o medidas em MHz (megahertz) em que 1 MHz e

1 milha
o de ciclos/s.
Chip Data MHz Trans. Memória Notas
4004 4/1971 0,108 2.300 640 Primeiro microprocessador em um chip
8008 4/1972 0,108 3.500 16 KB Primeiro microprocessador de 8 bits
8080 4/1974 2 6.000 64 KB Primeira CPU de uso geral em um chip
8086 6/1978 5–10 29.000 1 MB Primeira CPU de 16 bits em um chip
8088 6/1979 5–8 29.000 1 MB Usada no IBM PC
80286 2/1982 8–12 134.000 16 MB Com proteção de memória
80386 10/1985 16–33 275.000 4 GB Primeira CPU de 32 bits
80486 4/1989 25–100 1,2M 4 GB Memória cache de 8 KB embutida
Pentium 3/1993 60–233 3,1M 4 GB Dois pipelines; modelos posteriores tinham MMX
Pentium Pro 3/1995 150–200 5,5M 4 GB Dois níveis de cache embutidos
Pentium II 5/1997 233–450 7,5M 4 GB Pentium Pro mais instruções MMX
Pentium III 2/1999 650–1.400 9,5M 4 GB Instruções SSE para gráficos em 3D
Pentium 4 11/2000 1.300–3.800 42M 4 GB Hyperthreading; mais instruções SSE
Core Duo 1/2006 1.600–3.200 152M 2 GB Dual cores em um único substrato
Core 7/2006 1.200–3.200 410M 64 GB Arquitetura quad core de 64 bits
Core i7 1/2011 1.100–3.300 1.160M 24 GB Processador gráfico integrado
Como a empresa não esperava muita demanda pelo 8008, montou uma linha de produção de baixo volume.
Para o espanto de todos, houve um enorme interesse, portanto, a ntel passou a projetar um novo chip de CPU
que ultrapassava o limite de 16 kilobytes de memória do 8008 (imposto pelo número de pinos no chip). Esse
projeto resultou no 8080, uma CPU pequena, de uso geral, lançada em 1974. Muito parecido com o PDP-8, esse
produto tomou o setor de assalto e se tornou de imediato um item de mercado de massa. Só que, em vez de vender
milhares, como a DEC tinha vendido, a ntel vendeu milhões.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
32
Em 1978, veio o 8086, uma genuína CPU de 16 bits em um único chip. O 8086 foi projetado para ser seme-
lhante ao 8080, mas não era totalmente compatível com o 8080. O 8086 foi seguido pelo 8088, que tinha a mesma
arquitetura do 8086 e executava os mesmos programas, mas tinha um barramento de 8 bits, em vez de 16 bits, o
que o tornava mais lento e mais barato do que o 8086. Quando a BM escolheu o 8088 como a CPU do BM PC
original, esse chip rapidamente se tornou o padrão da indústria dos computadores pessoais.
Nem o 8088 nem o 8086 podiam endereçar mais do que 1 megabyte de memória. No início da década de
1980, isso se tornou um problema cada vez mais sério, por isso a ntel projetou o 80286, uma versão do 8086
compatível com os chips anteriores. O conjunto de instruções básicas era em essência o mesmo do 8086 e do
8088, mas a organização da memória era bem diferente e um pouco desajeitada por causa do requisito de compa-
tibilidade com os chips mais antigos. O 80286 foi usado no BM PC/AT e nos modelos de faixa média PS/2. Assim
como o 8088, ele foi um grande sucesso, em grande parte, porque todos o consideravam um 8088 mais veloz.
O próximo passo lógico seria uma verdadeira CPU de 32 bits em um chip, o 80386, lançado em 1985. Assim
como o 80286, esse chip era mais ou menos compatível com tudo que havia antes, até o 8080. Sendo compatível
com a família anterior, era importante para pessoas que queriam rodar velhos programas, mas um aborrecimento
para quem preferia uma arquitetura simples, limpa e moderna que não fosse prejudicada pelos erros e pela tec-
nologia do passado.
Quatro anos mais tarde, foi lançado o 80486 que, em essência, era uma versão mais veloz do 80386, que
também tinha uma unidade de ponto flutuante e 8 kilobytes de memória cache no chip. A memória cache é usada
para conter as palavras de memória mais usadas, dentro ou próximas da CPU, de modo a evitar o acesso (lento)
à memória principal. O 80486 também tinha suporte de multiprocessador embutido, o que permitia que os fabri-
cantes construíssem sistemas com várias CPUs que compartilhavam uma memória em comum.
Nesse ponto, a ntel descobriu do modo mais difícil (perdendo uma ação judicial de violação de marca regis-
trada) que números (como 80486) não podem ser considerados marca registrada, portanto, a geração seguinte
ganhou um nome: Pentium (da palavra grega para cinco, πεντε). Diferente do 80486, que tinha um só pipeline
interno, o Pentium tinha dois, o que ajudava a torná-lo duas vezes mais rápido (discutiremos pipelines em deta-
lhes no Capítulo 2).
Mais tarde, a ntel acrescentou à linha de produção as instruções especiais MMX (MultiMedia eXtension).
O propósito dessas instruções era acelerar os cálculos exigidos para processar áudio e vídeo, o que tornou desne-
cessária a adição de coprocessadores especiais de multimídia.
Quando a próxima geração apareceu, quem estava esperando por um Sexium (sex é “seis” em latim) ficou
desapontado. O nome Pentium agora era tão conhecido que o pessoal de marketing resolveu conservá-lo, e o novo
chip foi denominado Pentium Pro. A despeito da pequena mudança de nome em relação a seu antecessor, esse
processador representou uma grande ruptura com o passado. Em vez de ter dois ou mais pipelines, o Pentium Pro
tinha uma organização interna muito diferente e podia executar até cinco instruções por vez.
Outra inovação encontrada no Pentium Pro era uma memória cache de dois níveis. O chip do processador
em si tinha 8 kilobytes de memória rápida para conter instruções mais usadas e mais 8 kilobytes de memória
rápida para conter dados mais usados. Na mesma cavidade dentro do pacote Pentium Pro (mas não no chip em
si) havia uma segunda memória cache de 256 kilobytes.
Embora o Pentium Pro tivesse uma grande cache, faltavam as instruções MM (porque a ntel não conse-
guiu fabricar um chip tão grande com desempenho aceitável). Quando a tecnologia melhorou o bastante para
conseguir colocar as instruções MM e a cache no mesmo chip, o produto combinado foi lançado como Pentium
. Logo após, foram adicionadas ainda mais instruções de multimídia, denominadas SSE (Streaming SIM
Extensions), para melhorar os gráficos em 3D (Raman et al., 2000). O novo chip foi denominado Pentium ,
mas internamente era, em essência, um Pentium .
O próximo Pentium, lançado em novembro de 2000, era baseado em uma arquitetura interna diferente, mas
tinha o mesmo conjunto de instruções dos anteriores. Para celebrar esse evento, a ntel mudou de algarismos
romanos para algarismos arábicos e o denominou Pentium 4. Como sempre, o Pentium 4 era mais rápido do
que todos os seus antecessores. A versão de 3,06 GHz também introduziu uma nova e intrigante característica,
C a p 
t u l o 1 I n t r o d u c
 a
 o 33
o hyperthreading. Essa característica permitia que os programas distribuíssem seu trabalho para dois threads de
controle que o Pentium 4 podia executar em paralelo, acelerando a execução. Além disso, foi acrescentado um
novo lote de instruções SSE para acelerar ainda mais o processamento de áudio e vídeo.
Em 2006, a ntel mudou o nome da marca Pentium para Core e lançou um chip dual core, o Core 2 duo.
Quando a ntel decidiu que queria uma versão mais barata em um único núcleo do chip, ela simplesmente ven-
deu os Core 2 duos com um núcleo desabilitado, pois desperdiçar um único silício em cada chip fabricado, por
fim, era mais barato do que incorrer na enorme despesa de projetar e testar um novo chip do zero. A série Core
continuou a evoluir, com o i3, i5 e i7 sendo variantes populares para computadores com desempenho baixo,
médio e alto. Sem dúvida, haverá mais variantes. Uma foto do i7 aparece na Figura 1.12. Na realidade, existem
oito núcleos nela, mas, exceto na versão eon, somente seis estão habilitados. Essa técnica significa que um chip
com um ou dois núcleos com defeito ainda será vendido, desabilitando o(s) defeituoso(s). Cada núcleo tem suas
próprias caches de nível 1 e 2, mas há também uma cache de nível 3 (L3) compartilhada, usada por todos os
núcleos. Discutiremos as caches com mais detalhes em outro ponto deste livro.
Figura 1.12 O chip Intel Core i7-3960X. O substrato tem 21 × 21 mm e 2,27 bilho
es de transistores. Direitos da fotografia da Intel
Corporation, 2011, reproduc
a
o permitida.
Fila, Uncore
& E/S
Núcleo
Núcleo
Núcleo
Núcleo
Núcleo
Núcleo
Cache L3
compartilhado
Controlador de memória
Além das CPUs de desktop de uso geral discutidas até aqui, a ntel fabricou variantes de alguns dos chips
Pentium para mercados especiais. No início de 1998, introduziu uma nova linha de produtos chamada Celeron,
que era uma versão de baixo custo e baixo desempenho do Pentium 2, voltada para PCs inferiores. Uma vez que
o Celeron tem a mesma arquitetura Pentium 2, não o discutiremos mais neste livro. Em junho de 1998, lançou
uma versão especial do Pentium 2 para a faixa mais alta do mercado. Esse processador, denominado Xeon, tinha uma
cache maior, barramento mais rápido e melhor suporte de microprocessador, mas, fora isso, era um Pentium 2
normal, portanto, tampouco vamos discuti-lo em separado. O Pentium  também teve uma versão eon, assim
como os chips mais recentes. Nestes, um recurso do eon é a maior quantidade de núcleos.
Em 2003, a ntel lançou o Pentium M (de Mobile), um chip projetado para notebooks. Esse chip era parte da
arquitetura Centrino, cujos objetivos eram menor consumo de energia para maior tempo de vida útil das baterias,
computadores menores e mais leves, e capacidade de rede sem fio embutida usando o padrão EEE 802.11 (WiFi).
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
34
O Pentium M consumia muito menos potência e era muito menor que o Pentium 4, duas características que logo
lhe permitiriam (e aos seus sucessores) substituir a microarquitetura do Pentium 4 em produtos futuros da ntel.
Todos os chips da ntel são compatíveis com seus antecessores até os antigos 8086. Em outras palavras, um
Pentium 4 pode executar antigos programas 8086 sem modificação. A ntel sempre considerou essa compatibili-
dade como um requisito de projeto, para permitir que seus usuários não percam seus investimentos em software.
Claro que o Pentium 4 é quatro ordens de grandeza mais complexo do que o 8086, por isso pode fazer algumas
coisas que o 8086 não podia. Essas extensões escalonadas resultaram em uma arquitetura que não é tão elegante
quanto poderia ter sido se alguém tivesse dado aos arquitetos do Pentium 4 42 milhões de transistores e instru-
ções para começar tudo de novo.
É interessante notar que, embora a lei de Moore venha há tempos sendo associada com o número de bits em
uma memória, ela se aplica igualmente bem a chips de CPU. Plotando o número de transistores dados na Figura
1.8 contra as datas de lançamento de cada chip em uma escala semilogarítmica, vemos que a lei de Moore também
vale nesse caso. Esse gráfico é apresentado na Figura 1.13.
Figura 1.13 Lei de Moore para chips de CPU (Intel).
Lei de Moore
Ano de lançamento
2010
2005
2000
1995
1990
1985
1980
1975
8008
4004
8080
8086
80286
Pentium
Pentium II
Pentium III
Pentium 4
Core Duo
Core 2
Core i7
8008
80386
80486 Pentium
Pro
1970
1
10
100
1K
10K
100K
1M
10M
100M
1G
10G
Transistores
Embora a lei de Moore provavelmente continue válida por alguns anos ainda, outro problema está come-
çando a lançar uma sombra sobre ela: a dissipação de calor. Transistores menores possibilitam execução em fre-
quências de clock mais altas, o que requer a utilização de uma tensão mais alta. O consumo de energia e o calor
dissipado são proporcionais ao quadrado da tensão elétrica, portanto, execução mais rápida significa ter mais
calor para se livrar. Em 3,6 GHz, o Pentium 4 consome 115 watts de potência, o que significa que ele fica quase
tão quente quanto uma lâmpada de 100 watts. Acelerar o clock agrava o problema.
Em novembro de 2004, a ntel cancelou o Pentium 4 de 4 GHz por causa de problemas de dissipação de
calor. Grandes ventiladores podem ajudar, mas o barulho que fazem não agrada aos usuários, e a refrigeração
com água, embora usada em grandes mainframes, não é uma opção viável para equipamentos de desktop (menos
ainda para notebooks). Como consequência, a antes implacável marcha do clock pode ter terminado, ao menos até
que os engenheiros da ntel descubram como se livrar com eficiência de todo o calor gerado. Em vez disso, os
planos atuais da ntel são colocar duas ou mais CPUs em um mesmo chip, junto com uma grande cache compar-
tilhada. Por causa do modo como o consumo de energia está relacionado com a tensão elétrica e a velocidade de
clock, duas CPUs em um chip consomem muito menos energia do que uma CPU a uma velocidade duas vezes
maior. Como consequência, o ganho oferecido pela lei de Moore pode ser ainda mais explorado no futuro para
incluir mais núcleos e caches cada vez maiores embutidas em um chip, em vez de velocidades de clock cada vez
C a p 
t u l o 1 I n t r o d u c
 a
 o 35
mais altas. Tirar proveito desses multiprocessadores impõe grandes desafios aos programadores, pois, diferente
das sofisticadas microarquiteturas uniprocessador, os multiprocessadores exigem que o programador orquestre
explicitamente a execução paralela, usando threads, semáforos, memória compartilhada e outras tecnologias que
causam bugs e dores de cabeça.
1.4.2 Introduc
a
o a
 arquitetura ARM
No início da década de 1980, a empresa Acorn Computer, sediada na Grã-Bretanha, após o sucesso de seu
computador pessoal de 8 bits BBC Micro, começou a trabalhar em uma segunda máquina com a esperança de
competir com o recém-lançado BM PC. O BBC Micro era baseado no processador de 8 bits 6502, e Steve Furber
e seus colegas da Acorn acharam que o 6502 não tinha força para competir com o processador de 16 bits 8086 do
BM PC. Eles começaram a examinar as opções no mercado, e decidiram que estavam muito limitados.
nspirados pelo projeto RSC de Berkeley, em que uma pequena equipe projetou um processador incrivel-
mente rápido (que, por fim, levou à arquitetura SPARC), decidiram montar sua própria CPU para o projeto.
Eles chamaram seu projeto de Acorn RSC Machine (ou ARM, que mais tarde seria rebatizado para a máquina
Advanced RSC, quando o ARM por fim se separou da Acorn). O projeto foi concluído em 1985. Ele incluía ins-
truções e dados de 32 bits, um espaço de endereços de 26 bits, e foi fabricado pela LS Technology.
A primeira arquitetura ARM (denominada ARM2) apareceu no computador pessoal Acorn Archimedes. O
Archimedes era uma máquina muito rápida e barata para a sua época, rodando em até 2 MPS (milhões de instru-
ções por segundo) e custando apenas 899 libras esterlinas no lançamento. A máquina tornou-se muito popular
na Grã-Bretanha, rlanda, Austrália e Nova Zelândia, em especial nas escolas.
Com base no sucesso do Archimedes, a Apple fez contato com a Acorn para desenvolver um processa-
dor ARM para seu próximo projeto Apple Newton, o primeiro computador palmtop. Para focar melhor no
projeto, a equipe de arquitetura ARM saiu da Acorn para criar uma nova empresa, chamada Advanced RSC
Machines (ARM). Seu novo processador foi chamado de ARM 610, que controlou o Apple Newton quando
ele foi lançado em 1993. Diferente do projeto ARM original, esse novo processador ARM incorporava uma
cache de 4 KB, o que melhorou significativamente o desempenho do projeto. Embora o Apple Newton não
tenha sido um grande sucesso, o ARM 610 viu outras aplicações bem-sucedidas, incluindo o computador
RSC PC da Acorn.
Em meados dos anos 1990, a ARM colaborou com a Digital Equipment Corporation para desenvolver uma
versão de alta velocidade e baixa potência do ARM, voltada para aplicações móveis com escassez de energia, como
PDAs. Eles produziram o projeto StrongARM, que desde o seu lançamento causou um rebuliço no setor devido à
sua alta velocidade (233 MHz) e demandas de potência ultrabaixa (1 watt). Ele ganhou eficiência por meio de um
projeto simples e limpo, que incluía duas caches de 16 KB para instruções e dados. O StrongARM e seus suces-
sores na DEC foram moderadamente bem-sucedidos no mercado, fazendo parte de diversos PDAs, transdutores
de T, dispositivos de mídia e roteadores.
Talvez a mais venerável das arquiteturas ARM seja o projeto ARM7, lançado inicialmente pela ARM em 1994
e ainda bastante utilizado hoje em dia. O projeto incluía caches separados para instrução e dados, e também
incorporava o conjunto de instruções de 16 bits Thumb. O conjunto de instruções Thumb é uma versão reduzida
do conjunto de instruções completo de 32 bits do ARM, permitindo que os programadores codifiquem muitas
das operações mais comuns em instruções menores de 16 bits, reduzindo bastante a quantidade de memória de
programa necessária. O processador funcionava bem para uma grande variedade de aplicações embutidas, de nível
inferior a médio, como torradeiras, controle de motor e até mesmo o console de jogos portátil Gameboy Advance
da Nintendo.
Diferente de muitas empresas de computador, a ARM não fabrica qualquer microprocessador. Em vez disso,
ela cria projetos e ferramentas e bibliotecas para o desenvolvedor baseadas em ARM, licenciando-as para proje-
tistas de sistemas e fabricantes de chips. Por exemplo, a CPU usada no computador tablet Samsung Galaxy Tab
baseado no Android é um processador baseado no ARM. O Galaxy Tab contém o processador de sistema-em-um-
-chip Tegra 2, que inclui dois processadores ARM Cortex-A9 e uma unidade de processamento gráfico Nvidia
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
36
GeForce. Os núcleos do Tegra 2 foram projetados pela ARM, integrados a um projeto de sistema-em-um-chip
pela Nvidia e fabricados pela Taiwan Semiconductor Manufacturing Company (TSMC). Essa é uma colaboração
impressionante por empresas em diferentes países, na qual todas elas agregaram valor ao projeto final.
A Figura 1.14 mostra uma foto do substrato do sistema-em-um-chip Tegra 2 da Nvidia. O projeto contém
três processadores ARM: dois núcleos ARM Cortex-A9 de 1,2 GHz mais um núcleo ARM7. Os núcleos Cortex-A9
são núcleos fora de ordem de emissão dual e uma cache L2 de 1 MB, com suporte para multiprocessamento de
memória compartilhada. (Todos esses termos serão explicados em outros capítulos. Por enquanto, basta saber
que esses recursos tornam o projeto muito veloz!) O núcleo ARM7 é um núcleo ARM mais antigo e menor,
usado para configuração do sistema e gerenciamento de energia. O núcleo gráfico é um projeto com uma unidade
de processamento gráfico (GPU) GeForce de 333 MHz, otimizado para operação com baixa potência. Também
incluídos no Tegra 2 estão um codificador/decodificador de vídeo, um processador de áudio e uma interface de
saída de vídeo HDM.
Figura 1.14 O sistema Nvidia Tegra 2 em um chip. Direitos de reproduc
a
o da Nvidia Corporation, 2011, reproduc
a
o permitida.
Processador
de sinal de
imagem
Processador
de codificação
de vídeo
Processador
de áudio
Vídeo
dual
HDMI NAND
Processador de
decodificação
de vídeo
E/S
USB
Cache
CPU
A7
CPU
Cortex A9
CPU
Cortex A9
Processador
gráfico
A arquitetura ARM teve grande sucesso nos mercados de dispositivos de baixa potência, móveis e embutidos.
Em janeiro de 2011, a ARM anunciou que tinha vendido 15 bilhões de processadores desde o seu lançamento, e
indicou que as vendas estavam continuando a crescer. Embora apropriada para mercados de classe mais baixa,
a arquitetura ARM tem a capacidade de computação para funcionar em qualquer mercado, e existem indícios de
que poderá estar expandindo seus horizontes. Por exemplo, em outubro de 2011, foi anunciado um ARM de 64
bits. Também em janeiro de 2011, a Nvidia anunciou o “Projeto Denver”, um sistema-em-um-chip baseado em
ARM, sendo desenvolvido para o mercado de servidores e outros. O projeto irá incorporar vários processadores
ARM de 64 bits e mais uma GPU de uso geral (GPGPU). Os aspectos de baixa potência do projeto ajudarão a
reduzir os requisitos de resfriamento de server farms e data centers.
C a p 
t u l o 1 I n t r o d u c
 a
 o 37
1.4.3 Introduc
a
o a
 arquitetura AVR
Nosso terceiro exemplo é muito diferente do primeiro (a arquitetura x86, usada em computadores pessoais
e servidores) e do segundo (a arquitetura ARM, usada em PDAs e smartphones). É a arquitetura AR, usada
em sistemas embutidos de muito baixo nível. A história do AR começa em 1996, no Norwegian nstitute of
Technology, onde os estudantes Alf-Egil Bogen e egard Wollan projetaram uma CPU RSC de 8 bits chamada
AR. Esse nome supostamente significa “(A)lf and ()egard’s (R)SC processor” (processador RSC de Alf e
egard). Logo depois que o projeto foi concluído, a Atmel o comprou e lançou a Atmel Norway, onde os dois
arquitetos continuaram a refinar o projeto do processador AR. A Atmel lançou seu primeiro microcontrolador
AR, o AT90S1200, em 1997. Para facilitar sua adoção pelos projetistas de sistemas, eles executaram a pinagem
para que fosse idêntica à do ntel 8051, que era um dos microcontroladores mais populares da época. Hoje, há
muito interesse na arquitetura AR porque ela está no centro da plataforma muito popular de controle embutido
Arduino, de fonte aberta.
A arquitetura AR é realizada em três classes de microcontroladores, listados na Figura 1.15. A classe mais
baixa, a tinyAR, foi projetada para aplicações mais restritas quanto a superfície, potência e custo. Ela inclui uma
CPU de 8 bits, suporte digital básico para E/S e suporte para entrada analógica (por exemplo, na leitura de valores
de temperatura de um termômetro). O tinyAR é tão pequeno que seus pinos trabalham com dupla função, de
modo que podem ser reprogramados em tempo de execução para qualquer uma das funções digitais ou analógicas
admitidas pelo microcontrolador. O megaAR, que é encontrado no popular sistema embutido de fonte aberta
Arduino, também acrescenta suporte para E/S serial, clocks internos e saídas analógicas programáveis. O topo de
linha nessa ponta inferior é o microcontrolador AR MEGA, que também incorpora um acelerador para opera-
ções criptográficas e mais suporte interno para interfaces USB.
Figura 1.15 Classes de microcontrolador na fam
lia AVR.
Chip Flash EEPROM RAM Pinos Características
tinyAVR 0,5–16 KB 0–512 B 32–512 B 6–32 Pequeno, E/S digital, entrada analógica
megaAVR 8–256 KB 0,5–4 KB 0,25–8 KB 28–100 Muitos periféricos, saída analógica
AVR XMEGA 16–256 KB 1–4 KB 2–16 KB 44–100 Aceleração criptográfica, E/S USB
Junto com diversos periféricos adicionais, cada classe de processador AR inclui alguns recursos de memória
adicionais. Os microcontroladores possuem em geral três tipos de memória na placa: flash, EEPROM e RAM. A
memória flash é programável usando uma interface externa e altas voltagens, e é nela que são armazenados código
de programa e dados. A RAM flash é não volátil, de modo que, mesmo que o sistema perca a energia, a memória
flash se lembrará do que foi gravado nela. Assim como a flash, a EEPROM também é não volátil, mas, diferente
da RAM flash, ela pode ser mudada pelo programa enquanto está rodando. Esse é o armazenamento em que um
sistema embutido manteria informações de configuração do usuário, como se o seu relógio mostra as horas em
formato de 12 ou 24 horas. Por fim, a RAM é onde as variáveis do programa serão armazenadas enquanto o pro-
grama roda. Essa memória é volátil, de modo que qualquer valor armazenado aqui será perdido quando o sistema
estiver sem energia. Estudamos os tipos de RAM volátil e não volátil com detalhes no Capítulo 2.
A receita para o sucesso no negócio de microcontroladores é colocar no chip tudo o que ele possivelmente
precisará (e a pia da cozinha também, se puder ser reduzida para um milímetro quadrado) e depois colocá-lo em
um pacote barato e pequeno, com muito poucos pinos. ntegrando muitas características no microcontrolador,
ele pode funcionar para muitas aplicações, e tornando-o barato e pequeno, ele pode caber em muitos tamanhos.
Para entender melhor quantas coisas podem caber em um microcontrolador moderno, vejamos os periféricos
incluídos no Atmel ATmega168 AR:
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
38
1. Três temporizadores (dois temporizadores de 8 bits e um de 16 bits).
2. Clock de tempo real com oscilador.
3. Seis canais por modulação de largura de pulso usados, por exemplo, para controlar a intensidade da luz
ou a velocidade do motor.
4. Oito canais de conversão analógico-digital usados para ler níveis de tensão elétrica.
5. Receptor/transmissor serial universal.
6. nterface serial 2C, um padrão comum para a interface com sensores.
7. Temporizador de vigia programável, que detecta quando o sistema ficou travado.
8. Comparador analógico no chip, que compara duas tensões de entrada.
9. Detector de falha de energia, que interrompe o sistema quando a energia estiver faltando.
10. Oscilador de clock interno programável, para controlar o clock da CPU.
1.5 Unidades me
tricas
Para evitar qualquer confusão, vale a pena deixar explícito que, neste livro, assim como na ciência da computação
em geral, são usadas unidades métricas em vez das tradicionais unidades inglesas (o sistema furlong-stone-
-fortnight). Os principais prefixos métricos estão relacionados na Figura 1.16. Os prefixos costumam ser abrevia-
dos por suas primeiras letras, sendo a unidade maior do que 1 em maiúsculas (KB, MB etc.). Uma exceção (por
razões históricas) é kbps para kilobits/s. Assim, uma linha de comunicação de 1 Mbps transmite 106
bits/s e um
relógio de 100 ps bate a cada 10–10
segundos. Uma vez que ambos os prefixos, mili e micro, começam com a letra
“m”, foi preciso fazer uma escolha. Normalmente, “m” representa mili e “μ” (a letra grega mu) representa micro.
Figura 1.16 Os principais prefixos me
tricos.
Exp. Explícito Prefixo Exp. Explícito Prefixo
10–3
0,001 mili 103
1.000 kilo
10–6
0,000001 micro 106
1.000.000 mega
10–9
0,000000001 nano 109
1.000.000.000 giga
10–12
0,000000000001 pico 1012
1.000.000.000.000 tera
10–15
0,000000000000001 femto 1015
1.000.000.000.000.000 peta
10–18
0,000000000000000001 ato 1018
1.000.000.000.000.000.000 exa
10–21
0,000000000000000000001 zepto 1021
1.000.000.000.000.000.000.000 zeta
10–24
0,000000000000000000000001 iocto 1024
1.000.000.000.000.000.000.000.000 iota
Também vale a pena lembrar que, para medir tamanhos de memórias, discos, arquivos e banco de dados,
na prática comum do setor as unidades têm significados ligeiramente diferentes. Quilo, por exemplo, significa
210
(1.024) em vez de 103
(1.000), porque as memórias são sempre uma potência de dois. Assim, uma memó-
ria de 1 KB contém 1.024 bytes, e não 1.000 bytes. De modo semelhante, uma memória de 1 MB contém 220
(1.048.576) bytes, uma memória de 1 GB contém 230
(1.073.741.824) bytes e um banco de dados de 1 TB contém
240
(1.099.511.627.776) bytes.
C a p 
t u l o 1 I n t r o d u c
 a
 o 39
Todavia, uma linha de comunicação de 1 kbps pode transmitir 1.000 bits por segundo e uma LAN de 10
Mbps funciona a 10.000.000 bits/s porque essas velocidades não são potências de dois. nfelizmente, muitas pes-
soas confundem esses dois sistemas, em especial quando se tratam de tamanhos de disco.
Para evitar ambiguidade, as organizações de padrões introduziram os novos termos kibibyte para 210
bytes,
mebibyte para 220
bytes, gibibyte para 230
bytes e tebibyte para 240
bytes, mas o setor não os adotou ainda.
Achamos que, até esses novos termos serem mais utilizados, é melhor ficar com os símbolos KB, MB, GB e TB
para 210
, 220
, 230
e 240
bytes, respectivamente, e os símbolos kbps, Mbps, Gbps e Tbps para 103
, 106
, 109
e 1012
bits/s, respectivamente.
1.6 Esquema deste livro
Este livro trata de computadores multiníveis (o que inclui praticamente todos os computadores modernos)
e de como eles são organizados. Examinaremos quatro níveis com considerável detalhe – a saber, o nível lógico
digital, o da microarquitetura, o SA e o do sistema operacional da máquina. Entre alguns dos assuntos básicos
examinados estão o projeto global do nível (e por que foi projetado desse jeito), os tipos de instruções e dados
disponíveis, a organização e endereçamento da memória e o método de execução do nível. O estudo desses
tópicos e de tópicos semelhantes é denominado organização de computadores ou arquitetura de computadores.
Preocupamo-nos principalmente com os conceitos, em vez dos detalhes ou da matemática formal. Por esse
motivo, alguns dos exemplos dados serão um pouco simplificados, a fim de enfatizar as ideias centrais, e não os
detalhes.
Para dar uma ideia de como os princípios apresentados neste livro podem ser, e são, aplicados na prática,
usaremos as arquiteturas x86, ARM e AR como exemplos correntes em todo o livro. Esses três foram escolhidos
por diversas razões. Primeiro, todos são muito usados e é provável que o leitor tenha acesso a no mínimo um
deles. Segundo, cada um tem sua própria arquitetura exclusiva, o que dá uma base de comparação e incentiva
uma atitude de questionamento a respeito das possíveis alternativas. Livros que tratam apenas de uma máquina
costumam deixar o leitor com uma sensação de estar revelando um projeto de máquina absoluto, o que é absurdo
à luz das muitas concessões e decisões arbitrárias que os projetistas são obrigados a tomar. ncentivamos estudar
esses e todos os outros computadores com espírito crítico e tentar entender por que as coisas são como são e
também como poderiam ser diferentes, em vez de simplesmente aceitá-las como fatos.
É preciso que fique claro desde o início que este livro não diz respeito a programar o x86, ARM ou AR.
Essas máquinas serão usadas como ilustração quando adequado, mas não temos a pretensão de sermos completos.
Os leitores que desejarem uma introdução minuciosa a uma delas devem consultar o material publicado pelos
fabricantes.
O Capítulo 2 é uma introdução aos componentes básicos de um computador – processadores, memórias e
equipamento de E/S. Pretende oferecer uma visão geral da arquitetura de sistema e uma introdução aos capítulos
seguintes.
Cada um dos capítulos seguintes – 3, 4, 5 e 6 – trata de um único nível específico mostrado na Figura 1.2.
Nosso tratamento é de baixo para cima, porque as máquinas são tradicionalmente projetadas dessa maneira. O
projeto do nível k é determinado em grande parte pelas propriedades do nível k – 1, portanto, é difícil entender
qualquer nível, a menos que você já tenha um bom domínio do nível subjacente que o motivou. Além disso, em
termos educacionais, parece mais sensato partir dos níveis inferiores mais simples para os níveis superiores mais
complexos do que o contrário.
O Capítulo 3 é sobre o nível lógico digital, o verdadeiro hardware da máquina. Discute o que são portas
e como podem ser combinadas para formar circuitos úteis. Também introduzimos a álgebra booleana, uma
ferramenta para analisar circuitos digitais. São explicados barramentos de computador, em especial o popular
barramento PC. Nesse capítulo, são discutidos diversos exemplos do setor, incluindo os três exemplos cor-
rentes já mencionados.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
40
O Capítulo 4 apresenta a arquitetura do nível de microarquitetura e seu controle. Uma vez que a função
desse nível é interpretar instruções de nível 2 na camada acima dele, nós nos concentraremos nesse tópico e o
ilustraremos por meio de exemplos. O capítulo também contém discussões do nível de microarquitetura de algu-
mas máquinas reais.
O Capítulo 5 discute o nível SA, aquele que a maioria dos fornecedores anuncia como a linguagem de
máquina. Aqui, examinaremos em detalhes nossas máquinas de exemplo.
O Capítulo 6 abrange algumas das instruções, organização de memória e mecanismos de controle presentes
no nível do sistema operacional da máquina. Os exemplos usados aqui são o sistema operacional Windows (popu-
lar em sistemas de desktop baseados no x86) e o Unix, usado em muitos sistemas baseados no ARM.
O Capítulo 7 trata do nível de linguagem de montagem. Abrange a linguagem de montagem e o processo de
montagem. Aqui também é apresentado o tópico da ligação.
O Capítulo 8 discute computadores paralelos, um tópico de crescente importância nos dias de hoje. Alguns
desses computadores paralelos têm múltiplas CPUs que compartilham a mesma memória. Outros têm múltiplas
CPUs sem memória em comum. Alguns são supercomputadores; alguns são sistemas em um chip e outros são
clusters de computadores.
O Capítulo 9 contém uma lista comentada de leituras sugeridas, que estão na Sala irtual. Consulte
<sv.pearson.com.br>.
Problemas
1. Explique cada um dos termos seguintes com suas
próprias palavras:
a. Tradutor.
b. nterpretador.
c. Máquina virtual.
2. É concebível um compilador gerar saída para o nível
de microarquitetura em vez de para o nível SA?
Discuta prós e contras dessa proposta.
3. ocê pode imaginar qualquer computador multiní-
veis no qual o nível de dispositivo e os níveis lógi-
cos digitais não estivessem nos níveis mais baixos?
Explique.
4. Considere um computador multinível no qual todos
os níveis são diferentes. Cada nível tem instruções
que são m vezes mais poderosas do que as do nível
abaixo dele; isto é, uma instrução de nível r pode
fazer o trabalho de m instruções de nível r – 1. Se um
programa de nível 1 requer k segundos para execu-
tar, quanto tempo levariam programas equivalentes
nos níveis 2, 3 e 4 admitindo que são necessárias
n instruções de nível r para interpretar uma única
instrução de nível r + 1?
5. Algumas instruções no nível do sistema operacional
da máquina são idênticas a instruções em linguagem
SA. Elas são executadas diretamente pelo micropro-
grama ou pelo hardware, e não pelo sistema opera-
cional. À luz de sua resposta ao problema anterior,
por que você acha que isso acontece?
6. Considere um computador com interpretadores
idênticos nos níveis 1, 2 e 3. Um interpretador preci-
sa de n instruções para buscar, examinar e executar
uma instrução. Uma instrução de nível 1 demora k
nanossegundos para executar. Quanto tempo demo-
ra para executar uma instrução nos níveis 2, 3 e 4?
7. Em que sentido hardware e software são equivalen-
tes? E não equivalentes?
8. A máquina diferencial de Babbage tinha um progra-
ma fixo que não podia ser trocado. sso é em essência
a mesma coisa que um CD-ROM moderno que não
pode ser trocado? Explique sua resposta.
9. Uma das consequências da ideia de von Neumann
de armazenar um programa na memória é que esses
programas podem ser modificados, exatamente como
os dados. ocê consegue imaginar um exemplo onde
essa facilidade poderia ser útil? (Dica: pense em efe-
tuar aritmética em vetores.)
10. A relação entre desempenho do 360 modelo 75 e do
360 modelo 30 era de 50 vezes. Ainda assim, o tempo
de ciclo era só cinco vezes mais rápido. Como você
explica essa discrepância?
11. Dois projetos de sistemas são mostrados nas figuras
1.5 e 1.6. Descreva como poderia ocorrer entrada/
C a p 
t u l o 1 I n t r o d u c
 a
 o 41
saída em cada sistema. Qual deles tem potencial para
melhor desempenho global do sistema?
12. Suponha que cada um dos 300 milhões de habitantes
dos Estados Unidos consome totalmente dois pacotes
de mercadoria por dia marcados com etiquetas RFD.
Quantas dessas etiquetas teriam de ser produzidas
por ano para satisfazer à demanda? Se a etiqueta cus-
tar um centavo de dólar por unidade, qual é o custo
total das etiquetas? Dado o tamanho do PB, essa
quantia será um obstáculo à sua utilização em cada
pacote oferecido à venda?
13. Dê o nome de três eletrodomésticos ou aparelhos
candidatos a funcionar com uma CPU embutida.
14. Em certa época, um transistor instalado em um
microprocessador tinha 0,1 mícron de diâmetro.
Segundo a lei de Moore, que tamanho teria um tran-
sistor no modelo do ano seguinte?
15. Mostrou-se que a lei de Moore não se aplica apenas
à densidade de semicondutores, mas também prevê o
aumento em tamanhos de simulação (razoáveis),
e a redução nos tempos de simulação de cálculo.
Primeiro, mostre, para uma simulação de mecânica
de fluidos que gasta 4 horas para rodar em uma
máquina hoje, que só deverá gastar 1 hora para rodar
em máquinas montadas daqui a 3 anos, e apenas 15
minutos em máquinas montadas daqui a 6 anos.
Depois, mostre que, para uma simulação grande, que
possui um tempo de execução estimado de 5 anos,
ela seria completada mais cedo se esperássemos 3
anos para iniciar a simulação.
16. Em 1959, o BM 7090 poderia executar cerca de 500
mil instruções/s, tinha uma memória de 32.768 pala-
vras de 36 bits e custava US$ 3 milhões. Compare
isso com um computador atual e determine o quanto
melhor o atual é, multiplicando a razão de tamanhos
e velocidades de memória e depois dividindo isso
pela razão dos preços. Agora, veja o que os mesmos
ganhos teriam feito com o setor de aviação no mesmo
período de tempo. O Boeing 707 foi entregue às
companhias aéreas em quantidades substanciais em
1959. Sua velocidade era de 950 km/h e sua capaci-
dade era inicialmente de 180 passageiros. Ele custa
US$ 4 milhões. Quais seriam agora a velocidade,
capacidade e custo de uma aeronave se ela tivesse os
mesmos ganhos de um computador? De forma clara,
expresse suas suposições sobre velocidade, tamanho
de memória e preço.
17. Os desenvolvimentos no setor de computação geral-
mente são cíclicos. De início, os conjuntos de
instruções eram fixos, depois foram microprogra-
mados, depois surgiram máquinas RSC e eles eram
novamente fixos. Na origem, a computação era
centralizada em grandes computadores mainframe.
Liste dois desenvolvimentos que demonstram o
comportamento cíclico aqui também.
18. A questão legal que envolvia quem teria inventado o
computador foi resolvida em abril de 1973 pelo juiz
Earl Larson, que julgou uma ação judicial de violação
de patente impetrada pela Sperry Rand Corporation,
que tinha adquirido as patentes do ENAC. A posição
da Sperry Rand era de que todos os fabricantes de
computadores lhe deviam royalties porque as patentes
principais lhe pertenciam. O caso foi a julgamento em
junho de 1971 e mais de 30 mil provas foram apre-
sentadas. O arquivo do caso passou de 20 mil páginas.
Estude esse caso com mais cuidado usando a grande
quantidade de informações disponíveis na nternet e
redija um relatório que discuta seus aspectos técnicos.
O que, exatamente, Eckert e Mauchley patentearam e
por que o juiz achou que o sistema deles era baseado
no trabalho anterior de Atanasoff?
19. Escolha três pessoas que você considera serem as
mais influentes na criação do moderno hardware de
computadores e redija um curto relatório que des-
creva suas contribuições e o motivo de escolhê-las.
20. Escolha três pessoas que você considera serem as
mais influentes na criação do moderno software de
sistemas de computação e redija um curto relató-
rio que descreva suas contribuições e o motivo de
escolhê-las.
21. Escolha três pessoas que você considera serem as
mais influentes na criação dos modernos sites da web
e redija um curto relatório que descreva suas contri-
buições e o motivo de escolhê-las.
U
m computador digital consiste em um sistema interconectado de processadores, memória e dispositi-
vos de entrada/saída. Este capítulo é uma introdução a esses três componentes e a sua interconexão,
como base para o exame mais detalhado de níveis específicos nos cinco capítulos subsequentes.
Processadores, memórias e dispositivos de entrada/saída são conceitos fundamentais e estarão presentes em
todos os níveis, portanto, iniciaremos nosso estudo da arquitetura de computadores examinando todos os três,
um por vez.
2.1 Processadores
A organização de um computador simples com barramento é mostrada na Figura 2.1. A CPU (Central
Processing Unit  unidade central de processamento) é o “cérebro” do computador. Sua função é executar
programas armazenados na memória principal buscando suas instruções, examinando-as e então executando-as
uma após a outra. Os componentes são conectados por um barramento, conjunto de fios paralelos que transmi-
tem endereços, dados e sinais de controle. Barramentos podem ser externos à CPU, conectando-a à memória e
aos dispositivos de E/S, mas também podem ser internos, como veremos em breve. Os computadores modernos
possuem vários barramentos.
Organizac
a
o de sistemas
de computadores
2
Cap
tulo
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 43
Figura 2.1 A organizac
a
o de um computador simples com uma CPU e dois dispositivos de E/S.
Barramento
…
…
Unidade central de processamento (CPU)
Unidade de
controle
Unidade de
lógica e
aritmética
(ULA)
Registradores
Dispositivos de E/S
Memória
principal Disco Impressora
A CPU é composta por várias partes distintas. A unidade de controle é responsável por buscar instruções na
memória principal e determinar seu tipo. A unidade de aritmética e lógica efetua operações como adição e AND
(E) booleano para executar as instruções.
A CPU também contém uma pequena memória de alta velocidade usada para armazenar resultados tem-
porários e para algum controle de informações. Essa memória é composta de uma quantidade de registradores,
cada um deles com determinado tamanho e função. Em geral, todos os registradores têm o mesmo tamanho. Cada
um pode conter um número, até algum máximo definido pelo tamanho do registrador. Registradores podem ser
lidos e escritos em alta velocidade porque são internos à CPU.
O registrador mais importante é o Contador de Programa (PC – Program Counter), que indica a próxi-
ma instrução a ser buscada para execução. (O nome “contador de programa” é um tanto enganoso, porque
nada tem a ver com contar qualquer coisa; porém, o termo é de uso universal.) Também importante é o
Registrador de Instrução (IR – Instruction Register), que mantém a instrução que está sendo executada no
momento em questão. A maioria dos computadores também possui diversos outros registradores, alguns de
uso geral, outros de uso específico. Outros registradores são usados pelo sistema operacional para controlar
o computador.
2.1.1 Organizac
a
o da CPU
A organização interna de parte de uma típica CPU de von Neumann é mostrada na Figura 2.2 com mais
detalhes. Essa parte é denominada caminho de dados e é composta por registradores (em geral 1 a 32), da UL
(unidade lógica e aritmética) e por diversos barramentos que conectam as partes. Os registradores alimentam
dois registradores de entrada da ULA, representados por A e B na figura. Eles contêm a entrada da ULA enquan-
to ela está executando alguma operação de computação. O caminho de dados é muito importante em todas as
máquinas e nós o discutiremos minuciosamente em todo este livro.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
44
Figura 2.2 O caminho de dados de uma t
pica ma
quina de von Neumann.
A + B
A + B
A
A
B
B
Registradores
Registrador de entrada da ULA
Barramento de entrada da ULA
Registrador de saída da ULA
ULA
A ULA efetua adição, subtração e outras operações simples sobre suas entradas, produzindo assim um resul-
tado no registrador de saída, o qual pode ser armazenado em um registrador. Mais tarde, ele pode ser escrito (isto
é, armazenado) na memória, se desejado. Nem todos os projetos têm os registradores A, B e de saída. No exemplo,
ilustramos uma adição, mas as ULAs também realizam outras operações.
Grande parte das instruções pode ser dividida em uma de duas categorias: registrador-memória ou
registrador-registrador. nstruções registrador-memória permitem que palavras de memória sejam buscadas
em registradores, onde podem ser usadas como entradas de ULA em instruções subsequentes, por exemplo.
(“Palavras” são as unidades de dados movimentadas entre memória e registradores. Uma palavra pode ser
um número inteiro. Discutiremos organização de memória mais adiante neste capítulo.) Outras instruções
registrador-memória permitem que registradores voltem à memória para armazenagem.
O outro tipo de instrução é registrador-registrador. Uma instrução registrador-registrador típica busca dois
operandos nos registradores, traz os dois até os registradores de entrada da ULA, efetua alguma operação com eles
(por exemplo, adição ou AND booleano) e armazena o resultado em um dos registradores. O processo de passar
dois operandos pela ULA e armazenar o resultado é denominado ciclo do caminho de dados e é o coração da
maioria das CPUs. Até certo ponto considerável, ele define o que a máquina pode fazer. Quanto mais rápido for
o ciclo do caminho de dados, mais rápido será o funcionamento da máquina.
2.1.2 Execuc
a
o de instruc
a
o
A CPU executa cada instrução em uma série de pequenas etapas. Em termos simples, as etapas são as seguintes:
1. Trazer a próxima instrução da memória até o registrador de instrução.
2. Alterar o contador de programa para que aponte para a próxima instrução.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 45
3. Determinar o tipo de instrução trazida.
4. Se a instrução usar uma palavra na memória, determinar onde essa palavra está.
5. Trazer a palavra para dentro de um registrador da CPU, se necessário.
6. Executar a instrução.
7. oltar à etapa 1 para iniciar a execução da instrução seguinte.
Tal sequência de etapas costuma ser denominada ciclo buscar-decodificar-executar. É fundamental para a
operação de todos os computadores.
Essa descrição do modo de funcionamento de uma CPU é muito parecida com um programa escrito em
inglês. A Figura 2.3 mostra esse programa informal reescrito como um método Java (isto é, um procedimento)
denominado interpret. A máquina que está sendo interpretada tem dois registradores visíveis para programas
usuários: o contador de programa (PC), para controlar o endereço da próxima instrução a ser buscada, e o acu-
mulador (AC), para acumular resultados aritméticos. Também tem registradores internos para conter a instrução
corrente durante sua execução (instr), o tipo da instrução corrente (instr_type), o endereço do operando da ins-
trução (data_loc) e o operando corrente em si (data). Admitimos que as instruções contêm um único endereço de
memória. A localização de memória endereçada contém o operando, por exemplo, o item de dado a ser somado
ao acumulador.
Figura 2.3 Interpretador para um computador simples (escrito em Java).
public class Interp {
static int PC; // contador de programa contém endereço da próxima instr
static int AC; // o acumulador, um registrador para efetuar aritmética
static int instr; // um registrador para conter a instrução corrente
static int instr_type; // o tipo da instrução (opcode)
static int data_loc; // o endereço dos dados, ou –1 se nenhum
static int data; // mantém o operando corrente
static boolean run_bit = true; // um bit que pode ser desligado para parar a máquina
public static void interpret(int memory[ ], int starting_ address) {
// Esse procedimento interpreta programas para uma máquina simples com instruções que têm
// um operando na memória. A máquina tem um registrador AC (acumulador), usado para
// aritmética. A instrução ADD soma um inteiro na memória do AC, por exemplo.
// O interpretador continua funcionando até o bit de funcionamento ser desligado pela instrução HALT.
// O estado de um processo que roda nessa máquina consiste em memória, o
// contador de programa, bit de funcionamento e AC. Os parâmetros de entrada consistem
/ na imagem da memória e no endereço inicial.
PC = starting_address;
while (run_bit) {
instr = memory[PC]; // busca a próxima instrução e armazena em instr
PC = PC + 1; // incrementa contador de programa
instr_type = get_instr_type(instr); // determina tipo da instrução
data_loc = find_data(instr, instr_type); // localiza dados (–1 se nenhum)
if (data_loc >= 0) // se data_loc é –1, não há nenhum operando
data = memory[data_loc]; // busca os dados
execute(instr_type, data); // executa instrução
}
}
private static int get_instr_type(int addr) { ... }
private static int find_data(int instr, int type) { ... }
private static void execute(int type, int data) { ... }
}
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
46
Essa equivalência entre processadores de hardware e interpretadores tem importantes implicações para a
organização de computadores e para o projeto de sistemas de computadores. Após a especificação da lingua-
gem de máquina, L, para um novo computador, a equipe de projeto pode decidir se quer construir um processador
de hardware para executar programas em L diretamente ou se quer escrever um interpretador para interpretar
programas em L. Se a equipe preferir escrever um interpretador, também deve providenciar alguma máquina de
hardware para executá-lo. São possíveis ainda certas construções híbridas, com um pouco de execução em hard-
ware, bem como alguma interpretação de software.
Um interpretador subdivide as instruções da máquina em questão em pequenas etapas. Por conseguinte, a
máquina na qual o interpretador roda deve ser muito mais simples e menos cara do que seria um processador de
hardware para a máquina citada. Essa economia é bastante significativa se a máquina em questão tiver um grande
número de instruções e estas forem razoavelmente complicadas, com muitas opções. Basicamente, a economia
vem do fato de que o hardware está sendo substituído por software (o interpretador) e custa mais reproduzir
hardware do que software.
Os primeiros computadores tinham conjuntos de instruções pequenos, simples. Mas a procura por equipa-
mentos mais poderosos levou, entre outras coisas, a instruções individuais mais poderosas. Logo se descobriu que
instruções mais complexas muitas vezes levavam à execução mais rápida do programa mesmo que as instruções
individuais demorassem mais para ser executadas. Uma instrução de ponto flutuante é um exemplo de instru-
ção mais complexa. O suporte direto para acessar elementos matriciais é outro. Às vezes, isso era simples como
observar que as mesmas duas instruções muitas vezes ocorriam em sequência, de modo que uma única instrução
poderia fazer o trabalho de ambas.
As instruções mais complexas eram melhores porque a execução de operações individuais às vezes podia ser
sobreposta ou então executada em paralelo usando hardware diferente. No caso de computadores caros, de alto
desempenho, o custo desse hardware extra poderia ser justificado de imediato. Assim, computadores caros, de
alto desempenho, passaram a ter mais instruções do que os de custo mais baixo. Contudo, requisitos de compa-
tibilidade de instruções e o custo crescente do desenvolvimento de software criaram a necessidade de executar
instruções complexas mesmo em computadores de baixo custo, nos quais o custo era mais importante do que a
velocidade.
No final da década de 1950, a BM (na época a empresa que dominava o setor de computadores) percebeu
que prestar suporte a uma única família de máquinas, todas executando as mesmas instruções, tinha muitas
vantagens, tanto para a BM quanto para seus clientes. Então, a empresa introduziu o termo arquitetura para
descrever esse nível de compatibilidade. Uma nova família de computadores teria uma só arquitetura, mas muitas
implementações diferentes que poderiam executar o mesmo programa e seriam diferentes apenas em preço e velo-
cidade. Mas como construir um computador de baixo custo que poderia executar todas as complicadas instruções
de máquinas caras, de alto desempenho?
A resposta foi a interpretação. Essa técnica, que já tinha sido sugerida por Maurice Wilkes (1951), permitia
o projeto de computadores simples e de menor custo, mas que, mesmo assim, podiam executar um grande núme-
ro de instruções. O resultado foi a arquitetura BM System/360, uma família de computadores compatíveis que
abrangia quase duas ordens de grandeza, tanto em preço quanto em capacidade. Uma implementação de hardware
direto (isto é, não interpretado) era usada somente nos modelos mais caros.
Computadores simples com instruções interpretadas também tinham outros benefícios, entre os quais os
mais importantes eram:
1. A capacidade de corrigir em campo instruções executadas incorretamente ou até compensar deficiên-
cias de projeto no hardware básico.
2. A oportunidade de acrescentar novas instruções a um custo mínimo, mesmo após a entrega da máquina.
3. Projeto estruturado que permitia desenvolvimento, teste e documentação eficientes de instruções
complexas.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 47
À medida que o mercado explodia em grande estilo na década de 1970 e as capacidades de computação
cresciam depressa, a demanda por máquinas de baixo custo favorecia projetos de computadores que usassem
interpretadores. A capacidade de ajustar hardware e interpretador para um determinado conjunto de instruções
surgiu como um projeto muito eficiente em custo para processadores. À medida que a tecnologia subjacente dos
semicondutores avançava, as vantagens do custo compensavam as oportunidades de desempenho mais alto e as
arquiteturas baseadas em interpretador se tornaram o modo convencional de projetar computadores. Quase todos
os novos computadores projetados na década de 1970, de microcomputadores a mainframes, tinham a interpre-
tação como base.
No final da década de 1970, a utilização de processadores simples que executavam interpretadores tinha se
propagado em grande escala, exceto entre os modelos mais caros e de desempenho mais alto, como o Cray-1 e
a série Cyber da Control Data. A utilização de um interpretador eliminava as limitações de custo inerentes às
instruções complexas, de modo que os projetistas começaram a explorar instruções muito mais complexas, em
particular os modos de especificar os operandos a utilizar.
A tendência alcançou seu ponto mais alto com o A da Digital Equipment Corporation, que tinha várias
centenas de instruções e mais de 200 modos diferentes de especificar os operandos a serem usados em cada ins-
trução. nfelizmente, desde o início a arquitetura do A foi concebida para ser executada com um interpretador,
sem dar muita atenção à realização de um modelo de alto desempenho. Esse modo de pensar resultou na inclusão
de um número muito grande de instruções de valor marginal e que eram difíceis de executar diretamente. Essa
omissão mostrou ser fatal para o A e, por fim, também para a DEC (a Compaq comprou a DEC em 1998 e a
Hewlett-Packard comprou a Compaq em 2001).
Embora os primeiros microprocessadores de 8 bits fossem máquinas muito simples com conjuntos de instru-
ções muito simples, no final da década de 1970 até os microprocessadores tinham passado para projetos baseados
em interpretador. Durante esse período, um dos maiores desafios enfrentados pelos projetistas de microproces-
sadores era lidar com a crescente complexidade, possibilitada por meio de circuitos integrados. Uma importante
vantagem do método baseado em interpretador era a capacidade de projetar um processador simples e confinar
quase toda a complexidade na memória que continha o interpretador. Assim, um projeto complexo de hardware
se transformou em um projeto complexo de software.
O sucesso do Motorola 68000, que tinha um grande conjunto de instruções interpretadas, e o concomitante
fracasso do Zilog Z8000 (que tinha um conjunto de instruções tão grande quanto, mas sem um interpretador)
demonstraram as vantagens de um interpretador para levar um novo microprocessador rapidamente ao mercado.
Esse sucesso foi ainda mais surpreendente dada a vantagem de que o Zilog desfrutava (o antecessor do Z8000,
o Z80, era muito mais popular do que o antecessor do 68000, o 6800). Claro que outros fatores também contri-
buíram para isso, e um dos mais importantes foi a longa história da Motorola como fabricante de chips e a longa
história da Exxon (proprietária da Zilog) como empresa de petróleo, e não como fabricante de chips.
Outro fator a favor da interpretação naquela época foi a existência de memórias rápidas somente de leitura,
denominadas memórias de controle, para conter os interpretadores. Suponha que uma instrução interpretada
típica precisasse de 10 instruções do interpretador, denominadas microinstruções, a 100 ns cada, e duas referên-
cias à memória principal a 500 ns cada. Então, o tempo total de execução era 2.000 ns, apenas um fator de dois
pior do que o melhor que a execução direta podia conseguir. Se a memória de controle não estivesse disponível,
a instrução levaria 6.000 ns. Uma penalidade de fator seis é muito mais difícil de aceitar do que uma penalidade
de fator dois.
2.1.3 RISC versus CISC
Durante o final da década de 1970, houve experiências com instruções muito complexas que eram pos-
sibilitadas pelo interpretador. Os projetistas tentavam fechar a “lacuna semântica” entre o que as máquinas
podiam fazer e o que as linguagens de programação de alto nível demandavam. Quase ninguém pensava em
projetar máquinas mais simples, exatamente como agora não há muita pesquisa na área de projeto de plani-
lhas, redes, servidores Web etc. menos poderosos (o que talvez seja lamentável).
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
48
Um grupo que se opôs à tendência e tentou incorporar algumas das ideias de Seymour Cray em um minicom-
putador de alto desempenho foi liderado por John Cocke na BM. Esse trabalho resultou em um minicomputador
denominado 801. Embora a BM nunca tenha lançado essa máquina no mercado e os resultados tenham sido
publicados só muitos anos depois (Radin, 1982), a notícia vazou e outros começaram a investigar arquiteturas
semelhantes.
Em 1980, um grupo em Berkeley, liderado por David Patterson e Carlo Séquin, começou a projetar chips
para CPUs LS que não usavam interpretação (Patterson, 1985; Patterson e Séquin, 1982). Eles cunharam o
termo RISC para esse conceito e deram ao seu chip de CPU o nome RSC  CPU, seguido logo depois pelo RSC .
Um pouco mais tarde, em 1981, do outro lado da baía de São Francisco, em Stanford, John Hennessy projetou
e fabricou um chip um pouco diferente, que ele chamou de MIPS (Hennessy, 1984). Esses chips evoluíram para
produtos de importância comercial, o SPARC e o MPS, respectivamente.
Esses novos processadores tinham diferenças significativas em relação aos que havia no comércio naquela
época. Uma vez que essas novas CPUs não eram compatíveis com os produtos existentes, seus projetistas tinham
liberdade para escolher novos conjuntos de instruções que maximizassem o desempenho total do sistema.
Embora a ênfase inicial estivesse dirigida a instruções simples, que podiam ser executadas rapidamente, logo se
percebeu que projetar instruções que podiam ser emitidas (iniciadas) rapidamente era a chave do bom desem-
penho. Na verdade, o tempo que uma instrução demorava importava menos do que quantas delas podiam ser
iniciadas por segundo.
Na época em que o projeto desses processadores simples estava no início, a característica que chamou a aten-
ção de todos era o número relativamente pequeno de instruções disponíveis, em geral cerca de 50. Esse número
era muito menor do que as 200 a 300 de computadores como o A da DEC e os grandes mainframes da BM.
De fato, o acrônimo RSC quer dizer Reduced Instruction Set Computer (computador com conjunto de instru-
ções reduzido), em comparação com CSC, que significa Complex Instruction Set Computer (computador com
conjunto de instruções complexo), uma referência nada sutil ao A que, na época, dominava os departamentos
de ciência da computação das universidades. Hoje em dia, poucas pessoas acham que o tamanho do conjunto de
instruções seja um assunto importante, mas o nome pegou.
Encurtando a história, seguiu-se uma grande guerra santa, com os defensores do RSC atacando a ordem
estabelecida (A, ntel, grandes mainframes da BM). Eles afirmavam que o melhor modo de projetar um com-
putador era ter um pequeno número de instruções simples que executassem em um só ciclo do caminho de dados
da Figura 2.2, ou seja, buscar dois registradores, combiná-los de algum modo (por exemplo, adicionando-os ou
fazendo AND) e armazenar o resultado de volta em um registrador. O argumento desses pesquisadores era de que,
mesmo que uma máquina RSC precisasse de quatro ou cinco instruções para fazer o que uma CSC fazia com
uma só, se as instruções RSC fossem dez vezes mais rápidas (porque não eram interpretadas), o RSC vencia.
Também vale a pena destacar que, naquele tempo, a velocidade de memórias principais tinha alcançado a velo-
cidade de memórias de controle somente de leitura, de modo que a penalidade imposta pela interpretação tinha
aumentado demais, o que favorecia muito as máquinas RSC.
Era de imaginar que, dadas as vantagens de desempenho da tecnologia RSC, as máquinas RSC (como a Sun
UltraSPARC) passariam como rolo compressor sobre as máquinas CSC (tal como a Pentium da ntel) existentes
no mercado. Nada disso aconteceu. Por quê?
Antes de tudo, há a questão da compatibilidade e dos bilhões de dólares que as empresas tinham investido
em software para a linha ntel. Em segundo lugar, o que era surpreendente, a ntel conseguiu empregar as mesmas
ideias mesmo em uma arquitetura CSC. A partir do 486, as CPUs da ntel contêm um núcleo RSC que executa
as instruções mais simples (que normalmente são as mais comuns) em um único ciclo do caminho de dados,
enquanto interpreta as mais complicadas no modo CSC de sempre. O resultado disso é que as instruções comuns
são rápidas e as menos comuns são lentas. Mesmo que essa abordagem híbrida não seja tão rápida quanto um
projeto RSC puro, ela resulta em desempenho global competitivo e ainda permite que softwares antigos sejam
executados sem modificação.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 49
2.1.4 Princ
pios de projeto para computadores modernos
Agora que já se passaram mais de duas décadas desde que as primeiras máquinas RSC foram lançadas, certos
princípios de projeto passaram a ser aceitos como um bom modo de projetar computadores, dado o estado atual
da tecnologia de hardware. Se ocorrer uma importante mudança na tecnologia (por exemplo, se, de repente, um
novo processo de fabricação fizer o ciclo de memória ficar dez vezes mais rápido do que o tempo de ciclo da
CPU), todas as apostas perdem. Assim, os projetistas de máquinas devem estar sempre de olho nas mudanças
tecnológicas que possam afetar o equilíbrio entre os componentes.
Dito isso, há um conjunto de princípios de projeto, às vezes denominados princípios de projeto RISC, que
os arquitetos de CPUs de uso geral se esforçam por seguir. Limitações externas, como a exigência de compatibili-
dade com alguma arquitetura existente, muitas vezes exigem uma solução de conciliação de tempos em tempos,
mas esses princípios são metas que a maioria dos projetistas se esforça para cumprir. A seguir, discutiremos os
principais.
Todas as instruc
o
es sa
o executadas diretamente por hardware
Todas as instruções comuns são executadas diretamente pelo hardware – não são interpretadas por micro-
instruções. Eliminar um nível de interpretação dá alta velocidade à maioria das instruções. No caso de compu-
tadores que executam conjuntos de instruções CSC, as instruções mais complexas podem ser subdivididas em
partes separadas que então podem ser executadas como uma sequência de microinstruções. Essa etapa extra torna
a máquina mais lenta, porém, para instruções que ocorrem com menos frequência, isso pode ser aceitável.
Maximize a taxa de execuc
a
o das instruc
o
es
Computadores modernos recorrem a muitos truques para maximizar seu desempenho, entre os quais o prin-
cipal é tentar iniciar o máximo possível de instruções por segundo. Afinal, se você puder emitir 500 milhões de
instruções por segundo, terá construído um processador de 500 MPS, não importa quanto tempo elas realmente
levem para ser concluídas. (MIPS quer dizer Milhões de nstruções Por Segundo. O processador MPS recebeu
esse nome como um trocadilho desse acrônimo. Oficialmente, ele significa Microprocessor without Interlocked
Pipeline Stages – microprocessador sem estágios paralelos de interbloqueio.) Esse princípio sugere que o parale-
lismo pode desempenhar um importante papel na melhoria do desempenho, uma vez que emitir grandes quanti-
dades de instruções lentas em curto intervalo de tempo só é possível se várias instruções puderem ser executadas
ao mesmo tempo.
Embora as instruções sempre sejam encontradas na ordem do programa, nem sempre elas são executadas
nessa mesma ordem (porque algum recurso necessário pode estar ocupado) e não precisam terminar na ordem
do programa. É claro que, se a instrução 1 estabelece um registrador e a instrução 2 usa esse registrador, deve-se
tomar muito cuidado para garantir que a instrução 2 não leia o registrador até que ele contenha o valor correto.
Fazer isso funcionar direito requer muito controle, mas possibilita ganhos de desempenho por executar várias
instruções ao mesmo tempo.
Instruc
o
es devem ser fa
ceis de decodificar
Um limite crítico para a taxa de emissão de instruções é a decodificação de instruções individuais para
determinar quais recursos elas necessitam. Qualquer coisa que possa ajudar nesse processo é útil. sso inclui fazer
instruções regulares, de comprimento fixo, com um pequeno número de campos. Quanto menor o número de
formatos diferentes para as instruções, melhor.
Somente LOAD e STORE devem referenciar a memo
ria
Um dos modos mais simples de subdividir operações em etapas separadas é requerer que os operandos para
a maioria das instruções venham de registradores da CPU e a eles retornem. A operação de movimentação de
operandos da memória para registradores pode ser executada em instruções separadas. Uma vez que o acesso à
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
50
memória pode levar um longo tempo, e que o atraso é imprevisível, o melhor é sobrepor essas instruções a outras
se elas nada fizerem exceto movimentar operandos entre registradores e memória. Essa observação significa que
somente instruções LOAD e STORE devem referenciar a memória. Todas as outras devem operar apenas em
registradores.
Providencie muitos registradores
isto que o acesso à memória é relativamente lento, é preciso providenciar muitos registradores (no mínimo,
32) de modo que, assim que uma palavra for buscada, ela possa ser mantida em um registrador até não ser mais
necessária. Esgotar os registradores e ter de descarregá-los de volta à memória só para ter de recarregá-los mais
tarde é indesejável e deve ser evitado o máximo possível. A melhor maneira de conseguir isso é ter um número
suficiente de registradores.
2.1.5 Paralelismo no n
vel de instruc
a
o
Arquitetos de computadores estão sempre se esforçando para melhorar o desempenho das máquinas que
projetam. Fazer os chips funcionarem com maior rapidez aumentando suas velocidades de clock é um modo,
mas, para cada novo projeto, há um limite para o que é possível fazer por força bruta naquele momento da
História. Por conseguinte, grande parte dos arquitetos de computadores busca o paralelismo (fazer duas ou
mais coisas ao mesmo tempo) como um meio de conseguir desempenho ainda melhor para dada velocidade
de clock.
O paralelismo tem duas formas gerais, a saber, no nível de instrução e no nível de processador. Na primeira,
o paralelismo é explorado dentro de instruções individuais para obter da máquina mais instruções por segundo.
Na última, várias CPUs trabalham juntas no mesmo problema. Cada abordagem tem seus próprios méritos. Nesta
seção, vamos estudar o paralelismo no nível de instrução; na seção seguinte, estudaremos o paralelismo no nível
de processador.
Pipelining (paralelismo)
Há anos sabe-se que o processo de buscar instruções na memória é um grande gargalo na velocidade de
execução da instrução. Para amenizar esse problema, os computadores, desde o BM Stretch (1959), tinham a
capacidade de buscar instruções na memória antecipadamente, de maneira que estivessem presentes quando
necessárias. Essas instruções eram armazenadas em um conjunto de registradores denominado buffer de busca
antecipada (ou prefetch buffer). Desse modo, quando necessária, uma instrução podia ser apanhada no buffer de
busca antecipada, em vez de esperar pela conclusão de uma leitura da memória.
Na verdade, a busca antecipada divide a execução da instrução em duas partes: a busca e a execução
propriamente dita. O conceito de pipeline (paralelismo, canalização) amplia muito mais essa estratégia. Em
vez de dividir a execução da instrução em apenas duas partes, muitas vezes ela é dividida em muitas partes
(uma dúzia ou mais), cada uma manipulada por uma parte dedicada do hardware, e todas elas podem exe-
cutar em paralelo.
A Figura 2.4(a) ilustra um pipeline com cinco unidades, também denominadas estágios. O estágio 1 busca
a instrução na memória e a coloca em um buffer até que ela seja necessária. O estágio 2 decodifica a instrução,
determina seu tipo e de quais operandos ela necessita. O estágio 3 localiza e busca os operandos, seja nos regis-
tradores, seja na memória. O estágio 4 é que realiza o trabalho de executar a instrução, normalmente fazendo os
operandos passarem pelo caminho de dados da Figura 2.2. Por fim, o estágio 5 escreve o resultado de volta no
registrador adequado.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 51
Figura 2.4 (a) Pipeline de cinco esta
gios. (b) Estado de cada esta
gio como uma func
a
o do tempo. Sa
o ilustrados nove ciclos de clock.
(a)
(b)
S1:
S2:
S3:
S4:
S5:
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8
1 2 3 4 5 6 7
1 2 3 4 5 6
1 2 3 4 5
1 2 3 4 5 6 7 8 9
…
S1 S2 S3 S4 S5
Unidade
de busca de
instrução
Unidade de
decodificação
de instrução
Unidade de
busca de
operando
Unidade de
execução
de instrução
Unidade de
gravação
Tempo
Na Figura 2.4(b), vemos como o pipeline funciona em função do tempo. Durante o ciclo de clock 1, o
estágio S1 está trabalhando na instrução 1, buscando-a na memória. Durante o ciclo 2, o estágio S2 decodifica
a instrução 1, enquanto o estágio S1 busca a instrução 2. Durante o ciclo 3, o estágio S3 busca os operandos
para a instrução 1, o estágio S2 decodifica a instrução 2 e o estágio S1 busca a terceira instrução. Durante o
ciclo 4, o estágio S4 executa a instrução 1, S3 busca os operandos para a instrução 2, S2 decodifica a instrução
3 e S1 busca a instrução 4. Por fim, durante o ciclo 5, S5 escreve (grava) o resultado da instrução 1 de volta ao
registrador, enquanto os outros estágios trabalham nas instruções seguintes.
amos considerar uma analogia para esclarecer melhor o conceito de pipelining. magine uma fábrica de
bolos na qual a operação de produção dos bolos e a operação da embalagem para expedição são separadas.
Suponha que o departamento de expedição tenha uma longa esteira transportadora ao longo da qual trabalham
cinco funcionários (unidades de processamento). A cada 10 segundos (o ciclo de clock), o funcionário 1 coloca
uma embalagem de bolo vazia na esteira. A caixa é transportada até o funcionário 2, que coloca um bolo dentro
dela. Um pouco mais tarde, a caixa chega à estação do funcionário 3, onde é fechada e selada. Em seguida, prosse-
gue até o funcionário 4, que coloca uma etiqueta na embalagem. Por fim, o funcionário 5 retira a caixa da esteira e
a coloca em um grande contêiner que mais tarde será despachado para um supermercado. Em termos gerais, esse
é o modo como um pipeline de computador também funciona: cada instrução (bolo) passa por diversos estágios
de processamento antes de aparecer já concluída na extremidade final.
oltando ao nosso pipeline da Figura 2.4, suponha que o tempo de ciclo dessa máquina seja 2 ns. Sendo
assim, uma instrução leva 10 ns para percorrer todo o caminho do pipeline de cinco estágios. À primeira vista,
como uma instrução demora 10 ns, parece que a máquina poderia funcionar em 100 MPS, mas, na verdade, ela
funciona muito melhor do que isso. A cada ciclo de clock (2 ns), uma nova instrução é concluída, portanto, a
velocidade real de processamento é 500 MPS, e não 100 MPS.
O pipelining permite um compromisso entre latência (o tempo que demora para executar uma instrução) e lar-
gura de banda de processador (quantos MPS a CPU tem). Com um tempo de ciclo de T ns e n estágios no pipeline,
a latência é nT ns porque cada instrução passa por n estágios, cada um dos quais demora T ns.
isto que uma instrução é concluída a cada ciclo de clock e que há 109
/T ciclos de clock por segundo, o
número de instruções executadas por segundo é 109
/T. Por exemplo, se T = 2 ns, 500 milhões de instruções são
executadas a cada segundo. Para obter o número de MPS, temos de dividir a taxa de execução de instrução por
1 milhão para obter (109
/T)/106
= 1.000/T MPS. Em teoria, poderíamos medir taxas de execução de instrução em
BPS em vez de MPS, mas ninguém faz isso, portanto, nós também não o faremos.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
52
Arquiteturas superescalares
Se um pipeline é bom, então certamente dois pipelines são ainda melhores. Um projeto possível para
uma CPU com dois pipelines, com base na Figura 2.4, é mostrado na Figura 2.5. Nesse caso, uma única
unidade de busca de instruções busca pares de instruções ao mesmo tempo e coloca cada uma delas em
seu próprio pipeline, completo com sua própria ULA para operação paralela. Para poder executar em para-
lelo, as duas instruções não devem ter conflito de utilização de recursos (por exemplo, registradores) e
nenhuma deve depender do resultado da outra. Assim como em um pipeline único, ou o compilador deve
garantir que essa situação aconteça (isto é, o hardware não verifica e dá resultados incorretos se as ins-
truções não forem compatíveis), ou os conflitos deverão ser detectados e eliminados durante a execução
usando hardware extra.
Figura 2.5 Pipelines duplos de cinco esta
gios com uma unidade de busca de instruc
a
o em comum.
S1 S2 S3 S4 S5
Unidade de
busca de
instrução
Unidade de
decodificação
de instrução
Unidade de
busca de
operando
Unidade de
execução de
instrução
Unidade de
gravação
Unidade de
decodificação
de instrução
Unidade de
busca de
operando
Unidade de
execução de
instrução
Unidade de
gravação
Embora pipelines, simples ou duplos, sejam usados em sua maioria em máquinas RSC (o 386 e seus
antecessores não tinham nenhum), a partir do 486 a ntel começou a acrescentar pipelines de dados em
suas CPUs. O 486 tinha um pipeline e o Pentium original tinha pipelines de cinco estágios mais ou menos
como os da Figura 2.5, embora a exata divisão do trabalho entre os estágios 2 e 3 (denominados decode-1 e
decode-2) era ligeiramente diferente do que em nosso exemplo. O pipeline principal, denominado pipeline u,
podia executar uma instrução Pentium qualquer. O segundo, denominado pipeline v, podia executar apenas
instruções com números inteiros (e também uma instrução simples de ponto flutuante – FCH).
Regras fixas determinavam se um par de instruções era compatível e, portanto, se elas podiam ser exe-
cutadas em paralelo. Se as instruções em um par não fossem simples o suficiente ou se fossem incompatíveis,
somente a primeira era executada (no pipeline u). A segunda era retida para fazer par com a instrução seguin-
te. nstruções eram sempre executadas em ordem. Assim, os compiladores específicos para Pentium que
produziam pares compatíveis podiam produzir programas de execução mais rápidos do que compiladores
mais antigos. Medições mostraram que um código de execução Pentium otimizado para ele era exatamente
duas vezes mais rápido para programas de inteiros do que um 486 que executava à mesma velocidade de
clock (Pountain, 1993). Esse ganho podia ser atribuído inteiramente ao segundo pipeline.
Passar para quatro pipelines era concebível, mas exigiria duplicar muito hardware (cientistas da compu-
tação, ao contrário de especialistas em folclore, não acreditam no número três). Em vez disso, uma aborda-
gem diferente é utilizada em CPUs de topo de linha. A ideia básica é ter apenas um único pipeline, mas lhe
dar várias unidades funcionais, conforme mostra a Figura 2.6. Por exemplo, a arquitetura ntel Core tem uma
estrutura semelhante à dessa figura, que será discutida no Capítulo 4. O termo arquitetura superescalar foi
cunhado para essa técnica em 1987 (Agerwala e Cocke, 1987). Entretanto, suas raízes remontam a mais de
40 anos, ao computador CDC 6600. O 6600 buscava uma instrução a cada 100 ns e a passava para uma das
10 unidades funcionais para execução paralela enquanto a CPU saía em busca da próxima instrução.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 53
Figura 2.6 Processador superescalar com cinco unidades funcionais.
S2 S3 S5
S1
S4
Unidade
de busca
de instrução
Unidade de
decodificação
de instrução
Unidade
de busca
de operando
ULA
ULA
LOAD
STORE
Ponto
flutuante
Unidade de
gravação
A definição de “superescalar” evoluiu um pouco ao longo do tempo. Agora, ela é usada para descrever
processadores que emitem múltiplas instruções – frequentemente, quatro ou seis – em um único ciclo de
clock. Claro que uma CPU superescalar deve ter várias unidades funcionais para passar todas essas instru-
ções. Uma vez que, em geral, os processadores superescalares têm um só pipeline, tendem a ser parecidos
com os da Figura 2.6.
Usando essa definição, o 6600 não era tecnicamente um computador superescalar, pois emitia apenas uma
instrução por ciclo. Todavia, o efeito era quase o mesmo: instruções eram terminadas em uma taxa muito mais alta
do que podiam ser executadas. A diferença conceitual entre uma CPU com um clock de 100 ns que executa uma
instrução a cada ciclo para um grupo de unidades funcionais e uma CPU com um clock de 400 ns que executa
quatro instruções por ciclo para o mesmo grupo de unidades funcionais é muito pequena. Em ambos os casos,
a ideia fundamental é que a taxa final é muito mais alta do que a taxa de execução, sendo a carga de trabalho
distribuída entre um conjunto de unidades funcionais.
mplícito à ideia de um processador superescalar é que o estágio S3 pode emitir instruções com rapidez
muito maior do que o estágio S4 é capaz de executá-las. Se o estágio S3 executasse uma instrução a cada 10 ns
e todas as unidades funcionais pudessem realizar seu trabalho em 10 ns, nunca mais do que uma unidade
estaria ocupada ao mesmo tempo, o que negaria todo o raciocínio. Na verdade, grande parte das unidades fun-
cionais no estágio 4 leva um tempo bem maior do que um ciclo de clock para executar, decerto as que acessam
memória ou efetuam aritmética de ponto flutuante. Como pode ser visto na figura, é possível ter várias ULAs
no estágio S4.
2.1.6 Paralelismo no n
vel do processador
A demanda por computadores cada vez mais rápidos parece ser insaciável. Astrônomos querem simular o
que aconteceu no primeiro microssegundo após o Big Bang, economistas querem modelar a economia mundial e
adolescentes querem se divertir com jogos multimídia em 3D com seus amigos virtuais pela nternet. Embora as
CPUs estejam cada vez mais rápidas, haverá um momento em que elas terão problemas com a velocidade da luz,
que provavelmente permanecerá a 20 cm/nanossegundo em fio de cobre ou fibra ótica, não importando o grau
de inteligência dos engenheiros da ntel. Chips mais velozes também produzem mais calor, cuja dissipação é um
problema. De fato, a dificuldade para se livrar do calor produzido é o principal motivo pelo qual as velocidades
de clock da CPU se estagnaram na última década.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
54
Paralelismo no nível de instrução ajuda um pouco, mas pipelining e operação superescalar raramente rendem
mais do que um fator de cinco ou dez. Para obter ganhos de 50, 100 ou mais, a única maneira é projetar compu-
tadores com várias CPUs; portanto, agora vamos ver como alguns deles são organizados.
Computadores paralelos
Um número substancial de problemas em domínios de cálculo como ciências físicas, engenharia e gráficos de
computador envolve laços e matrizes, ou então tem estrutura de alta regularidade. Muitas vezes, os mesmos cálcu-
los são efetuados em muitos conjuntos diferentes de dados ao mesmo tempo. A regularidade e a estrutura desses
programas os tornam alvos especialmente fáceis para aceleração por meio de execução paralela. Há dois métodos
que têm sido usados para executar esses programas altamente regulares de modo rápido e eficaz: processadores
SMD e processadores vetoriais. Embora esses dois esquemas guardem notáveis semelhanças na maioria de seus
aspectos, por ironia o primeiro deles é considerado um computador paralelo, enquanto o segundo é considerado
uma extensão de um processador único.
Computadores paralelos de dados encontraram muitas aplicações bem-sucedidas como consequência de
sua notável eficiência. Eles são capazes de produzir poder de computação significativo com menos transis-
tores do que os métodos alternativos. Gordon Moore (da lei de Moore) observou que o silício custa cerca de 1 bilhão
de dólares por acre (4.047 m²). Assim, quanto mais poder de computação puder ser espremido desse acre de
silício, mais dinheiro uma empresa de computador poderá obter vendendo silício. Os processadores paralelos
de dados são um dos meios mais eficientes de espremer o desempenho do silício. Como todos os processado-
res estão rodando a mesma instrução, o sistema só precisa de um “cérebro” controlando o computador. Em
consequência, o processador só precisa de um estágio de busca, um estágio de decodificação e um conjunto
de lógica de controle. Essa é uma enorme economia no silício, que dá aos computadores paralelos uma grande
vantagem sobre outros processadores, desde que o software que eles estejam rodando seja altamente regular,
com bastante paralelismo.
Um processador SIM (Single Instruction-stream Multiple ata-stream, ou fluxo único de instruções,
fluxo múltiplo de dados) consiste em um grande número de processadores idênticos que efetuam a mesma
sequência de instruções sobre diferentes conjuntos de dados. O primeiro processador SMD do mundo foi o
LLAC  da Universidade de llinois (Bouknight et al., 1972). O projeto original do LLAC  consistia em qua-
tro quadrantes, cada um deles com uma grade quadrada de 8 × 8 elementos de processador/memória. Uma única
unidade de controle por quadrante transmitia uma única instrução a todos os processadores, que era executada
no mesmo passo por todos eles, cada um usando seus próprios dados de sua própria memória. Por causa de um
excesso de custo, somente um quadrante de 50 megaflops (milhões de operações de ponto flutuante por segun-
do) foi construído; se a construção da máquina inteira de 1 gigaflop tivesse sido concluída, ela teria duplicado a
capacidade de computação do mundo inteiro.
As modernas unidades de processamento de gráficos (GPUs) contam bastante com o processamento SMD
para fornecer poder computacional maciço com poucos transistores. O processamento de gráficos foi apropriado
para processadores SMD porque a maioria dos algoritmos é altamente regular, com operações repetidas sobre
pixels, vértices, texturas e arestas. A Figura 2.7 mostra o processador SMD no núcleo da GPU Fermi da Nvidia.
A GPU Fermi contém até 16 multiprocessadores de fluxo (com memória compartilhada – SM) SMD, com cada
multiprocessador contendo 32 processadores SMD. A cada ciclo, o escalonador seleciona dois threads para
executar no processador SMD. A próxima instrução de cada thread é então executada em até 16 processadores
SMD, embora possivelmente menos se não houver paralelismo de dados suficiente. Se cada thread for capaz de
realizar 16 operações por ciclo, um núcleo GPU Fermi totalmente carregado com 32 multiprocessadores realizará
incríveis 512 operações por ciclo. Esse é um feito impressionante, considerando que uma CPU quad-core de uso
geral com tamanho semelhante lutaria para conseguir 1/32 desse processamento.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 55
Figura 2.7 O nu
cleo SIMD da unidade de processamento de gra
ficos Fermi.
Cache de instruções
Despacho de instruções Despacho de instruções
Arquivo de registradores
Operando Operando
Unidade
de PF
ULA
Registrador de resultado
Núcleo
Rede de interconexão
Memória compartilhada
Núcleo
Núcleo Núcleo Núcleo Núcleo
Núcleo Núcleo Núcleo Núcleo
Núcleo Núcleo Núcleo Núcleo
Núcleo Núcleo Núcleo Núcleo
Núcleo Núcleo Núcleo Núcleo
Núcleo Núcleo Núcleo Núcleo
Núcleo Núcleo Núcleo Núcleo
Núcleo Núcleo Núcleo Núcleo
Para um programador, um processador vetorial se parece muito com um processador SMD. Assim como
um processador SMD, ele é muito eficiente para executar uma sequência de operações em pares de elementos
de dados. Porém, diferente de um processador SMD, todas as operações de adição são efetuadas em uma única
unidade funcional, de alto grau de paralelismo. A Cray Research, empresa fundada por Seymour Cray, produziu
muitos processadores vetoriais, começando com o Cray-1 em 1974 e continuando até os modelos atuais.
Processadores SMD, bem como processadores vetoriais, trabalham com matrizes de dados. Ambos execu-
tam instruções únicas que, por exemplo, somam os elementos aos pares para dois vetores. Porém, enquanto o
processador SMD faz isso com tantos somadores quantos forem os elementos do vetor, o processador vetorial
tem o conceito de um registrador vetorial, que consiste em um conjunto de registradores convencionais que
podem ser carregados com base na memória em uma única instrução que, na verdade, os carrega serialmente
com base na memória. Então, uma instrução de adição vetorial efetua as adições a partir dos elementos de dois
desses vetores, alimentando-os em um somador com paralelismo (pipelined) com base em dois registradores
vetoriais. O resultado do somador é outro vetor, que pode ser armazenado em um registrador vetorial ou usado
diretamente como um operando para outra operação vetorial. As instruções SSE (Streaming SMD Extension)
disponíveis na arquitetura ntel Core utilizam esse modelo de execução para agilizar o cálculo altamente
regular, como multimídia e software científico. Nesse aspecto particular, o LLAC  é um dos ancestrais da
arquitetura ntel Core.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
56
Multiprocessadores
Os elementos de processamento em um processador SMD não são CPUs independentes, uma vez que há
uma só unidade de controle compartilhada por todos eles. Nosso primeiro sistema paralelo com CPUs totalmen-
te desenvolvidas é o multiprocessador, um sistema com mais de uma CPU que compartilha uma memória em
comum, como um grupo de pessoas que, dentro de uma sala de aula, compartilha um quadro em comum. Uma
vez que cada CPU pode ler ou escrever em qualquer parte da memória, elas devem se coordenar (em software)
para evitar que uma atrapalhe a outra. Quando duas ou mais CPUs têm a capacidade de interagir de perto, como
é o caso dos multiprocessadores, diz-se que elas são fortemente acopladas.
Há vários esquemas de implementação possíveis. O mais simples é um barramento único com várias CPUs e
uma memória, todas ligadas nele. Um diagrama desse tipo de multiprocessador de barramento único é mostrado
na Figura 2.8(a).
Figura 2.8 (a) Multiprocessador de barramento u
nico. (b) Multicomputador com memo
rias locais.
(a) (b)
CPU CPU CPU CPU CPU CPU CPU CPU
Memórias locais
Memória
compartilhada
Memória
compartilhada
Barramento Barramento
Não é preciso muita imaginação para perceber que, com um grande número de processadores velozes ten-
tando acessar a memória pelo mesmo barramento, surgirão conflitos. Projetistas de multiprocessadores apresen-
taram vários esquemas para reduzir essa disputa e melhorar o desempenho. Um desses esquemas, mostrado na
Figura 2.8(b), dá a cada processador um pouco de memória local só dele, que não é acessível para os outros. Essa
memória pode ser usada para o código de programa e para os itens de dados que não precisam ser compartilhados.
O acesso a essa memória privada não usa o barramento principal, o que reduz muito o tráfego no barramento.
Outros esquemas (por exemplo, caching – veja mais adiante) também são possíveis.
Multiprocessadores têm a vantagem sobre outros tipos de computadores paralelos: é fácil trabalhar com o
modelo de programação de uma única memória compartilhada. Por exemplo, imagine um programa que procura
células cancerosas na foto de algum tecido, tirada por um microscópio. A fotografia digitalizada poderia ser man-
tida na memória em comum, sendo cada processador designado para caçar essas células em alguma região. Uma
vez que cada processador tem acesso a toda a memória, estudar a célula que começa em sua região designada mas
atravessa a fronteira da próxima região não é problema.
Multicomputadores
Embora seja um tanto fácil construir multiprocessadores com um número modesto de processadores
(≤ 256), construir grandes é surpreendentemente difícil. A dificuldade está em conectar todos os processado-
res à memória. Para evitar esses problemas, muitos projetistas simplesmente abandonaram a ideia de ter uma
memória compartilhada e passaram a construir sistemas que consistissem em grandes números de computa-
dores interconectados, cada um com sua própria memória privada, mas nenhuma em comum. Esses sistemas
são denominados multicomputadores. Costuma-se dizer que as CPUs de um multicomputador são fracamente
acopladas, para contrastá-las com as CPUs fortemente acopladas de um multiprocessador.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 57
As CPUs de um multicomputador se comunicam enviando mensagens umas às outras, mais ou menos como
enviar e-mails, porém, com muito mais rapidez. Em sistemas grandes, não é prático ter cada computador liga-
do a todos os outros, portanto, são usadas topologias como malhas 2D e 3D, árvores e anéis. O resultado é que
mensagens de um computador para outro muitas vezes passam por um ou mais computadores ou comutadores
(chaves) intermediários para ir da fonte até o destino. Não obstante, podem-se conseguir tempos de transmissão
de mensagem da ordem de alguns microssegundos sem muita dificuldade. Multicomputadores com mais de 250
mil CPUs, como o Blue Gene/P da BM, já foram construídos.
Uma vez que multiprocessadores são mais fáceis de programar e multicomputadores são mais fáceis de cons-
truir, há muita pesquisa sobre projetos de sistemas híbridos que combinam as boas propriedades de cada um.
Esses computadores tentam apresentar a ilusão de memória compartilhada sem bancar a despesa de realmente
construí-la. Falaremos mais de multiprocessadores e multicomputadores no Capítulo 8.
2.2 Memo
ria prima
ria
A memória é a parte do computador onde são armazenados programas e dados. Alguns cientistas da com-
putação (em especial, os britânicos) usam o termo armazém ou armazenagem em vez de memória, se bem que
o termo “armazenagem” está sendo usado cada vez mais para a armazenagem em disco. Sem uma memória da
qual os processadores possam ler e na qual possam gravar, ou escrever, informações, não haveria computadores
digitais com programas armazenados.
2.2.1 Bits
A unidade básica de memória é dígito binário, denominado bit. Um bit pode conter um 0 ou um 1. É a
unidade mais simples possível. (Um dispositivo capaz de armazenar somente zeros dificilmente poderia formar a
base de um sistema de memória; são necessários pelo menos dois valores.)
As pessoas costumam dizer que computadores usam aritmética binária porque ela é “eficiente”. O que elas
querem dizer, embora quase nunca percebam, é que informações digitais podem ser armazenadas distinguindo
entre valores diferentes de alguma quantidade física contínua, tal como tensão ou corrente elétrica. Quanto maior
for o número de valores que precisam ser distinguidos, menores serão as separações entre valores adjacentes, e
menos confiável será a memória. O sistema numérico binário requer a distinção entre apenas dois valores. Por
conseguinte, é o método mais confiável para codificar informações digitais. Se você não estiver familiarizado com
números binários, consulte o Apêndice A.
Há empresas que anunciam que seus computadores têm aritmética decimal, bem como binária, como é o
caso da BM e seus grandes mainframes. Essa façanha é realizada usando-se 4 bits para armazenar um dígito
decimal que utiliza um código denominado BC (Binary Coded ecimal  decimal codificado em binário).
Quatro bits oferecem 16 combinações, usadas para os 10 dígitos de 0 a 9, mas seis combinações não são usa-
das. O número 1.944 é mostrado a seguir codificado em formato decimal e em formato binário puro, usando
16 bits em cada exemplo:
decimal: 0001 1001 0100 0100 binário: 0000011110011000
Dezesseis bits no formato decimal podem armazenar os números de 0 a 9999, dando somente 10 mil com-
binações, ao passo que um número binário puro de 16 bits pode armazenar 65.536 combinações diferentes. Por
essa razão, as pessoas dizem que o binário é mais eficiente.
No entanto, considere o que aconteceria se algum jovem e brilhante engenheiro elétrico inventasse um dis-
positivo eletrônico de alta confiabilidade que pudesse armazenar diretamente os dígitos de 0 a 9 dividindo a região
de 0 a 10 volts em 10 intervalos. Quatro desses dispositivos poderiam armazenar qualquer número decimal de 0 a
9999. Quatro desses dispositivos dariam 10 mil combinações. Eles também poderiam ser usados para armazenar
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
58
números binários usando somente 0 e 1, caso em que quatro deles só poderiam armazenar 16 combinações. Com
tais dispositivos, o sistema decimal é obviamente mais eficiente.
2.2.2 Enderec
os de memo
ria
Memórias consistem em uma quantidade de células (ou locais), cada uma das quais podendo armazenar uma
informação. Cada célula tem um número, denominado seu endereço, pelo qual os programas podem se referir a
ela. Se a memória tiver n células, elas terão endereços de 0 a n – 1. Todas as células em uma memória contêm o
mesmo número de bits. Se uma célula consistir em k bits, ela pode conter quaisquer das 2k
diferentes combina-
ções de bits. A Figura 2.9 mostra três organizações diferentes para uma memória de 96 bits. Note que as células
adjacentes têm endereços consecutivos (por definição).
Figura 2.9 Tre
s maneiras de organizar uma memo
ria de 96 bits.
0
(c)
1
2
3
4
5
6
7
8
9
10
11
0
1
2
3
4
5
6
7
0
1
2
3
4
5
16 bits
(b)
12 bits
(a)
8 bits
Endereço Endereço 1 célula Endereço
Computadores que usam o sistema de números binários (incluindo notação octal ou hexadecimal para
números binários) expressam endereços de memória como números binários. Se um endereço tiver m bits, o
número máximo de células endereçáveis é 2m
. Por exemplo, um endereço usado para referenciar a memória da
Figura 2.9(a) precisa de no mínimo 4 bits para expressar todos os números de 0 a 11. Contudo, um endereço
de 3 bits é suficiente para as figuras 2.9(b) e (c). O número de bits no endereço determina o número máximo
de células diretamente endereçáveis na memória e é independente do número de bits por célula. Uma memória
com 212
células de 8 bits cada e uma memória com 212
células de 64 bits cada precisam de endereços de 12 bits.
A Figura 2.10 mostra o número de bits por célula para alguns computadores que já foram vendidos comer-
cialmente.
A significância da célula é que ela é a menor unidade endereçável. Há poucos anos, praticamente todos os fabri-
cantes de computadores padronizaram células de 8 bits, que é denominada um byte. O termo octeto também é usado.
Bytes são agrupados em palavras. Um computador com uma palavra de 32 bits tem 4 bytes/palavra, enquanto um
computador com uma palavra de 64 bits tem 8 bytes/palavra. A significância de uma palavra é que grande parte das
instruções efetua operações com palavras inteiras, por exemplo, somando duas palavras. Assim, uma máquina de 32
bits terá registradores de 32 bits e instruções para manipular palavras de 32 bits, enquanto uma máquina de 64 bits
terá registradores de 64 bits e instruções para movimentar, somar, subtrair e, em geral, manipular palavras de 64 bits.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 59
Figura 2.10 Nu
mero de bits por ce
lula para alguns computadores comerciais historicamente interessantes.
Computador Bits/célula
Burroughs B1700 1
IBM PC 8
DEC PDP-8 12
IBM 1130 16
DEC PDP-15 18
XDS 940 24
Electrologica X8 27
XDS Sigma 9 32
Honeywell 6180 36
CDC 3600 48
CDC Cyber 60
2.2.3 Ordenac
a
o de bytes
Os bytes em uma palavra podem ser numerados da esquerda para a direita ou da direita para a esquerda. A
princípio, essa opção pode parecer sem importância, mas, como veremos em breve, ela tem consideráveis impli-
cações. A Figura 2.11(a) retrata parte da memória de um computador de 32 bits cujos bytes são numerados da
esquerda para a direita, tal como o SPARC ou os grandes mainframes da BM. A Figura 2.11(b) dá uma represen-
tação análoga de um computador de 32 bits que usa uma numeração da direita para a esquerda, como a família
ntel. O primeiro sistema, no qual a numeração começa na ordem “grande”, isto é, na ordem alta, é denominado
computador big endian, ao contrário do little endian da Figura 2.11(b). Esses termos se devem a Jonathan Swift,
cujo livro As viagens de Gulliver satirizava os políticos que discutiam por que uns eram a favor de quebrar ovos
no lado grande (big end) e outros achavam que deviam ser quebrados no lado pequeno (little end). O termo foi
empregado pela primeira vez na arquitetura de computadores em um interessante artigo de Cohen (1981).
Figura 2.11 (a) Memo
ria big endian. (b) Memo
ria little endian.
0
0
(a)
4
4
8
8
12
12
0
4
8
12
1
5
9
13
2
6
10
14
3
7
11
15
3
(b)
7
11
15
2
6
10
14
1
5
9
13
0
4
8
12
Endereço Big endian Little endian Endereço
Byte Byte
Palavra de 32 bits Palavra de 32 bits
É importante entender que, tanto no sistema big endian como no little endian, um inteiro de 32 bits com o
valor numérico de, digamos, 6 é representado pelos bits 110 nos três bits mais à direita (baixa ordem) de uma
palavra e os zeros nos 29 bits da esquerda. No esquema big endian, os bits 110 estão no byte 3 (ou 7, ou 11 etc.),
enquanto no esquema little endian eles estão no byte 0 (ou 4, ou 8 etc.). Em ambos os casos, a palavra que contém
esses inteiros tem endereço 0.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
60
Se os computadores somente armazenassem inteiros, não haveria nenhum problema. Contudo, muitas apli-
cações requerem uma mistura de inteiros, cadeias de caracteres e outros tipos de dados. Considere, por exemplo,
um simples registro de pessoal composto de uma cadeia (nome do empregado) e dois inteiros (idade e número do
departamento). A cadeia é encerrada com 1 ou mais bytes de valor 0 para completar uma palavra. Para o registro
“Jim Smith, idade 21, departamento 260 (1 × 256 + 4 = 260)”, a representação big endian é mostrada na Figura
2.12(a) e a representação little endian é mostrada na Figura 2.12(b).
Figura 2.12 (a) Registro de pessoal para uma ma
quina big endian. (b) O mesmo registro para uma ma
quina little endian. (c) Resultado
da transfere
ncia do registro de uma ma
quina big endian para uma little endian. (d) Resultado da troca de bytes (c).
(a)
J
0 I M
S
4 M I T
H
8 0 0 0
0
12 0 0 21
0
16 0 1 4
(b)
J 0
M I
T 4
I M S
0 8
0 0 H
0 12
0 0 21
0 16
0 1 4
(c)
J
M I
T I M S
0 0 0 H
21 0 0 0
4 1 0 0
(d)
J 0
I M
S 4
M I T
H 8
0 0 0
0 12
0 0 21
0 16
0 1 4
Big endian Little endian
Transferência de
big endian para
little endian
Transferência
e troca
Ambas as representações são boas e internamente consistentes. Os problemas começam quando uma das
máquinas tenta enviar um registro à outra por uma rede. amos supor que a big endian envie o registro à little
endian um byte por vez, começando com o byte 0 e terminando com o byte 19. (amos ser otimistas e supor que
os bits dos bytes não sejam invertidos pela transmissão porque, assim como está, já temos problemas suficientes.)
Portanto, o byte 0 da big endian entra na memória da little endian no byte 0 e assim por diante, como mostra a
Figura 2.12(c).
Quando a little endian tenta imprimir o nome, ela funciona bem, mas a idade sai como 21 × 224
e o depar-
tamento também fica errado. Essa situação surge porque a transmissão inverteu a ordem dos caracteres em uma
palavra, como deveria, mas também inverteu os bytes de um inteiro, o que não deveria.
Uma solução óbvia é fazer o software inverter os bytes de uma palavra após tê-la copiado. sso leva à Figura
2.12(d), que faz os dois inteiros se saírem bem, mas transforma a cadeia em “MJTMS” e deixa o “H” perdido
no meio do nada. Essa inversão da cadeia ocorre porque, ao ler a cadeia, o computador lê primeiro o byte 0 (um
espaço), em seguida o byte 1 (M), e assim por diante.
Não há nenhuma solução simples. Um modo que funciona – porém, ineficiente – é incluir um cabeçalho
na frente de cada item de dado, que informa qual tipo de dado vem a seguir (cadeia, inteiro ou outro) e qual é
seu comprimento. sso permite que o destinatário efetue apenas as conversões necessárias. De qualquer modo, é
preciso deixar claro que a falta de um padrão para a ordenação de bytes é um grande aborrecimento quando há
troca de dados entre máquinas diferentes.
2.2.4 Co
digos de correc
a
o de erro
Memórias de computador podem cometer erros de vez em quando devido a picos de tensão na linha elé-
trica, raios cósmicos ou outras causas. Para se resguardar contra esses erros, algumas memórias usam códigos de
detecção de erros ou códigos de correção de erros. Quando são usados, bits extras são adicionados a cada palavra
de memória de modo especial. Quando uma palavra é lida na memória, os bits extras são verificados para ver se
ocorreu um erro.
Para entender como os erros podem ser manipulados, é preciso ver de perto o que é, na realidade, um erro.
Suponha que uma palavra de memória consista em m bits de dados, aos quais serão adicionados r bits redundantes,
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 61
ou de verificação. Seja o comprimento total n (isto é, n = m + r). Uma unidade de n bits que contém m dados e r
bits de verificação costuma ser denominada uma palavra de código de n bits.
Dadas duas palavras de código quaisquer, por exemplo, 10001001 e 10110001, é possível determinar quan-
tos bits correspondentes são diferentes. Nesse caso, 3 bits são diferentes. Para saber quantos bits são diferentes,
basta calcular o ECLUSE OR (OU ECLUSO) booleano bit por bit das duas palavras de código e contar o
número de bits 1 no resultado. O número de posições de bit nas quais as duas palavras de código diferem é deno-
minado distância de Hamming (Hamming, 1950). Sua principal significância é que, se duas palavras de código
estiverem separadas por uma distância de Hamming d, será preciso d erros de único bit para converter uma na
outra. Por exemplo, as palavras de código 11110001 e 00110000 estão a uma distância de Hamming 3 porque é
preciso 3 erros de único bit para converter uma na outra.
Com uma palavra de memória de m bits, todos os 2m
padrões de bits são válidos, mas, devido ao modo como
os bits de verificação são computados, somente 2m
das 2n
palavras de código são válidas. Se uma leitura de memó-
ria aparecer com uma palavra de código inválida, o computador sabe que ocorreu um erro de memória. Dado o
algoritmo para calcular os bits de verificação, é possível montar uma lista completa das palavras de código válidas
e, por meio dela, achar as duas palavras de código cuja distância de Hamming seja mínima. Essa distância é a
distância de Hamming do código completo.
As propriedades de detecção de erro e correção de erro de um código dependem de sua distância de
Hamming. Para detectar d erros de único bit, você precisa de um código de distância d + 1 porque, com tal
código, não existe nenhum modo que permita que d erros de único bit mudem uma palavra de código válida
para outra. De modo semelhante, para corrigir erros de único bit, você precisa de um código de distância 2d +
1 porque, desse modo, as palavras de código válidas estão tão distantes uma da outra que, mesmo que d mude,
a palavra de código original ainda estará mais perto do que qualquer outra, portanto, ela pode ser unicamente
determinada.
Como um exemplo simples de um código de detecção de erro, considere um código em que um único bit
de paridade é anexado aos dados. O bit de paridade é escolhido de modo que o número de bits 1 na palavra de
código seja par (ou ímpar). Tal código tem uma distância 2, uma vez que qualquer erro de bit único produz uma
palavra de código com paridade errada. Ou seja, ele precisa de dois erros de único bit para ir de uma palavra de
código válida até outra palavra de código válida. Ele pode ser usado para detectar erros isolados. Sempre que uma
palavra que contenha paridade errada for lida da memória, uma condição de erro é sinalizada. O programa não
pode continuar, mas, ao menos, nenhum resultado errado é calculado.
Como um exemplo simples de um código de correção de erros, considere um código que tenha apenas quatro
palavras de código válidas:
0000000000, 0000011111, 1111100000 e 1111111111
Esse código tem uma distância 5, o que significa que pode corrigir erros duplos. Se a palavra de código
0000000111 chegar, o destinatário sabe que a original deve ter sido 0000011111 (se não houver mais do
que um duplo erro). Contudo, se um erro triplo mudar 0000000000 para 0000000111, o erro não pode ser
corrigido.
magine que queremos projetar um código com m bits de dados e r bits de verificação que permitirá que
todos os erros de bits únicos sejam corrigidos. Cada uma das 2m
palavras de memória válidas tem n palavras de
código inválidas a uma distância 1. Essas palavras de código inválidas são formadas sistematicamente invertendo
cada um dos n bits na palavra de código de n bits formada com base nela. Assim, cada uma das 2m
palavras de
memória válidas requer n + 1 padrões de bits dedicados a ela (para os n possíveis erros e padrão de correção).
Uma vez que o número total de padrões de bits é 2n
, temos de ter (n + 1)2m
≤ 2n
. Usando n = m + r, esse requisito
se torna (m + r + 1) ≤ 2r
. Dado m, isso impõe um limite inferior ao número de bits de verificação necessários para
corrigir erros únicos. A Figura 2.13 mostra o número de bits de verificação requeridos por vários tamanhos de
palavras de memória.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
62
Figura 2.13 Nu
mero de bits de verificac
a
o para um co
digo que pode corrigir um erro u
nico.
Tamanho da palavra Bits de verificação Tamanho total Acréscimo percentual
8 4 12 50
16 5 21 31
32 6 38 19
64 7 71 11
128 8 136 6
256 9 265 4
512 10 522 2
Esse limite inferior teórico pode ser conseguido usando um método criado por Richard Hamming (1950).
Antes de analisar o algoritmo de Hamming, vamos examinar uma representação gráfica simples que ilustra com
clareza a ideia de um código de correção de erros para palavras de 4 bits. O diagrama de enn da Figura 2.14(a)
contém três círculos, A, B e C, que juntos formam sete regiões. Como exemplo, vamos codificar a palavra de
memória de 4 bits 1100 nas regiões AB, ABC, AC e BC, 1 bit por região (em ordem alfabética). Essa codificação
é mostrada na Figura 2.14(a).
Figura 2.14 (a) Codificac
a
o de 1100. (b) Paridade par adicionada. (c) Erro em AC.
B
A
C
1
1
0
0
(a)
B
(b)
A
C
1
1
0
0
0
0
1
(c)
A
B
C
1 1
1
1
0
0
0
Erro
Bits de
paridade
Em seguida, acrescentamos um bit de paridade a cada uma dessas três regiões vazias para produzir pari-
dade par, como ilustrado na Figura 2.14(b). Por definição, agora a soma dos bits em cada um dos três círculos,
A, B e C, é um número par. No círculo A, temos os quatro números 0, 0, 1 e 1, cuja soma total é 2, um núme-
ro par. No círculo B, os números são 1, 1, 0 e 0, cuja soma total é 2, um número par. Por fim, no círculo C,
temos a mesma coisa. Nesse exemplo, por acaso todos os círculos são iguais, mas as somas de 0 e 4 também
são possíveis em outros exemplos. Essa figura corresponde a uma palavra de código com 4 bits de dados e 3
bits de paridade.
Agora, suponha que algo de ruim aconteça com o bit na região AC e ele mude de 0 para 1, conforme mostra
a Figura 2.14(c). Agora, o computador pode ver que os círculos A e C têm a paridade errada (ímpar). A única
mudança de bit individual que pode corrigi-los é restaurar AC para 0, o que corrige o erro. Desse modo, o com-
putador pode corrigir automaticamente erros de memória em único bit.
Agora, vamos ver como o algoritmo de Hamming pode ser usado para construir códigos de correção de erros
para qualquer tamanho de palavra de memória. Em um código de Hamming, são acrescentados r bits de paridade
a uma palavra de m bits, formando uma nova palavra de comprimento m + r bits. Os bits são numerados come-
çando com 1, não com 0, sendo que o bit 1 é o da extrema esquerda (ordem alta). Todos os bits cujo número de
bit for uma potência de 2 são de paridade; os restantes são usados para dados. Por exemplo, com uma palavra
de 16 bits, são adicionados 5 bits de paridade. Os bits 1, 2, 4, 8 e 16 são bits de paridade e todos os restantes são
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 63
bits de dados. No total, a palavra de memória tem 21 bits (16 de dados, 5 de paridade). Neste exemplo, usaremos
(arbitrariamente) a paridade par.
Cada bit de paridade verifica posições específicas de bits; o bit de paridade é estabelecido de modo que o
número de 1s nas posições verificadas seja par. As posições de bits verificadas pelos bits de paridade são
Bit 1 verifica bits 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21.
Bit 2 verifica bits 2, 3, 6, 7, 10, 11, 14, 15, 18, 19.
Bit 4 verifica bits 4, 5, 6, 7, 12, 13, 14, 15, 20, 21.
Bit 8 verifica bits 8, 9, 10, 11, 12, 13, 14, 15.
Bit 16 verifica bits 16, 17, 18, 19, 20, 21.
Em geral, o bit b é verificado pelos bits b1
, b2
, ..., bj
tais que b1
+ b2
+ ... + bj
= b. Por exemplo, o bit 5 é
verificado pelos bits 1 e 4 porque 1 + 4 = 5. O bit 6 é verificado pelos bits 2 e 4 porque 2 + 4 = 6 e assim por
diante.
A Figura 2.15 mostra a construção de um código de Hamming para a palavra de memória de 16 bits
1111000010101110. A palavra de código de 21 bits é 001011100000101101110. Para ver como funciona a
correção de erros, considere o que aconteceria se o bit 5 fosse invertido por uma sobrecarga elétrica na linha de
força. A nova palavra de código seria 001001100000101101110 em vez de 001011100000101101110. Os 5 bits
de paridade serão verificados com os seguintes resultados:
Bit de paridade 1 incorreto (1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21 contêm cinco 1s).
Bit de paridade 2 correto (2, 3, 6, 7, 10, 11, 14, 15, 18, 19 contêm seis 1s).
Bit de paridade 4 incorreto (4, 5, 6, 7, 12, 13, 14, 15, 20, 21 contêm cinco 1s).
Bit de paridade 8 correto (8, 9, 10, 11, 12, 13, 14, 15 contêm dois 1s).
Bit de paridade 16 correto (16, 17, 18, 19, 20, 21 contêm quatro 1s).
Figura 2.15 Construc
a
o do co
digo de Hamming para a palavra de memo
ria 1111000010101110 adicionando 5 bits de verificac
a
o aos
16 bits de dados.
0
1
0
2
1
3
0
4
1
5
1
6
1
7
0
8
0
9
0
10
0
11
0
12
1
13
0
14
1
15
1
16
0
17
1
18
1
19
1
20
0
21
Palavra de memória 1111000010101110
Bits de
paridade
O número total de 1s nos bits 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 e 21 deve ser par porque está sendo usada a
paridade par. O bit incorreto deve ser um dos bits verificados pelo bit de paridade 1 – ou seja, bit 1, 3, 5, 7, 9,
11, 13, 15, 17, 19 ou 21. O bit de paridade 4 está incorreto, o que significa que um dos bits 4, 5, 6, 7, 12, 13, 14,
15, 20 ou 21 está incorreto. O erro deve ser um dos bits que está em ambas as listas, a saber, 5, 7, 13, 15 ou 21.
Contudo, o bit 2 está correto, o que elimina os bits 7 e 15. De modo semelhante, o bit 8 está correto, eliminando
o 13. Por fim, o bit 16 está correto, eliminando o 21. O único que sobrou é 5, que é o bit que está com erro. Uma
vez que foi lido como um 1, ele deveria ser um 0. Dessa maneira, os erros podem ser corrigidos.
Um método simples para achar o bit incorreto é calcular antes todos os bits de paridade. Se todos estiverem
corretos, não houve nenhum erro (ou então houve mais de um). Em seguida, somar todos os bits de paridade
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
64
incorretos, contando 1 para o bit 1, 2 para o bit 2, 4 para o bit 4 e assim por diante. A soma resultante é a posição
do bit incorreto. Por exemplo, se os bits de paridade 1 e 4 estiverem incorretos, mas 2, 8 e 16 estiverem corretos,
o bit 5 (1 + 4) foi invertido.
2.2.5 Memo
ria cache
Historicamente, as CPUs sempre foram mais rápidas do que as memórias. Conforme memórias melhoraram
as CPUs também se aperfeiçoaram, mantendo o desequilíbrio. Na verdade, à medida que fica possível colocar cada
vez mais circuitos em um chip, os projetistas estão usando essas novas facilidades no paralelismo (pipelining) e em
operação superescalar, fazendo as CPUs ficarem ainda mais velozes. Projetistas de memória costumam usar nova
tecnologia para aumentar a capacidade de seus chips, e não a velocidade, portanto, parece que os problemas estão
piorando com o passar do tempo. Na prática, o significado desse desequilíbrio é que, após emitir uma requisição
de memória, a CPU não obterá a palavra de que necessita por muitos ciclos de CPU. Quanto mais lenta a memó-
ria, mais ciclos a CPU terá de esperar.
Como já destacamos, há duas maneiras de tratar desse problema. O modo mais simples é somente iniciar
READs (leituras) de memória quando elas forem encontradas, mas continuar executando e bloquear a CPU se
uma instrução tentar usar a palavra de memória antes de ela chegar. Quanto mais lenta a memória, maior será a
frequência desse problema e maior será a penalidade quando isso, de fato, ocorrer. Por exemplo, se uma instru-
ção em cinco toca na memória e o tempo de acesso à memória for de cinco ciclos, o tempo de execução será o
dobro daquele que teria sido na memória instantânea. Mas, se o tempo de acesso for de 50 ciclos, então o tempo
de execução será elevado por um fator de 11 (5 ciclos para executar instruções mais 50 ciclos para esperar pela
memória).
A outra solução é ter máquinas que não ficam bloqueadas, mas, em vez disso, exigem que o compilador
não gere código para usar palavras antes que elas tenham chegado. O problema é que é muito mais fácil falar
dessa abordagem do que executá-la. Muitas vezes, não há nada mais a fazer após um LOAD (carregar), portanto,
o compilador é forçado a inserir instruções NOP (nenhuma operação), que nada mais fazem do que ocupar um
intervalo (slot) e gastar tempo. Com efeito, essa abordagem é um bloqueio de software em vez de um bloqueio de
hardware, mas a degradação do desempenho é a mesma.
Na verdade, o problema não é tecnológico, mas econômico. Os engenheiros sabem como construir memórias
tão rápidas quanto as CPUs, mas para que executem a toda velocidade, elas têm de estar localizadas no chip da
CPU (porque passar pelo barramento para alcançar a memória é uma operação muito lenta). nstalar uma memó-
ria grande no chip da CPU faz com que esta fique maior e, portanto, mais cara. Ainda que o custo não fosse uma
questão a considerar, há limites de tamanho para um chip de CPU. Assim, a opção se resume a ter uma pequena
quantidade de memória rápida ou uma grande quantidade de memória lenta. O que nós gostaríamos de ter é uma
grande quantidade de memória rápida a um preço baixo.
O interessante é que há técnicas conhecidas para combinar uma pequena quantidade de memória rápida com
uma grande quantidade de memória lenta para obter (quase) a velocidade da memória rápida e a capacidade da
memória grande a um preço módico. A memória pequena e rápida é denominada cache (do francês cacher, que
significa “esconder” e se pronuncia “késh”). Em seguida, descreveremos brevemente como as caches são usadas e
como funcionam. O Capítulo 4 apresenta uma descrição mais detalhada.
A ideia básica de uma cache é simples: as palavras de memória usadas com mais frequência são mantidas na
cache. Quando a CPU precisa de uma palavra, ela examina em primeiro lugar a cache. Somente se a palavra não
estiver ali é que ela recorre à memória principal. Se uma fração substancial das palavras estiver na cache, o tempo
médio de acesso pode ser muito reduzido.
Assim, o sucesso ou o fracasso depende da fração das palavras que estão na cache. Há anos todos sabemos
que programas não acessam suas memórias de forma totalmente aleatória. Se uma dada referência à memória for
para o endereço A, é provável que a próxima estará na vizinhança geral de A. Um exemplo simples é o próprio
programa. Exceto quando se trata de desvios e de chamadas de procedimento, as instruções são buscadas em
localizações consecutivas da memória. Além do mais, grande parte do tempo de execução de um programa é
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 65
gasto em laços, nos quais um número limitado de instruções é executado repetidas vezes. De modo semelhante,
é provável que um programa de manipulação de matrizes fará muitas referências à mesma matriz antes de passar
para outra coisa qualquer.
A observação de que referências à memória feitas em qualquer intervalo de tempo curto tendem a usar
apenas uma pequena fração da memória total é denominada princípio da localidade, e forma a base de todos
os sistemas de cache. A ideia geral é que, quando uma palavra for referenciada, ela e algumas de suas vizinhas
sejam trazidas da memória grande e lenta para a cache, de modo que, na próxima vez em que for usada, ela
possa ser acessada rapidamente. Um arranjo comum da CPU, cache e memória principal é ilustrado na Figura
2.16. Se uma palavra for lida ou escrita k vezes em um curto intervalo de tempo, o computador precisará de
1 referência à memória lenta e k – 1 referências à memória rápida. Quanto maior for k, melhor será o desem-
penho global.
Figura 2.16 A localizac
a
o lo
gica da cache e
 entre a CPU e a memo
ria principal. Em termos f
sicos, ha
 diversos lugares em que ela poderia
estar localizada.
Memória
principal
CPU
Cache
Barramento
Podemos formalizar esse cálculo introduzindo c, o tempo de acesso à cache; m, o tempo de acesso à memória
principal; e h, a taxa de acerto, que é a fração de todas as referências que podem ser satisfeitas através da cache.
Em nosso pequeno exemplo do parágrafo anterior, h = (k – 1)/k. Alguns autores também definem a taxa de falha
(na cache), que é 1 – h.
Com essas definições, podemos calcular o tempo de acesso médio como segue:
tempo de acesso médio = c + (1 – h) m
À medida que h → 1, todas as referências podem ser satisfeitas fora da cache e o tempo de acesso médio se
aproxima de c. Por outro lado, à medida que h → 0, toda vez será necessária uma referência à memória, portanto,
o tempo de acesso se aproxima de c + m, primeiro um tempo para verificar a cache (sem sucesso) e então um
tempo m para fazer a referência à memória. Em alguns sistemas, a referência à memória pode ser iniciada em
paralelo com a busca na cache, de modo que, se ocorrer uma falha na cache (cache miss), o ciclo da memória já
terá sido iniciado. Contudo, essa estratégia requer que a memória possa ser interrompida se houver uma presença
na cache (cache hit), o que torna a implantação mais complicada.
Usando o princípio da localidade como guia, memórias principais e caches são divididas em blocos de tama-
nho fixo. Ao nos referirmos a esses blocos dentro da cache, eles costumam ser chamados de linhas de cache.
Quando a busca na cache falha, toda a linha de cache é carregada da memória principal para a cache, e não
apenas a palavra que se quer. Por exemplo, com uma linha de cache de 64 bytes de tamanho, uma referência
ao endereço de memória 260 puxará a linha que consiste nos bytes 256 a 319 para uma linha de cache. Com
um pouco de sorte, algumas das outras palavras na linha de cache também serão necessárias em breve. Esse
tipo de operação é mais eficiente do que buscar palavras individuais porque é mais rápido buscar k palavras de
uma vez só do que uma palavra k vezes. Além disso, ter entradas de cache de mais do que uma palavra significa
que há menor número delas; por conseguinte, é preciso menos memória auxiliar (overhead). Por fim, muitos
computadores podem transferir 64 ou 128 bits em paralelo em um único ciclo do barramento, até mesmo em
máquinas de 32 bits.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
66
O projeto de cache é uma questão de importância cada vez maior para CPUs de alto desempenho. Um aspec-
to é o tamanho da cache. Quanto maior, melhor seu funcionamento, mas também maior é o custo. Um segundo
aspecto é o tamanho da linha de cache. Uma cache de 16 KB pode ser dividida em até 1.024 linhas de 16 bytes,
2.048 linhas de 8 bytes e outras combinações. Um terceiro aspecto é a maneira de organização, isto é, como ela
controla quais palavras de memória estão sendo mantidas no momento. Examinaremos caches detalhadamente
no Capítulo 4.
Um quarto aspecto do projeto é se as instruções e dados são mantidos na mesma cache ou em caches dife-
rentes. Ter uma cache unificada (instruções e dados usam a mesma cache) é um projeto mais simples e mantém
automaticamente o equilíbrio entre buscas de instruções e buscas de dados. No entanto, a tendência hoje é uma
cache dividida, com instruções em uma cache e dados na outra. Esse projeto também é denominado arquitetura
Harvard e essa referência volta ao passado até o computador Mark  de Howard Aiken, que tinha memórias
diferentes para instruções e dados. A força que impele os projetistas nessa direção é a utilização muito difundida
de CPUs com paralelismo (pipelined). A unidade de busca de instrução precisa acessar instruções ao mesmo
tempo em que a unidade de busca de operandos precisa de acesso aos dados. Uma cache dividida permite acessos
paralelos; uma cache unificada, não. Além disso, como as instruções não são modificadas durante a execução, o
conteúdo da cache de instrução nunca tem de ser escrito de volta na memória.
Por fim, um quinto aspecto é o número de caches. Hoje em dia não é incomum ter chips com uma cache
primária no chip, uma cache secundária fora dele, mas no mesmo pacote do chip da CPU, e uma terceira cache ainda
mais distante.
2.2.6 Empacotamento e tipos de memo
ria
Desde os primeiros dias da memória de semicondutor até o início da década 1990, a memória era fabrica-
da, comprada e instalada como chips únicos. As densidades dos chips iam de 1 K bits até 1 M bits e além, mas
cada chip era vendido como uma unidade separada. Os primeiros PCs costumavam ter soquetes vazios nos quais
podiam ser ligados chips de memória adicionais, se e quando o comprador precisasse deles.
Desde o início da década de 1990, usa-se um arranjo diferente. Um grupo de chips, em geral 8 ou 16, é
montado em uma minúscula placa de circuito impresso e vendido como uma unidade. Essa unidade é deno-
minada SIMM (Single Inline Memory Module  módulo único de memória em linha) ou IMM (ual Inline
Memory Module  módulo duplo de memória em linha), dependendo se tem uma fileira de conectores de um
só lado ou de ambos os lados da placa. Os SMMs têm um conector de borda com 72 contatos e transferem
32 bits por ciclo de clock. Os DMMs em geral têm conectores de borda com 120 contatos em cada lado da
placa, perfazendo um total de 240 contatos e transferem 64 bits por ciclo de clock. Os mais comuns hoje são
os DMMs DDR3, que é a terceira versão das memórias de taxa dupla. Um exemplo típico de DMM é ilustrado
na Figura 2.17.
Figura 2.17 Visa
o superior de um DIMM de 4 GB, com oito chips de 256 MB em cada lado. O outro lado tem a mesma apare
ncia.
133 mm
Conector
Chip de
memória
de 256 MB
Uma configuração típica de DMM poderia ter oito chips de dados com 256 MB cada. Então, o módulo intei-
ro conteria 2 GB. Muitos computadores têm espaço para quatro módulos, o que dá uma capacidade total de 8 GB
se usarem módulos de 2 GB e mais, se usarem módulos maiores.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 67
Um DMM fisicamente menor, denominado SO-IMM (Small Outline IMM  IMM pequeno perfil)
é usado em notebooks. Pode-se adicionar um bit de paridade ou correção de erro aos DMMS, porém, visto
que a taxa média de erro de um módulo é de um erro a cada dez anos, na maioria dos computadores de uso
comum e doméstico, detecção e correção de erros são omitidas.
2.3 Memo
ria secunda
ria
Seja qual for o tamanho da memória principal, ela sempre será muito pequena. As pessoas sempre querem
armazenar mais informações do que a memória pode conter, ainda mais porque, à medida que a tecnologia melho-
ra, elas começam a pensar em armazenar coisas que antes estavam inteiramente no reino da ficção científica. Por
exemplo, como as diretrizes orçamentárias do governo dos Estados Unidos obrigam as agências governamentais a
gerar sua própria receita, podemos imaginar a Biblioteca do Congresso decidindo digitalizar e vender todo o seu
conteúdo como um artigo de consumo (“Todo o conhecimento humano por apenas US$ 299,95”). Cerca de 50
milhões de livros, cada qual com 1 MB de texto e 1 MB de figuras comprimidas, requerem armazenagem de 1014
bytes ou 100 terabytes. Armazenar todos os 50 mil filmes produzidos até agora também faz parte desse carnaval.
Essa quantidade de informação não caberá na memória principal, ao menos por algumas décadas.
2.3.1 Hierarquias de memo
ria
A solução tradicional para armazenar grandes quantidades de dados é uma hierarquia de memória, como
ilustrada na Figura 2.18. No topo, estão os registradores da CPU, que podem ser acessados à velocidade total da
CPU. Em seguida, vem a memória cache, que está na faixa de 32 KB a alguns megabytes. A memória vem logo
após, hoje com tamanhos que vão de 1 GB para sistemas básicos até centenas de gigabytes na extremidade mais
alta. Depois, vêm os discos magnéticos, o atual burro de carga da armazenagem permanente. Por fim, temos fitas
magnéticas e discos ópticos para armazenagem de arquivos.
À medida que descemos na hierarquia, três parâmetros aumentam. Primeiro, o tempo de acesso fica maior.
Os registradores da CPU podem ser acessados em um nanossegundo ou menos. Memórias cache demoram um
pequeno múltiplo dos registradores da CPU. Acessos à memória principal normalmente levam 10 nanossegundos.
Agora, vem uma grande lacuna, porque tempos de acesso a discos são no mínimo 10 vezes mais lentos para discos
em estado sólido e centenas de vezes mais lentos para discos magnéticos. Acessos a fitas ou discos óticos podem
ser medidos em segundos se a mídia tiver de ser buscada e inserida no drive.
Figura 2.18 Hierarquia de memo
ria de cinco n
veis.
Registradores
Cache
Memória principal
Disco magnético ou de estado sólido
Fita Disco ótico
Largura de
um 1 bit é
0,1 a 0,2 mícron
Cabeçote de
leitura/escrita
A sequência circular de bits escritos quando o disco faz uma rotação completa é denominada trilha. Cada
trilha é dividida em algum número de setores de tamanho fixo, que em geral contêm 512 bytes de dados, prece-
didos por um preâmbulo que permite a sincronização do cabeçote antes de uma leitura ou escrita. Em seguida
aos dados há um código de correção de erros (ECC – Error-Correcting Code), ou um código de Hamming ou,
mais comumente, um código que pode corrigir múltiplos erros, denominado código de Reed-Solomon. Entre
setores consecutivos há uma pequena lacuna intersetores. Alguns fabricantes citam a capacidade de seus discos
no estado sem formatação (como se cada trilha contivesse apenas dados), mas uma medida mais honesta é a capa-
cidade no estado formatado, que não conta os preâmbulos, ECCs e lacunas como dados. A capacidade do disco
formatado é normalmente 15% menor do que a capacidade sem formatação.
O r g a n i z a ç ã o e s t r u t u r a d a d e c o m p u t a d o r e s
68
Segundo, a capacidade de armazenagem aumenta à medida que descemos na hierarquia. Registradores de
CPU são bons para, talvez, 128 bytes, caches para algumas dezenas de megabytes, memórias principais para
alguns gigabytes, discos em estado sólido para centenas de gigabytes e discos magnéticos para terabytes. Fitas
e discos ópticos costumam ser mantidos off-line, portanto, sua capacidade é limitada apenas pelo orçamento
do usuário.
Terceiro, o número de bits por dólar gasto aumenta descendo a hierarquia. Embora os preços atuais mudem
com rapidez, a memória principal é medida em dólares/megabyte, o disco em estado sólido em dólares/gigabyte
e a armazenagem em disco magnético e fita em centavos/gigabyte.
Já vimos registradores, cache e memória principal. Nas seções seguintes, vamos examinar os discos magnéticos
e os discos em estado sólido; depois, estudaremos os discos óticos. Não estudaremos fitas porque são raramente
usadas, exceto para cópias de segurança (backup) e, de qualquer forma, não há muita coisa a dizer sobre elas.
2.3.2 Discos magnéticos
Um disco magnético é composto de um ou mais pratos de alumínio com um revestimento magnetizável.
No início, esses pratos tinham até 50 cm de diâmetro, mas agora têm normalmente de 3 a 9 cm, e discos para
notebooks já estão com menos de 3 cm e continuam encolhendo. Um cabeçote de disco que contém uma bobina
de indução flutua logo acima da superfície, apoiado sobre um colchão de ar. Quando uma corrente positiva ou
negativa passa pelo cabeçote, ele magnetiza a superfície logo abaixo dele, alinhando as partículas magnéticas para
a esquerda ou para a direita, dependendo da polaridade da corrente. Quando o cabeçote passa sobre uma área
magnetizada, uma corrente positiva ou negativa é induzida nele, o que possibilita a leitura dos bits armazenados
antes. Assim, à medida que o prato gira sob o cabeçote, uma corrente de bits pode ser escrita e mais tarde lida. A
geometria de uma trilha de disco é mostrada na Figura 2.19.
Figura 2.19 Porção de uma trilha de disco. Dois setores são ilustrados.
Braço
do disco
Read/write
head
Direction of disk rotation
4096 data bits
Preamble
E
C
C
E
C
C
1
setor
Lacuna de
intersecção
Direção da rotação do disc
o
Preâm
bulo
Preâmbulo
Largura
da trilha
é 1–2 micra
4096
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 69
Todos os discos têm braços móveis que podem se mover para dentro e para fora a diferentes distâncias
radiais da haste ao redor da qual o prato gira. A cada distância radial pode ser escrita uma trilha diferente.
Assim, as trilhas são uma série de círculos concêntricos ao redor da haste. A largura de uma trilha depende
da largura do cabeçote e da precisão com que ele pode ser posicionado radialmente. Com tecnologia atual, os
discos têm em torno de 50 mil trilhas por centímetro, resultando em larguras de trilha na faixa de 200 nanô-
metros (1 nanômetro = 1/1.000.000 mm). Deve-se notar que uma trilha não é um sulco físico na superfície,
mas apenas um anel de material magnetizado com pequenas áreas de proteção que o separa das trilhas que
estão dentro e fora dele.
A densidade linear de bits ao redor da circunferência da trilha é diferente da radial. Em outras palavras, o
número de bits por milímetro medida em torno de uma trilha é diferente do número de bits por milímetro a partir
do centro em direção à borda externa. A densidade ao redor de uma trilha é determinada em grande parte pela
pureza da superfície e pela qualidade do ar. Os discos de hoje atingem densidades de 25 gigabits/cm. A densidade
radial é determinada pela precisão que o braço pode ter para chegar a uma trilha. Assim, um bit é muitas vezes
maior na direção radial em comparação com a circunferência, conforme sugere a Figura 2.19.
Para atingir densidades ainda mais altas, os fabricantes de discos estão desenvolvendo tecnologias nas quais a
dimensão “longa” dos bits não está ao longo da circunferência do disco, mas na direção vertical, dentro do óxido
de ferro. Essa técnica é denominada gravação perpendicular e demonstrou-se que pode oferecer densidades de
dados de até 100 gigabits/cm. É provável que essa se torne a tecnologia dominante nos próximos anos.
Para conseguir alta qualidade de superfície e ar, a maioria dos discos é selada na fábrica para evitar a
entrada de pó. Esses drives eram denominados discos Winchester, pois os primeiros deles (criados pela BM)
tinham 30 MB de armazenagem selada e fixa e 30 MB de armazenagem removível. Conta a história que esses
discos 30-30 lembravam às pessoas os rifles Winchester 30-30, que desempenharam um papel importante na
abertura das fronteiras norte-americanas, e o nome “Winchester” ficou. Agora, eles são chamados simples-
mente de discos rígidos, para diferenciá-los dos antigos disquetes (ou discos flexíveis) usados nos primeiros
computadores pessoais. Nessa área, é muito difícil escolher um nome para alguma coisa que não se torne
ridículo 30 anos depois.
A maioria dos discos é composta de vários pratos empilhados na vertical, como ilustrado na Figura 2.20.
Cada superfície tem seu próprio braço e cabeçote. Os braços são agrupados de modo que todos se movimentem
para diferentes posições radiais ao mesmo tempo. O conjunto de trilhas em uma dada posição radial é denomi-
Figura 2.20 Disco com quatro pratos.
Superfície 7
Superfície 6
Superfície 5
Superfície 4
Superfície 3
Superfície 2
Superfície 1
Superfície 0
Cabeçote de leitura/escrita (1 por superfície)
Direção do movimento
do braço
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
70
nado cilindro. Os discos usados hoje em PCs costumam ter de 1 a 12 pratos por drive, o que resulta em 2 a 24
superfícies de gravação. Discos de última geração podem armazenar 1 TB em um único prato, e esse limite cer-
tamente crescerá com o tempo.
O desempenho do disco depende de vários fatores. Para ler ou escrever um setor, primeiro o braço deve se
deslocar até a posição radial correta. Essa ação é denominada busca (seek). Tempos médios de busca (entre trilhas
aleatórias) estão na faixa de 5 a 10 ms, embora buscas entre trilhas consecutivas agora já estejam abaixo de 1 ms.
Logo que o cabeçote estiver posicionado radialmente, há um atraso, denominado latência rotacional, até que o
setor desejado gire sob o cabeçote. A maioria dos discos gira a 5.400 RPM, 7.200 RPM ou 10.800 RPM, portanto, o
atraso médio (meia rotação) é de 3 a 6 ms. O tempo de transferência depende da densidade linear e da velocidade
de rotação. Com taxas de transferência típicas de 150 MB/s, um setor de 512 bytes demora cerca de 3,5 µs. Por
conseguinte, o tempo de busca e a latência rotacional dominam o tempo de transferência. Ler setores aleatórios
por todo o disco é claramente um modo ineficiente de operar.
ale a pena mencionar que, por conta de preâmbulos, ECCs, lacunas intersetores, tempos de busca e latên-
cias rotacionais, há uma grande diferença entre taxa de rajada (burst rate) máxima de um drive e sua taxa máxima
sustentada. A taxa máxima de rajada é a taxa de dados, uma vez que o cabeçote está sobre o primeiro bit de dados.
O computador deve ser capaz de manipular os dados que estão chegando com essa mesma rapidez. Contudo, o
drive só pode manter essa taxa para um único setor. Para algumas aplicações, como multimídia, o que importa
é a taxa sustentada média durante um período de segundos, que também tem de levar em conta as necessárias
buscas e atrasos rotacionais.
Um pouco de raciocínio e a utilização daquela velha fórmula de matemática do colegial para a circunferên-
cia de um círculo, c = 2πr, revelarão que a distância linear ao redor das trilhas mais externas é maior do que a
das trilhas mais internas. Uma vez que todos os discos magnéticos giram com velocidade angular constante, não
importando onde estão os cabeçotes, essa observação cria um problema. Nos drives antigos, os fabricantes usavam
a máxima densidade linear possível na trilha mais interna e densidades lineares de bits sucessivamente menores
nas trilhas mais externas. Se um disco tivesse 18 setores por trilha, por exemplo, cada uma ocupava 20 graus de
arco, não importando em qual cilindro se encontrava.
Hoje, usa-se uma estratégia diferente. Os cilindros são divididos em zonas (normalmente, 10 a 30 por drive)
e o número de setores por trilha aumenta de zona em zona partindo da trilha mais interna para a mais externa.
Essa mudança dificulta o rastreamento de informações mas aumenta a capacidade do drive, que é considerada
mais importante. Todos os setores são do mesmo tamanho. A Figura 2.21 mostra um disco com cinco zonas.
Figura 2.21 Disco com cinco zonas. Cada zona tem muitas trilhas.
Setor
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 71
Associado a cada drive há um controlador de disco, um chip que controla o drive. Alguns controladores
contêm uma CPU completa. Entre as tarefas do controlador estão: aceitar comandos do software, como READ,
WRTE e FORMAT (escrevendo todos os preâmbulos), controlar o movimento do braço, detectar e corrigir erros
e converter bytes de 8 bits lidos na memória em uma corrente serial de bits e vice-versa. Alguns controladores
também manipulam o buffer de múltiplos setores, fazendo cache de setores lidos para potencial uso futuro e rema-
peando setores ruins. Essa última função é causada pela existência de setores que têm um ponto ruim, ou seja,
permanentemente magnetizado. Quando descobre um setor ruim, o controlador o substitui por um dos setores
sobressalentes reservados para esse fim dentro de cada cilindro ou zona.
2.3.3 Discos IDE
Os discos dos modernos computadores pessoais evoluíram daquele usado no BM PC T, que era um disco
Seagate de 10 MB controlado por um controlador de disco ebec em um cartão de encaixe (plug-in). O disco
Seagate tinha 4 cabeçotes, 306 cilindros e 17 setores por trilha. O controlador conseguia manipular dois drives. O
sistema operacional lia e escrevia em um disco colocando parâmetros em registradores da CPU e então chamando
o BIOS (Basic Input Output System  sistema básico de entrada e saída) localizado na memória somente de
leitura do PC. O BOS emitia as instruções de máquina para carregar os registradores do controlador de disco que
iniciava as transferências.
A tecnologia evoluiu rapidamente e passou do controlador em uma placa separada para o controlador inte-
grado com os drives, começando com drives IE (Integrated rive Electronics  eletrônica integrada ao drive)
em meados da década de 1980. Contudo, as convenções de chamada do BOS não foram alteradas por causa da
compatibilidade. Essas convenções de chamada endereçavam setores dando seus números de cabeçote, cilindro e
setor, sendo que a numeração de cabeçotes e cilindros começava em 0, e de setores, em 1. Essa escolha provavel-
mente se deveu a um erro da parte do programador original do BOS, que escreveu sua obra-prima em assembler
8088. Com 4 bits para o cabeçote, 6 bits para o setor e 10 bits para o cilindro, o drive máximo podia ter 16 cabe-
çotes, 63 setores e 1.024 cilindros, para um total de 1.032.192 setores. Esse drive máximo tinha uma capacidade
de 504 MB, o que devia parecer uma infinidade naquela época, porém, agora, decerto não. (Hoje você criticaria
uma nova máquina que não pudesse manipular drives maiores do que 1.000 TB?)
nfelizmente, não passou muito tempo e apareceram drives acima de 504 MB, mas com a geometria errada
(por exemplo, 4 cabeçotes, 32 setores e 2.000 cilindros totalizam 256.000 setores). O sistema operacional não
conseguia endereçá-los de modo algum, por causa das convenções de chamada do BOS há muito cristalizadas. O
resultado é que os controladores de disco começaram a mentir, fingindo que a geometria estava dentro dos limites
do BOS embora, na verdade, estivesse remapeando a geometria virtual para a geometria real. Embora essa técnica
funcionasse, causava grandes estragos nos sistemas operacionais que posicionavam dados cuidadosamente para
minimizar tempos de busca.
Com o tempo, os drives DE evoluíram para drives EIE (Extended IE  IE estendido), que também
suportavam um segundo esquema de endereçamento denominado LB (Logical Block ddressing  endereça-
mento de blocos lógicos), que numera os setores começando em 0 até um máximo de 228
– 1. Esse esquema
requer que o controlador converta endereços LBA para endereços de cabeçote, setor e cilindro, mas ultrapassa
o limite de 504 MB. nfelizmente, ele criava um novo gargalo a 228
× 29
bytes (128 GB). Em 1994, quando foi
adotado o padrão EDE, ninguém poderia imaginar discos de 128 GB. Comitês de padronização, assim como os
políticos, têm tendência de empurrar problemas para que o próximo comitê os resolva.
Drives e controladores EDE também tinham outras melhorias. Por exemplo, controladores EDE podiam
ter dois canais, cada um com um drive primário e um secundário. Esse arranjo permitia um máximo de quatro
drives por controlador. Drives de CD-ROM e DD também eram suportados, e a taxa de transferência aumentou
de 4 MB/s para 16,67 MB/s.
Enquanto a tecnologia de disco continuava a melhorar, o padrão EDE continuava a evoluir, mas, por alguma
razão, o sucessor do EDE foi denominado -3 ( ttachment), uma referência ao BM PC/AT (onde AT se
referia à então “tecnologia avançada” – Advanced Technology – de uma CPU de 16 bits executando em 8 MHz).
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
72
Na edição seguinte, o padrão recebeu o nome de PI-4 ( Packet Interface  interface de pacotes ) e
a velocidade aumentou para 33 MB/s. Com o ATAP-5, ela alcançou 66 MB/s.
Nessa época, o limite de 128 GB imposto pelos endereços LBA de 28 bits estava ficando cada vez mais
ameaçador, portanto, o ATAP-6 alterou o tamanho do LBA para 48 bits. O novo padrão entrará em dificuldade
quando os discos chegarem a 248
× 29
bytes (128 PB). Com um aumento de capacidade de 50% ao ano, o limite
de 48 bits deverá durar até mais ou menos 2035. Para saber como o problema foi resolvido, favor consultar a
décima primeira edição deste livro. A melhor aposta é que o tamanho do LBA alcance 64 bits. O padrão ATAP-6
também aumentou a taxa de transferência para 100 MB/s e atacou a questão do ruído do disco pela primeira vez.
O padrão ATAP-7 é uma ruptura radical com o passado. Em vez de aumentar o tamanho do conector do
drive (para aumentar a taxa de dados), esse padrão usa o que é chamado  serial para transferir 1 bit por vez
por um conector de 7 pinos a velocidades que começam em 150 MB/s e que, com o tempo, espera-se que alcancem
1,5 GB/s. Substituir o atual cabo plano de 80 fios por um cabo redondo com apenas alguns milímetros a mais de
espessura melhora o fluxo de ar dentro do computador. Além disso, o ATA serial usa 0,5 volt para sinalização
(em comparação com os 5 volts dos drives ATAP-6), o que reduz o consumo de energia. É provável que, dentro
de alguns anos, todos os computadores usarão ATA serial. A questão do consumo de energia pelos discos é cada
vez mais importante, tanto na extremidade mais alta do mercado, onde centrais de dados têm vastas coleções de
discos, como na mais baixa, onde os notebooks são limitados em questão de energia (Gurumurthi et al., 2003).
2.3.4 Discos SCSI
Discos SCS não são diferentes de discos DE em relação ao modo como seus cilindros, trilhas e setores são
organizados, mas têm uma interface diferente e taxas de transferência muito mais elevadas. A história dos SCS
remonta a Howard Shugart, o inventor do disco flexível, cuja empresa lançou o disco SAS (Shugart Associates
System nterface – interface de sistema da Shugart Associates) em 1979. Após algumas modificações e muita dis-
cussão, a ANS o padronizou em 1986 e mudou o nome para SCSI (Small Computer System Interface  interface
para sistemas computacionais pequenos). A pronúncia de SCS em inglês é “scâzi”, de scuzzy. Desde então,
foram padronizadas versões cada vez mais rápidas sob os nomes de Fast SCS (10 MHz), Ultra SCS (20 MHz),
Ultra2 SCS (40 MHz), Ultra3 SCS (80 MHz) e Ultra4 SCS (160 MHz). Cada uma dessas versões também tem
uma versão larga (16 bits). As principais combinações são mostradas na Figura 2.22.
Figura 2.22 Alguns dos poss
veis para
metros SCSI.
Nome Bits de dados
Frequência do barramento
(MHz)
MB/s
SCSI-1 8 5 5
Fast SCSI 8 10 10
Wide Fast SCSI 16 10 20
Ultra SCSI 8 20 20
Wide Ultra SCSI 16 20 40
Ultra2 SCSI 8 40 40
Wide Ultra2 SCSI 16 40 80
Wide Ultra3 SCSI 16 80 160
Wide Ultra4 SCSI 16 160 320
Wide Ultra5 SCSI 16 320 640
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 73
Como têm altas taxas de transferência, os discos SCS são o disco padrão de grande parte das estações de
trabalho e servidores, em especial aqueles que trabalham na configuração RAD (ver adiante).
O SCS é mais do que apenas uma interface de disco rígido. É um barramento ao qual podem ser conectados
um controlador SCS e até sete dispositivos. Entre eles, podem estar um ou mais discos rígidos SCS, CD-ROMs,
gravadores de CD, scanners, unidades de fita e outros periféricos SCS. Cada dispositivo SCS tem um único D,
de 0 a 7 (15 para o SCS largo – wide SCS). Cada dispositivo tem dois conectores: um para entrada e um para
saída. Cabos conectam a saída de um dispositivo à entrada do seguinte, em série, como se fosse um cordão de
lâmpadas baratas de árvore de Natal. O último dispositivo do cordão deve ser terminado para evitar que reflexões
das extremidades do barramento SCS interfiram com outros dados no barramento. Em geral, o controlador está
em um cartão de encaixe (plug-in) no início da cadeia de cabos, embora essa configuração não seja uma exigência
estrita do padrão.
O cabo mais comum para SCS de 8 bits tem 50 fios, 25 dos quais são terras que fazem par com os outros
25 fios para dar excelente imunidade contra ruído, necessária para operação em alta velocidade. Dos 25 fios, 8
são para dados, 1 é para paridade, 9 são para controle e os restantes são para energia elétrica ou reservados para
utilização futura. Os dispositivos de 16 bits (e 32 bits) precisam de um segundo cabo para os sinais adicionais.
Os cabos podem ter muitos metros de comprimento, o que permite drives externos, scanners etc.
Controladores e periféricos SCS podem funcionar como iniciadores ou como alvos. Em geral, o controlador,
agindo como iniciador, emite comandos para discos e outros periféricos que agem como alvos. Esses comandos
são blocos de até 16 bytes, que dizem ao alvo o que ele tem de fazer. Comandos e respostas ocorrem em fases,
usando vários sinais de controle para delinear as fases e arbitrar o acesso ao barramento quando vários dispositi-
vos tentam usá-lo ao mesmo tempo. Essa arbitragem é importante porque o SCS permite que todos os disposi-
tivos funcionem simultaneamente, o que de modo potencial resulta em grande aumento do desempenho em um
ambiente em que há múltiplos processos ativos ao mesmo tempo. DE e EDE permitem apenas um dispositivo
ativo por vez.
2.3.5 RAID
O desempenho da CPU vem tendo aumento exponencial na última década e dobra a cada 18 meses mais ou
menos. O mesmo não acontece com o desempenho do disco. Na década de 1970, os tempos médios de busca em
discos de minicomputadores eram de 50 a 100 ms. Agora, são de 10 ms. Na maioria das indústrias técnicas (por
exemplo, automóveis ou aviação), um fator de 5 a 10 de melhoria de desempenho em duas décadas seria uma
grande notícia, mas na indústria de computadores isso é constrangedor. Assim, a lacuna entre o desempenho da
CPU e o do disco ficou cada vez maior com o passar do tempo.
Como vimos, muitas vezes é usado processamento paralelo para acelerar o desempenho da CPU. Ao longo
dos anos, ocorreu a várias pessoas que a E/S paralela também poderia ser uma boa ideia. Em seu artigo de
1988, Patterson et al. sugeriram seis organizações específicas de disco que poderiam ser usadas para melhorar o
desempenho, a confiabilidade do disco, ou ambos (Patterson et al., 1988). Essas ideias logo foram adotadas pela
indústria e deram origem a uma nova classe de dispositivos de E/S, denominados RI. Patterson et al. definiram
RI como Redundant rray of Inexpensive isks (arranjo redundante de discos baratos), mas a indústria
redefiniu o  como “independente” em vez de barato (inexpensive) – talvez para que pudessem usar discos caros?
Já que também era preciso ter um vilão (como no caso RSC versus CSC, também devido a Patterson), nesse caso
o bandido era o SLE (Single Large Expensive isk  disco único grande e caro).
A ideia fundamental de um RAD é instalar uma caixa cheia de discos próxima ao computador, em geral um
grande servidor, substituir a placa do controlador de disco por um controlador RAD, copiar os dados para o RAD
e então continuar a execução normal. Em outras palavras, um RAD deveria parecer um SLED para o sistema ope-
racional, mas ter melhor desempenho e melhor confiabilidade. Uma vez que discos SCS têm bom desempenho,
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
74
baixo preço e a capacidade de ter até 7 drives em um único controlador (15 para o wide SCS), é natural que a
maioria dos RADs consista em um controlador RAD SCS mais uma caixa de discos SCS que parecem para o
sistema operacional como um único disco grande. Portanto, não é preciso alterar software para usar o RAD, um
ótimo argumento de venda para muitos administradores de sistemas.
Além de parecerem um disco único para o software, há uma propriedade comum a todos os RADs,
que é a distribuição dos dados pelos drives para permitir operação paralela. Patterson et al. definiram vários
esquemas diferentes para fazer isso e, agora, eles são conhecidos como RAD nível 0 até RAD nível 5. Além
disso, há alguns outros níveis menos importantes que não discutiremos. O termo “nível” é, de certa manei-
ra, uma denominação imprópria, uma vez que não há nenhuma hierarquia envolvida; há simplesmente seis
diferentes organizações possíveis, cada qual com uma mistura diferente de características de confiabilidade
e desempenho.
O RAD nível 0 é ilustrado na Figura 2.23(a). Consiste em ver o disco virtual simulado pelo RAD como
se fosse dividido em tiras de k setores cada: os setores 0 a k – 1 são a tira 0, os setores k a 2k – 1 são a tira 1 e
assim por diante. Para k = 1, cada tira é um setor; para k = 2, uma tira são dois setores etc. A organização RAD
nível 0 escreve tiras consecutivas nos drives por alternância circular, como demonstrado na Figura 2.23(a) para
um RAD com quatro drives de disco. Essa distribuição de dados por múltiplos drives é denominada striping
(ou segmentação). Por exemplo, se o software emitir um comando para ler um bloco de dados que consiste
em quatro tiras consecutivas e começa na borda da tira, o controlador RAD o subdividirá em quatro comandos
separados, um para cada disco, e fará com que eles funcionem em paralelo. Assim, temos E/S paralela sem que
o software saiba disso.
O RAD nível 0 funciona melhor com requisições grandes; quanto maiores, melhor. Se uma requisição for
maior do que o número de drives vezes o tamanho da tira, alguns drives receberão múltiplas requisições, de modo
que, quando terminam a primeira, iniciam a segunda. Cabe ao controlador dividir a requisição e alimentar os
comandos adequados aos discos adequados na sequência certa e então agrupar os resultados na memória corre-
tamente. O desempenho é excelente e a execução é direta.
O RAD nível 0 funciona pior com sistemas operacionais que costumam requisitar dados a um setor por vez.
Os resultados serão corretos, mas não há paralelismo e, por conseguinte, nenhum ganho de desempenho. Outra
desvantagem dessa organização é que a confiabilidade é potencialmente pior do que ter um SLED. Se um RAD
consistir em quatro discos, cada um com um tempo médio de falha de 20 mil horas, mais ou menos uma vez
a cada 5 mil horas um drive falhará e haverá perda total de dados. Um SLED com um tempo médio de falha de
20 mil horas seria quatro vezes mais confiável. Como não há nenhuma redundância presente nesse projeto, na
realidade ele não é um RAD verdadeiro.
A próxima opção, RAD nível 1, mostrada na Figura 2.23(b), é um RAD verdadeiro. Ele duplica todos os
discos, portanto, há quatro discos primários e quatro de backup. Para uma escrita, cada tira é escrita duas vezes.
Para uma leitura, qualquer das duas cópias pode ser usada, distribuindo a carga por mais drives. Por conseguinte,
o desempenho da escrita não é melhor do que o de um único drive, mas o de leitura pode ser duas vezes melhor.
A tolerância a falhas é excelente: se um drive falhar, basta usar a outra cópia em seu lugar. A recuperação consiste
na simples instalação de um novo drive e em copiar todo o drive de backup para ele.
Ao contrário dos níveis 0 e 1, que trabalham com tiras de setores, o RAD nível 2 trabalha por palavra, pos-
sivelmente até por byte. magine dividir cada byte do disco virtual único em um par de nibbles de 4 bits e então
acrescentar um código de Hamming a cada um para formar uma palavra de 7 bits, dos quais os bits 1, 2 e 4 fos-
sem de paridade. magine ainda que a posição do braço e a posição rotacional dos sete drives da Figura 2.23(c)
fossem sincronizadas. Então, seria possível escrever a palavra de 7 bits codificada por Hamming nos sete drives,
um bit por drive.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 75
Figura 2.23 RAIDs n
veis 0 a 5. Os drives de backup e paridade esta
o sombreados.
(a)
(b)
(c)
(d)
(e)
(f)
RAID nível 0
RAID nível 1
RAID nível 2
RAID nível 3
RAID nível 4
RAID nível 5
Tira 0 Tira 1 Tira 2 Tira 3
Tira 4 Tira 5 Tira 6 Tira 7
Tira 8 Tira 9 Tira 10 Tira 11
Tira 0 Tira 1 Tira 2 Tira 3
Tira 4 Tira 5 Tira 6 Tira 7
Tira 8 Tira 9 Tira 10 Tira 11
Tira 0 Tira 1 Tira 2 Tira 3
Tira 4 Tira 5 Tira 6 Tira 7
Tira 8 Tira 9 Tira 10 Tira 11
Bit 1 Bit 2 Bit 3 Bit 4 Bit 5 Bit 6 Bit 7
Bit 1 Bit 2 Bit 3 Bit 4 Paridade
Tira 0 Tira 1 Tira 2 Tira 3 P0-3
Tira 4 Tira 5 Tira 6 Tira 7 P4-7
Tira 8 Tira 9 Tira 10 Tira 11 P8-11
Tira 0 Tira 1 Tira 2 Tira 3 P0-3
Tira 4 Tira 5 Tira 6 P4-7 Tira 7
Tira 8 Tira 9 P8-11 Tira 10 Tira 11
Tira 12 P12-15 Tira 13 Tira 14 Tira 15
P16-19 Tira 16 Tira 17 Tira 18 Tira 19
O computador Thinking Machine CM-2 usava esse esquema, pegando palavras de 32 bits de dados e adicio-
nando 6 bits de paridade para formar uma palavra de Hamming de 38 bits, mais um bit extra para paridade de
palavra, e distribuindo cada palavra em 39 drives de disco. O rendimento total era imenso porque em um tempo
de setor ele podia escrever o equivalente a 32 setores de dados. Além disso, perder um drive não causava problemas,
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
76
porque essa perda equivaleria a perder 1 bit em cada palavra de 39 bits lida, algo que o código de Hamming
poderia manipular facilmente.
Uma desvantagem é que esse esquema requer que as rotações de todos os drives sejam sincronizadas, e isso
só faz sentido com um número substancial de drives (mesmo com 32 drives de dados e 6 drives de paridade, a
sobrecarga seria de 19%). O esquema também exige muito do controlador, uma vez que ele deve efetuar uma soma
de verificação (checksum) de Hamming a cada tempo de bit.
O RAD nível 3, ilustrado na Figura 2.23(d), é uma versão simplificada do RAD nível 2. Nesse arranjo, um
único bit de paridade é computado para cada palavra de dados e escrito em um drive de paridade. Como no RAD
nível 2, os drives devem estar em exata sincronia, uma vez que palavras de dados individuais estão distribuídas
por múltiplos drives.
À primeira vista, pode parecer que um único bit de paridade dá somente detecção de erro, e não correção de
erro. Para o caso de erros aleatórios não detectados, essa observação é verdadeira. Todavia, para o caso de uma
falha de drive, ela provê correção total de erros de 1 bit, uma vez que a posição do bit defeituoso é conhecida. Se
um drive falhar, o controlador apenas finge que todos os seus bits são 0s. Se uma palavra tiver um erro de parida-
de, o bit que vem de um drive extinto deve ter sido um 1, portanto, é corrigido. Embora ambos os RADs níveis 2
e 3 ofereçam taxas de dados muito altas, o número de requisições separadas de E/S por segundo que eles podem
manipular não é melhor do que o de um único drive.
RADs níveis 4 e 5 de novo trabalham com tiras, e não com palavras individuais com paridade, e não reque-
rem drives sincronizados. O RAD nível 4 [veja a Figura 2.23(e)] é como o RAD nível 0, com paridade tira por tira
escrita em um drive extra. Por exemplo, se cada tira tiver k bytes de comprimento, todas as tiras passam por uma
operação de ECLUSE OR, resultando em uma tira de paridade de k bytes de comprimento. Se um drive falhar,
os bytes perdidos podem ser recalculados com base no drive de paridade.
Esse projeto protege contra a perda de um drive, mas seu desempenho é medíocre para pequenas atualiza-
ções. Se um setor for alterado, é necessário ler todos os drives para recalcular a paridade que, então, precisará ser
reescrita. Como alternativa, ele pode ler os velhos dados de usuário e os velhos dados de paridade e recalcular
nova paridade, e partir deles. Mesmo com essa otimização, uma pequena atualização requer duas leituras e duas
escritas, o que é, claramente, um mau arranjo.
Como consequência da carga pesada sobre o drive de paridade, ele pode se tornar um gargalo. Esse gargalo
é eliminado no RAD nível 5 distribuindo os bits de paridade uniformemente por todos os drives, por alternância
circular, conforme mostra a Figura 2.23(f). Contudo, no evento de uma falha de drive, a reconstrução do drive
danificado é um processo complexo.
2.3.6 Discos em estado so
lido
Discos feitos de memória flash não volátil, geralmente denominados discos em estado sólido (SSs – Solid-
-State isks), estão ganhando mais popularidade como uma alternativa de alta velocidade às tecnologias tradicio-
nais em disco magnético. A invenção do SSD é uma história clássica de “Quando lhe oferecem limões, faça uma
limonada”. Embora a eletrônica moderna possa parecer totalmente confiável, a realidade é que os transistores
se desgastam lentamente à medida que são usados. Toda vez que eles comutam, se desgastam um pouco e ficam
mais perto de não funcionarem mais. Um modo provável de falha de um transistor é pela “injeção de portadora
quente”, um mecanismo de falha em que uma carga elétrica é embutida dentro de um transistor que funcionava,
deixando-o em um estado onde fica permanentemente ligado ou desligado. Embora em geral considerado senten-
ça de morte para um transistor (provavelmente) inocente, Fujio Masuoka, enquanto trabalhava para a Toshiba,
descobriu um modo de aproveitar esse mecanismo de falha para criar uma nova memória não volátil. No início
da década de 1980, ele inventou a primeira memória flash.
Os discos flash são compostos de muitas células de memória flash em estado sólido. As células da memó-
ria flash são feitas de um único transistor flash especial. Uma célula de memória flash aparece na Figura 2.24.
Embutido no transistor há uma porta flutuante que pode ser carregada e descarregada usando altas voltagens.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 77
Antes de ser programada, a porta flutuante não afeta a operação do transistor, atuando como um isolador extra
entre a porta de controle e o canal do transistor. Se a célula flash for testada, ela atuará como um transistor
simples.
Figura 2.24 Uma ce
lula de memo
ria flash.
12 V
Tensão de programação
Porta de controle
Isolador
Porta flutuante
Isolador
Carga negativa
interceptada
Ponta de teste Origem Canal Dreno
Semicondutor
Terra
Para programar uma célula de bit flash, uma alta tensão (no mundo dos computadores, 12  é uma alta
tensão) é aplicada à porta de controle, que acelera o processo de injeção de portadora quente na porta flutuante.
Os elétrons são embutidos na porta flutuante, que coloca uma carga negativa interna no transistor flash. A carga
negativa embutida aumenta a tensão necessária para ligar o transistor flash e, testando se o canal liga ou não com
uma tensão alta ou baixa, é possível determinar se a porta flutuante está carregada ou não, resultando em um valor
0 ou 1 para a célula flash. A carga embutida permanece no transistor, mesmo que o sistema perca a alimentação,
tornando a célula de memória flash não volátil.
isto que os SSDs são basicamente memória, eles possuem desempenho superior aos discos giratórios, com
tempo de busca zero. Enquanto um disco magnético típico pode acessar dados em até 100 MB/s, um SSD pode
operar duas a três vezes mais rápido. E como o dispositivo não possui partes móveis, ele é muito adequado para
uso em notebooks, onde trepidações e movimentos não afetarão sua capacidade de acessar dados. A desvantagem
dos SSDs, em comparação com discos magnéticos, é o seu custo. Enquanto os discos magnéticos custam centa-
vos de dólar por gigabyte, um SSD típico custará de um a três dólares por gigabyte, tornando seu uso apropriado
apenas para aplicações com drive menor ou em situações em que o custo não é um problema. O custo dos SSDs
está caindo, mas ainda há um longo caminho até que alcancem os discos magnéticos baratos. Assim, embora os
SSDs estejam substituindo os discos magnéticos em muitos computadores, talvez ainda leve um bom tempo antes
que o disco magnético siga o caminho dos dinossauros (a menos que outro grande meteoro atinja a Terra, mas
nesse caso nem os SSDs sobreviveriam).
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
78
Outra desvantagem dos SSDs em comparação com os discos magnéticos é sua taxa de falha. Uma célula flash
típica pode ser escrita somente por cerca de 100 mil vezes antes que não funcione mais. O processo de injetar elé-
trons na porta flutuante a danifica aos poucos, bem como seus isoladores ao redor, até que não funcione mais. Para
aumentar o tempo de vida dos SSDs, é usada uma técnica denominada nivelamento de desgaste, para espalhar as
escritas por todas as células flash no disco. Toda vez que um novo bloco de disco é escrito, o bloco de destino é rea-
tribuído a um novo bloco do SSD, que não foi escrito recentemente. sso exige o uso de um mapa de blocos lógicos
dentro do drive flash, que é um dos motivos pelos quais os drives flash possuem altos overheads de armazenamento
interno. Usando o nivelamento de desgaste, um drive flash pode dar suporte a uma quantidade de escritas igual ao
número de escritas que uma célula pode sustentar multiplicado pelo número de blocos no disco.
Alguns SSDs são capazes de codificar vários bits por byte, usando células flash multiníveis. A tecnologia
controla cuidadosamente a quantidade de carga colocada na porta flutuante. Uma sequência cada vez maior de
voltagens é então aplicada à porta de controle para determinar quanta carga é armazenada na flutuante. As células
multiníveis típicas admitem quatro níveis de carga, resultando em dois bits por célula flash.
2.3.7 CD-ROMs
Discos ópticos foram desenvolvidos na origem para gravar programas e televisão, mas podem ser utilizados
para uma função mais estética como dispositivos de armazenagem de computadores. Por sua grande capacidade
e baixo preço, discos óticos são muito usados para distribuir software, livros, filmes e dados de todos os tipos,
bem como para fazer backup de discos rígidos.
A primeira geração de discos óticos foi inventada pela Philips, conglomerado holandês de eletrônica, para
conter filmes. Tinham 30 cm de diâmetro e eram comercializados com a marca Laserision, mas não se estabe-
leceram, exceto no Japão.
Em 1980, a Philips, junto com a Sony, desenvolveu o CD (Compact Disc), que logo substituiu os discos
de vinil de 33 1/3 RPM usados para gravar música. Os dados técnicos exatos do CD foram publicados em um
Padrão nternacional (S 10149), popularmente conhecido como Red Book (livro vermelho) por causa da cor
de sua capa. (Padrões nternacionais são emitidos pela nternational Organization for Standardization, que é a
contraparte internacional de grupos de padronização nacionais como ABNT, ANS etc. Cada um tem um número
S.) O motivo da publicação das especificações do disco e do drive como um Padrão nternacional é permitir que
CDs de diferentes gravadoras e aparelhos de reprodução de diferentes fabricantes funcionem em conjunto. Todos
os CDs têm 120 mm de diâmetro 1,2 mm de espessura, com um orifício de 15 mm no meio. O CD de áudio foi o
primeiro meio de armazenagem digital a ter sucesso no mercado de massa. Supõe-se que devam durar cem anos.
Favor verificar em 2080 um relatório sobre como se saiu o primeiro lote.
Um CD é preparado com a utilização de um laser infravermelho de alta potência para queimar orifícios de
0,8 mícron de diâmetro em um disco mestre revestido de vidro. Com base nesse mestre é fabricado um molde,
com saliências onde estavam os orifícios de laser. Então, injeta-se policarbonato fundido nesse molde para for-
mar um CD com o mesmo padrão de orifícios do disco mestre revestido de vidro. Em seguida, é depositada uma
fina camada de alumínio refletivo sobre o policarbonato, coberta por um verniz de proteção e, por fim, vem uma
etiqueta. As marcas no substrato de policarbonato são denominadas depressões (pits) e as áreas entre elas são
denominadas planos (lands).
Quando o disco é tocado, um diodo a laser de baixa potência emite luz infravermelha de comprimento de
onda de 0,78 mícron sobre as depressões e planos quando estes passam pela luz. O laser está no lado do policarbo-
nato, portanto, as depressões estão invertidas na direção do laser e aparecem como saliências sobre uma superfície
que, caso contrário, seria plana. Como as depressões têm uma altura de um quarto do comprimento de onda da
luz de laser, a luz que se reflete de uma depressão tem uma defasagem de meio comprimento de onda em relação
à que se reflete das superfícies que a circundam. O resultado é que as duas partes interferem uma com a outra
de modo destrutivo e devolvem menos luz ao fotodetector do aparelho de reprodução do que a luz que se reflete
de um plano. É assim que o aparelho distingue uma depressão de um plano. Embora talvez pareça mais simples
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 79
usar uma depressão para gravar um 0 e um plano para gravar um 1, é mais confiável usar uma transição depressão/
plano ou plano/depressão para um 1 e sua ausência para um 0; portanto, esse é o esquema usado.
As depressões e os planos são escritos em uma única espiral contínua que começa perto do orifício central e
continua por uma distância de 32 mm em direção à borda. A espiral faz 22.188 rotações ao redor do disco (cerca
de 600 por mm). Se fosse desenrolada, teria 5,6 km de comprimento. A espiral é ilustrada na Figura 2.25.
Figura 2.25 Estrutura de gravac
a
o de um disco compacto ou CD-ROM.
Sulco em espiral
Bloco de 2 K de
dados de usuário
Depressão
Plano
Para fazer a música ser tocada a uma taxa uniforme, é preciso que as depressões e os planos passem sob a
luz a uma velocidade linear constante. Em consequência, a taxa de rotação deve ser continuamente reduzida
à medida que o cabeçote de leitura se move da parte interna para a externa do CD. Na parte interna, a taxa
de rotação é de 530 RPM para conseguir a taxa de reprodução regular de 120 cm/s; na parte mais externa,
tem de cair para 200 RPM para dar a mesma velocidade linear no cabeçote. Um drive de velocidade linear
constante é bem diferente de um drive de disco magnético, que funciona a uma velocidade angular constan-
te, independente de onde o cabeçote esteja posicionado naquele momento. Além disso, 530 RPM estão bem
longe das 3.600 a 7.200 RPM com as quais gira a maioria dos discos magnéticos.
Em 1984, a Philips e a Sony perceberam o potencial para usar CDs como meio de armazenagem de dados
de computadores, então, publicaram o Yellow Book (livro amarelo) definindo um padrão exato para o que agora
conhecemos como C-ROMs (Compact isc-Read Only Memory  disco compacto com memória somente de
leitura). Para pegar carona no mercado de CDs de áudio, que já era substancial na época, os CD-ROMs tinham o
mesmo tamanho físico dos CDs de áudio, guardavam compatibilidade mecânica e ótica com eles e eram produzi-
dos usando as mesmas máquinas de moldagem por injeção. As consequências dessa decisão foram a necessidade
de motores lentos de velocidade variável mas também que o custo de manufatura de um CD-ROM estivesse bem
abaixo de um dólar para um volume moderado.
O Yellow Book definiu a formatação dos dados de computador. Também melhorou as capacidades de cor-
reção de erro do sistema, um passo essencial porque, embora os apreciadores de música não se importassem em
perder um bit aqui, outro ali, os apreciadores de computadores tendiam a ser muito exigentes com isso. O formato
básico de um CD-ROM consiste em codificar cada byte em um símbolo de 14 bits. Como já vimos, 14 bits são
suficientes para codificar com Hamming um byte de 8 bits e ainda sobram 2. Na verdade, é usado um sistema de
codificação mais poderoso. O mapeamento 14 para 8 para leitura é realizado em hardware por consulta de tabela.
Do nível seguinte para cima, um grupo de 42 símbolos consecutivos forma um quadro de 588 bits. Cada
quadro contém 192 bits de dados (24 bytes). Os 396 bits restantes são usados para correção e controle de erro.
Até aqui, esse esquema é idêntico para CDs e CD-ROMs.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
80
O que o Yellow Book acrescenta é o agrupamento de 98 quadros em um setor de C-ROM, conforme
mostra a Figura 2.26. Cada setor de CD-ROM começa com um preâmbulo de 16 bytes, sendo os 12 primeiros
00FFFFFFFFFFFFFFFFFFFF00 (hexadecimal), para permitir que o aparelho de reprodução reconheça o início
de um setor de CD-ROM. Os 3 bytes seguintes contêm o número do setor, necessário porque fazer busca em um
CD-ROM com sua única espiral de dados é muito mais difícil do que em um disco magnético com suas trilhas
concêntricas uniformes. Para buscar, o software no drive calcula mais ou menos aonde ir, leva o cabeçote até lá e
então começa a procurar um preâmbulo para verificar a precisão do cálculo. O último bit do preâmbulo é o modo.
Figura 2.26 Layout lo
gico de dados em um CD-ROM.
…
…
Símbolos de
14 bits cada
42 símbolos formam 1 quadro
Quadros de 588 bits,
cada um contendo 24
bytes de dados
Preâmbulo 98 quadros formam 1 setor
Dados ECC
Bytes 16 2.048 288
Setor do
modo 1
(2.352 bytes)
O Yellow Book define dois modos. O modo 1 usa o layout da Figura 2.26, com um preâmbulo de 16 bytes,
2.048 bytes de dados e um código de correção de erro de 288 bytes (um código de Reed-Solomon de intercalação
cruzada). O modo 2 combina os dados e campos ECC em um campo de dados de 2.336 bytes para as aplicações
que não precisam de correção de erro (ou não dispõem de tempo para executá-la), como áudio e vídeo. Note que,
para oferecer excelente confiabilidade, são usados três esquemas separados de correção de erros: dentro de um
símbolo, dentro de um quadro e dentro de um setor de CD-ROM. Erros de único bit são corrigidos no nível mais
baixo, erros em rajada curtos são corrigidos no nível de quadro e quaisquer erros residuais são apanhados no nível
de setor. O preço pago por essa confiabilidade é que são necessários 98 quadros de 588 bits (7.203 bytes) para
transportar uma única carga útil de 2.048 bytes, uma eficiência de apenas 28%.
Drives de CD-ROM de uma velocidade operam a 75 setores/s, o que dá uma taxa de dados de 153.600 bytes/s
em modo 1 e 175.200 bytes/s em modo 2. Drives de dupla velocidade são duas vezes mais rápidos e assim por
diante, até a velocidade mais alta. Um CD padrão de áudio tem espaço para 74 minutos de música que, se usado
para dados do modo 1, dá uma capacidade de 681.984.000 bytes. Esse número costuma ser informado como 650
MB, pois 1 MB é igual a 220
bytes (1.048.576 bytes), e não 1 milhão de bytes.
Como é muito comum, sempre que surge uma nova tecnologia, algumas pessoas tentam desafiar os limites.
Ao projetar o CD-ROM, a Philips e a Sony foram cuidadosas e fizeram o processo de escrita parar bem antes que
a borda externa do disco fosse alcançada. Não levou muito tempo para que alguns fabricantes permitissem que
seus drives fossem além do limite oficial e chegassem perigosamente perto da borda física da mídia, gerando cerca
de 700 MB em vez de 650 MB. Porém, quando a tecnologia foi aperfeiçoada e os discos vazios foram fabricados
com um padrão mais alto, 703,12 MB (360 mil setores de 2.048 bytes, em vez de 333 mil setores) se tornaram a
nova norma.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 81
Note que mesmo um drive de CD-ROM 32x (4.915.200 bytes/s) não é páreo para o drive de disco magnético
Fast SCS-2 a 10 MB/s. Quando você se der conta de que o tempo de busca muitas vezes é de várias centenas
de milissegundos, deve ficar claro que os drives de CD-ROM não estão de forma alguma na mesma categoria de
desempenho dos drives de disco magnético, a despeito de sua grande capacidade.
Em 1986, a Philips atacou mais uma vez com o Green Book (livro verde), acrescentando recursos gráficos
e a capacidade de intercalar áudio, vídeo e dados no mesmo setor, uma característica essencial para CD-ROMs
multimídia.
A última peça do quebra-cabeça do CD-ROM é o sistema de arquivos. Para possibilitar a utilização
do mesmo CD-ROM em diferentes computadores, era preciso chegar a um acordo quanto aos sistemas de
arquivos em CD-ROM. Para conseguir esse acordo, representantes de muitas empresas fabricantes de com-
putadores se reuniram em Lake Tahoe, nas High Sierras, na fronteira Califórnia-Nevada, e arquitetaram um
sistema de arquivos que denominaram High Sierra. Mais tarde, ele evoluiu para um Padrão nternacional (S
9660). O sistema tem três níveis. O nível 1 usa nomes de arquivo de até 8 caracteres e podem ser seguidos
de uma extensão de até 3 caracteres (a convenção de nomeação de arquivos do MS-DOS). Nomes de arquivos
só podem conter letras maiúsculas, dígitos e o caractere de sublinhado. Diretórios podem ser aninhados até
oito, mas nomes de diretórios não podem conter extensões. O nível 1 requer que todos os arquivos sejam
contíguos, o que não é problema para um meio que é escrito apenas uma vez. Qualquer CD-ROM que obe-
deça ao S 9660 nível 1 pode ser lido usando MS-DOS, um computador Apple, um computador UN ou
praticamente qualquer outro computador. Os fabricantes de CD-ROMs consideram essa propriedade uma
grande vantagem.
O S 9660 nível 2 permite nomes de até 32 caracteres e o nível 3 permite arquivos não contíguos. As exten-
sões Rock Ridge (o nome extravagante se deve à cidade em que Mel Brooks filmou Blazing Saddles [Banzé no
Oeste]) permitem nomes muito longos (para UN), UDs, GDs, e enlaces simbólicos, mas os CD-ROMs que
não obedecem ao nível 1 não poderão ser lidos em todos os computadores.
2.3.8 CDs grava
veis
De início, o equipamento necessário para produzir um CD-ROM mestre (ou CD de áudio, por falar nisso)
era muito dispendioso. Mas, como sempre acontece na indústria de computadores, nada permanece caro por
muito tempo. Em meados da década de 1990, gravadores de CD não maiores do que um reprodutor de CD eram
um periférico comum disponível na maioria das lojas de computadores. Esses dispositivos ainda eram diferentes
dos discos magnéticos porque, uma vez gravados, os CD-ROMs não podiam ser apagados. Ainda assim, eles logo
encontraram um nicho como um meio de backup para grandes discos rígidos magnéticos e também permitiram
que indivíduos ou novas empresas fabricassem seus próprios CD-ROMs em pequena escala ou produzissem mes-
tres para fornecer a empresas comerciais de reprodução de grandes volumes de CDs. Esses drives são conhecidos
como C-Rs (C-Recordables  Cs graváveis).
Os CD-Rs começaram com discos em branco de policarbonato de 120 mm de diâmetro que são como
CD-ROMs, exceto por conterem um sulco de 0,6 mm de largura para guiar o laser durante a escrita (gravação). O
sulco tem um desvio senoidal de 0,3 mm a uma frequência de exatos 22,05 kHz para prover realimentação contí-
nua, de modo que a rotação possa ser monitorada e ajustada com precisão, caso necessário. Os primeiros CD-Rs
pareciam CD-ROMs normais, exceto por terem a superfície superior dourada, e não prateada. Essa cor vinha da
utilização de ouro verdadeiro em vez de alumínio na camada refletiva. Diferente dos CDs prateados que conti-
nham depressões físicas, nos CD-Rs as diferentes refletividades das depressões e dos planos têm de ser simuladas.
sso é feito com a adição de uma camada de corante entre o policarbonato e a superfície refletiva, como mostra a
Figura 2.27. São usadas duas espécies de corantes: cianina, que é verde, e ftalocianina, que é amarelo-alaranjada.
Os químicos podem discutir eternamente sobre qual das duas é melhor. Com o tempo, a camada refletiva dourada
foi substituída por uma camada de alumínio.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
82
Figura 2.27 Sec
a
o transversal de um disco CD-R e laser (na
o esta
 em escala). Um CD-ROM tem estrutura semelhante, exceto por na
o ter
a camada de corante e por ter uma camada de alum
nio cheia de depresso
es em vez de uma camada refletiva.
Etiqueta impressa
Verniz protetor
Camada refletiva
Ponto escuro na camada
de corante queimado
pelo laser durante a
escrita
Camada de corante
Policarbonato Substrato
Direção de
movimento Lente
Fotodetector Prisma
Diodo de laser
infravermelho
Em seu estágio inicial, a camada de corante é transparente e permite que a luz do laser que a atravessa seja
refletida pela camada refletiva. Para gravar (escrever), o laser CD-R é ligado em alta potência (8–16 mW). Quando
o feixe atinge uma porção do corante, ele o aquece e rompe a ligação química. Essa alteração da estrutura mole-
cular cria um ponto escuro. Quando o CD-R é lido (a 0,5 mW), o fotodetector vê uma diferença entre os pontos
escuros onde o corante foi atingido e as áreas transparentes onde o disco está intacto. Essa diferença é interpretada
como a diferença entre depressões e planos, mesmo quando lidas por um leitor de CD-ROM normal ou até mesmo
por um reprodutor de CD de áudio.
Nenhum tipo novo de CD poderia se firmar com orgulho sem ter um livro colorido, portanto, o CD-R tem
o Orange Book (livro laranja), publicado em 1989. Esse documento define o CD-R e também um novo formato,
o C-ROM X, que permite que os CD-Rs sejam gravados por incrementos, alguns setores hoje, outros amanhã
e mais alguns no próximo mês. Um grupo de setores consecutivos escritos de uma só vez é denominado trilha
de C-ROM.
Um dos primeiros usos do CD-R foi no PhotoCD da Kodak. Nesse sistema, o cliente leva ao processador
de fotos um rolo de filme exposto e seu velho PhotoCD, e recebe de volta o mesmo PhotoCD com novas fotos
acrescentadas às antigas. O novo lote, que é criado por digitalização dos negativos, é gravado no PhotoCD como
uma trilha de CD-ROM separada. A gravação incremental é necessária porque os CD-Rs virgens são muito caros
para se ter um novo para cada rolo de filme.
Contudo, a gravação incremental cria um novo problema. Antes do Orange Book, todos os CD-ROMs
tinham, no início, uma única VOC (Volume able of Contents – sumário de conteúdo de volumes). Esse
esquema não funciona com escritas incrementais (isto é, multitrilhas). A solução do Orange Book é dar a cada
trilha de CD-ROM sua própria TOC. Os arquivos listados na TOC podem incluir alguns ou todos os arquivos
de trilhas anteriores. Após a inserção do CD-R no drive, o sistema operacional faz uma busca em todas as trilhas
do CD-ROM para localizar a TOC mais recente, que dá o estado atual do disco. Por incluir alguns, mas não
todos os arquivos de trilhas anteriores na TOC corrente, é possível dar uma ilusão de que os arquivos foram
apagados. As trilhas podem ser agrupadas em sessões, o que resulta em CD-ROMs multissessões. Reprodutores
de CD de áudio padrão não podem manipular CDs multissessões, já que esperam uma única TOC no início.
1,2 mm
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 83
O CD-R possibilita que indivíduos e empresas copiem CD-ROMs (e CDs de áudio) com facilidade, em geral com
a violação dos direitos autorais do editor. ários esquemas já foram inventados para dificultar esse tipo de pirataria e
também a leitura de um CD-ROM usando qualquer outra coisa que não seja o software do editor. Um deles envolve
gravar todos os comprimentos de arquivos do CD-ROM como multigigabyte, frustrando quaisquer tentativas de
copiar os arquivos para disco rígido com a utilização de software de cópia padrão. Os verdadeiros comprimentos estão
embutidos no software do editor ou ocultos (possivelmente criptografados) no CD-ROM em um lugar não esperado.
Outro esquema usa intencionalmente ECCs incorretos em setores selecionados, na esperança de que o software de
cópia de CDs “corrija” os erros. O software de aplicação verifica os ECCs e se recusa a funcionar se estiverem “corri-
gidos”. Usar lacunas não padronizadas entre trilhas e outros “defeitos” físicos também são possibilidades.
2.3.9 CDs regrava
veis
Embora todos estejam acostumados com outras mídias que aceitam apenas uma escrita, como papel
fotográfico, existe uma demanda por CD-ROMs regraváveis. Uma tecnologia disponível agora é o C-RW
(C-ReWritable  Cs regraváveis), que usa um meio do mesmo tamanho do CD-R. Contudo, em vez dos
corantes cianina ou ftalocianina, o CD-RW usa uma liga de prata, índio, antimônio e telúrio para a camada de
gravação. Essa liga tem dois estados estáveis: cristalino e amorfo, com diferentes refletividades.
Os drives de CD-RW usam lasers com três potências diferentes. Em alta potência, o laser funde a liga fazendo-
-a passar do estado cristalino de alta refletividade para o estado amorfo de baixa refletividade, para representar
uma depressão. Em potência média, a liga se funde e volta a seu estado natural cristalino para se tornar novamente
um plano. Em baixa potência, o estado do material é sondado (para leitura), mas não ocorre qualquer transição
de fase.
A razão por que o CD-RW não substituiu completamente o CD-R é que os CD-RWs em branco são mais
caros do que os CD-Rs em branco. Além disso, para aplicações de backup de discos rígidos, o fato de que, uma
vez escrito, o CD não possa ser apagado acidentalmente, é uma grande vantagem, e não um bug.
2.3.10 DVD
O formato básico do CD/CD-ROM está na praça desde 1980. Em meados da década de 1990, a tecnologia
melhorou bastante, de modo que discos ópticos de capacidade mais alta se tornaram economicamente viáveis. Ao
mesmo tempo, Hollywood estava procurando um meio de substituir as fitas analógicas de videoteipe por discos
digitais, pois estes têm qualidade mais alta, são mais baratos de fabricar, duram mais, ocupam menos espaço nas
prateleiras das locadoras de vídeo e não precisam ser rebobinados. Estava parecendo que a roda do progresso para
os discos óticos estava para girar mais uma vez.
Essa combinação de tecnologia e demanda por três indústrias imensamente ricas e poderosas resultou no
V, na origem um acrônimo para igital Video isk (disco de vídeo digital), mas agora oficialmente igital
Versatile isk (disco versátil digital). DDs usam o mesmo desenho geral dos CDs, com discos de policarbonato
de 120 mm moldados por injeção que contêm depressões e planos iluminados por um diodo de laser e lidos por
um fotodetector. A novidade é o uso de
1. Depressões menores (0,4 mícron versus 0,8 mícron para CDs).
2. Uma espiral mais apertada (0,74 mícron entre trilhas versus 1,6 mícron para CDs).
3. Um laser vermelho (a 0,65 mícron versus 0,78 mícron para CDs).
Juntas, essas melhorias aumentam sete vezes a capacidade, passando para 4,7 GB. Um drive de DD 1x
funciona a 1,4 MB/s (versus 150 KB/s para CDs). nfelizmente, a troca para lasers vermelhos usados em supermer-
cados significa que os reprodutores de DD precisarão de um segundo laser para poder ler os CDs e CD-ROMs
existentes, aumentando um pouco de complexidade e custo.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
84
Uma capacidade de 4,7 GB é suficiente? Talvez. Usando compressão MPEG-2 (padronizada no S 13346),
um disco DD de 4,7 GB pode conter 133 minutos de vídeo de tela cheia com imagens em movimento em alta
resolução (720 × 480), bem como trilhas sonoras em até oito idiomas e legendas em mais 32. Cerca de 92% de
todos os filmes que Hollywood já produziu têm menos de 133 minutos. Não obstante, algumas aplicações, como
jogos multimídia ou obras de referência, talvez precisem mais, e Hollywood gostaria de gravar vários filmes em
um mesmo disco, portanto, quatro formatos foram definidos:
1. Uma face, uma camada (4,7 GB).
2. Uma face, duas camadas (8,5 GB).
3. Duas faces, uma camada (9,4 GB).
4. Duas faces, duas camadas (17 GB).
Por que tantos formatos? Em uma palavra: política. A Philips e a Sony queriam discos de uma única face
com duas camadas para a versão de alta capacidade, mas a Toshiba e a Time Warner queriam discos de duas faces,
com uma camada. A Philips e a Sony não imaginaram que as pessoas estariam dispostas a virar os discos, e a
Time Warner não acreditava que colocar duas camadas em uma face poderia funcionar. A solução de conciliação:
todas as combinações, mas o mercado determinará quais sobreviverão. Bem, o mercado falou. A Philips e a Sony
estavam certas. Nunca aposte contra a tecnologia.
A tecnologia da camada dupla tem uma camada refletiva embaixo, coberta por uma semirrefletiva. Dependendo
de onde o laser for focalizado, ele se reflete de uma camada ou da outra. A camada inferior precisa de depressões e
planos um pouco maiores, para leitura confiável, portanto, sua capacidade é um pouco menor do que a da superior.
Discos de dupla face são fabricados colando dois discos de uma face de 0,6 mm. Para que todas as versões
tenham a mesma espessura, um disco de uma face consiste em um disco de 0,6 mm colado a um substrato em
branco (ou, talvez, no futuro, contendo 133 minutos de propaganda, na esperança de que as pessoas ficarão curio-
sas de saber o que existe lá dentro). A estrutura do disco de dupla face, dupla camada, é ilustrada na Figura 2.28.
Figura 2.28 Disco de DVD de dupla face, dupla camada.
Camada semirrefletiva
Refletor de alumínio
Refletor de alumínio
Camada semirrefletiva
Disco de
uma face
de 0,6 mm
Disco de
uma face
de 0,6 mm
Substrato de policarbonato 1
Camada adesiva
Substrato de policarbonato 2
O DD foi arquitetado por um consórcio de dez fabricantes de eletrônicos de consumo, sete deles japone-
ses, em estreita colaboração com os principais estúdios de Hollywood (alguns dos quais são de propriedade dos
fabricantes de eletrônicos japoneses pertencentes ao consórcio). As empresas de computadores e telecomunica-
ções não foram convidadas para o piquenique e o foco resultante foi o uso do DD para locação de filmes. Por
exemplo, entre as características padrão está a capacidade de saltar cenas impróprias em tempo real (o que per-
mite que os pais transformem um filme proibido para menores de 18 anos em um filme que possa ser visto por
criancinhas), seis canais de som e suporte para Pan-and-Scan. Essa última característica permite que o tocador
de DD decida dinamicamente como recortar as extremidades direita e esquerda dos filmes (cuja relação largura/
altura é 3:2) para que se ajustem aos tamanhos das telas de aparelhos de televisão atuais (cuja relação é 4:3).
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 85
Outro item em que a indústria de computadores provavelmente não teria pensado é uma incompatibilidade
intencional entre discos destinados aos Estados Unidos e discos destinados à Europa, e ainda outros padrões para outros
continentes. Hollywood exigiu essa “característica” porque filmes novos são sempre lançados antes nos
Estados Unidos e então despachados para a Europa quando os vídeos começam a sair do circuito comercial nos
Estados Unidos. A ideia era garantir que as locadoras de vídeo não pudessem comprar vídeos nos Estados Unidos
muito cedo, o que reduziria as receitas de filmes novos nos cinemas da Europa. Se Hollywood estivesse no con-
trole na indústria de computadores, teríamos disquetes de 3,5 polegadas nos Estados Unidos e disquetes de 9 cm
na Europa.
2.3.11 Blu-ray
Nada fica parado no negócio de computadores, certamente não na tecnologia de armazenagem. O DD mal
acabara de ser lançado e seu sucessor já ameaçava torná-lo obsoleto. O sucessor do DD é o Blu-ray (raio azul),
assim chamado porque usa um laser azul, em vez do vermelho usado por DDs. Um laser azul tem comprimento
de onda mais curto do que o laser vermelho, o que permite um foco mais preciso e, portanto, depressões e pla-
nos menores. Discos Blu-ray de uma face contêm cerca de 25 GB de dados; os de dupla face contêm cerca de 50
GB. A taxa de dados é mais ou menos 4,5 MB/s, o que é bom para um disco óptico, mas ainda insignificante em
comparação com discos magnéticos (cf. ATAP-6 a 100 MB/s e wide Ultra5 SCS a 640 MB/s). Espera-se que, com
o tempo, o Blu-ray substitua CD-ROMs e DDs, mas essa transição ainda levará alguns anos.
2.4 Entrada/Sa
da
Como mencionamos no início deste capítulo, um sistema de computador tem três componentes principais:
a CPU, as memórias (primária e secundária) e os equipamentos de E/S (entrada/saída), ou I/O (nput/Output),
como impressoras, scanners e modems. Até aqui, só examinamos CPU e as memórias. Agora, é hora de examinar
os equipamentos de E/S e como eles estão conectados ao restante do sistema.
2.4.1 Barramentos
A maioria dos computadores pessoais e estações de trabalho tem uma estrutura semelhante à mostrada
na Figura 2.29. O arranjo comum é um gabinete de metal que contém uma grande placa de circuito impresso na
parte inferior, denominada placa-mãe (ou placa-pai, para os que preferirem). A placa-mãe contém o chip da CPU,
alguns encaixes para os módulos DMM e vários chips de suporte. Contém também um barramento ao longo do
comprimento e soquetes nos quais os conectores de borda das placas de E/S podem ser inseridos.
Figura 2.29 Estrutura f
sica de um computador pessoal.
Controlador SCSI
Placa de som
Modem
Gabinete
Conector de borda
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
86
A estrutura lógica de um computador pessoal simples pode ser vista na Figura 2.30. Esse computador tem um
único barramento para conectar a CPU, a memória e os equipamentos de E/S; a maioria dos sistemas tem dois ou
mais barramentos. Cada dispositivo de E/S consiste em duas partes: uma que contém grande parte da eletrônica,
denominada controlador, outra que contém o dispositivo de E/S em si, tal como um drive de disco. O controlador
está em geral contido em uma placa que é ligada a um encaixe livre. Mesmo o monitor não sendo opcional, o con-
trolador de vídeo às vezes está localizado em uma placa de encaixe (plug-in) para permitir que o usuário escolha
entre placas com ou sem aceleradores gráficos, memória extra e assim por diante. O controlador se conecta com
seu dispositivo por um cabo ligado ao conector na parte de trás do gabinete.
Figura 2.30 Estrutura lo
gica de um computador pessoal simples.
Monitor
Teclado
Drive de
CD-ROM
Drive de
disco rígido
CPU Memória
Controlador
de vídeo
Controlador
de teclado
Controlador
de
CD-ROM
Controlador
de disco
rígido
Barramento
A função de um controlador é controlar seu dispositivo de E/S e manipular para ele o acesso ao barramento.
Quando um programa quer dados do disco, por exemplo, ele envia um comando ao controlador de disco, que
então emite comandos de busca e outros comandos para o drive. Quando a trilha e o setor adequados forem loca-
lizados, o drive começa a entregar dados ao controlador como um fluxo serial de bits. É função do controlador
dividir o fluxo de bits em unidades e escrever cada uma delas na memória, à medida que seja montada. Uma
unidade típica é composta de uma ou mais palavras. Quando um controlador lê ou escreve dados de ou para
a memória sem intervenção da CPU, diz-se que ele está executando acesso direto à memória (irect Memory
ccess), mais conhecido por seu acrônimo M. Concluída a transferência, o controlador normalmente causa
uma interrupção, forçando a CPU a suspender de imediato o programa em execução e começar a rodar um proce-
dimento especial, denominado rotina de interrupção, para verificar erros, executar qualquer ação especial neces-
sária e informar ao sistema operacional que a E/S agora está concluída. Quando a rotina de interrupção conclui
sua tarefa, a CPU continua com o programa que foi suspenso quando ocorreu a interrupção.
O barramento não é usado apenas pelos controladores de E/S, mas também pela CPU para buscar instruções
e dados. O que acontece se a CPU e um controlador de E/S quiserem usar barramento ao mesmo tempo? A res-
posta é que um chip, denominado árbitro de barramento, decide o que acontece em seguida. Em geral, é dada a
preferência aos dispositivos de E/S sobre a CPU, porque discos e outros dispositivos que estão em movimento não
podem ser interrompidos, e obrigá-los a esperar resultaria em perda de dados. Quando não há nenhuma E/S em
curso, a CPU pode ficar com todos os ciclos do barramento para si própria, para referenciar a memória. Contudo,
quando algum dispositivo de E/S também estiver executando, ele requisitará e terá acesso ao barramento sempre
que precisar. Esse processo é denominado roubo de ciclo, e reduz a velocidade do computador.
Esse projeto funcionou bem para os primeiros computadores pessoais, já que todos os componentes estavam
em certo equilíbrio. Contudo, à medida que CPUs, memórias e dispositivos de E/S ficavam mais rápidos, surgiu
um problema: o barramento não dava mais conta da carga apresentada. Em um sistema fechado, tal como uma
estação de trabalho de engenharia, a solução foi projetar um novo barramento mais rápido para o próximo modelo.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 87
Como ninguém nunca passava dispositivos de E/S de um modelo antigo para um novo, essa abordagem
funcionou bem.
Todavia, no mundo do PC, quem passava para uma CPU mais potente muitas vezes queria levar sua impres-
sora, scanner e modem para o novo sistema. Além disso, tinha-se desenvolvido uma imensa indústria destinada a
fornecer uma ampla gama de dispositivos de E/S para o barramento do BM PC, e essa indústria não estava nem
um pouco interessada em perder todo seu investimento e começar de novo. A BM aprendeu isso do modo mais
difícil quando lançou o sucessor do BM PC, a linha PS/2. O PS/2 tinha um barramento novo e mais rápido, mas
a maioria dos fabricantes de clones continuava a usar o antigo barramento do PC, agora denominado barramento
IS (Industry Standard rchitecture). A maioria dos fabricantes de discos e dispositivos de E/S continuou a
fabricar controladores para ele, e a BM se viu enfrentando a peculiar situação de ser a única fabricante de PCs
que não eram mais compatíveis com o PC da BM. Com o tempo, a empresa foi forçada a dar suporte ao barra-
mento SA. Hoje, o barramento SA é usado em sistemas legados e em museus de computador, pois foi substitu-
ído por arquiteturas de barramento padrão mais novas e mais rápidas. Como um comentário à parte, favor notar
que SA quer dizer nstruction Set Architecture (arquitetura do conjunto de instruções) no contexto de níveis
de máquina, ao passo que no contexto de barramentos quer dizer ndustry Standard Architecture (arquitetura
padrão da indústria).
Os barramentos PCI e PCIe
Não obstante, a despeito da pressão do mercado para que nada mudasse, o antigo barramento era mesmo
muito lento, portanto, era preciso fazer algo. Essa situação levou outras empresas a desenvolver máquinas com
múltiplos barramentos, um dos quais era o antigo barramento SA, ou seu sucessor compatível, o EIS (Extended
IS  IS estendido). Agora, o mais popular deles é o barramento PCI (Peripheral Component Interconnect
 interconexão de componentes periféricos). Esse barramento foi projetado pela ntel, mas a empresa decidiu
passar todas as patentes para domínio público, a fim de incentivar toda a indústria (incluindo seus concorrentes)
a adotá-lo.
O barramento PC pode ser usado em muitas configurações, mas a Figura 2.31 ilustra uma configuração
típica. Nesse caso, a CPU se comunica com um controlador de memória por meio de uma conexão dedicada, de
alta velocidade. O controlador se comunica diretamente com a memória e com o barramento PC, de modo que
o tráfego CPU-memória não passa pelo barramento PC. Outros periféricos podem ser conectados diretamente
ao barramento PC. Uma máquina com esse projeto teria dois ou três conectores PC vazios, permitindo que os
clientes conectem placas de E/S PC para novos periféricos.
Qualquer que seja a velocidade de algo no mundo da computação, muita gente acha que ela é baixa. Esse
destino também caiu sobre o barramento PC, que está sendo substituído pelo PCI Express, abreviado como
PCIe. A maior parte dos computadores modernos tem suporte para ele, de modo que os usuários podem conectar
dispositivos novos e velozes ao barramento PCe e os mais antigos e mais lentos ao barramento PC.
Figura 2.31 PC t
pico montado em torno do barramento PCI. O controlador SCSI e
 um dispositivo PCI.
cache
CPU
Cache
Ponte
para PCI
Barramento PCI
Controlador
de rede
Controlador
de vídeo
Controlador
SCSI
Disco
SCSI
Scanner
SCSI
Barramento
SCSI
Memória
principal
Barramento de memória
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
88
Enquanto o barramento PC foi apenas uma atualização para o SA mais antigo, com velocidades mais altas
e mais bits transferidos em paralelo, o PCe representa uma mudança radical do PC. Na verdade, ele sequer é
um barramento. É uma rede ponto a ponto usando linhas de bits seriais e troca de pacotes, mais parecido com a
nternet do que com um barramento tradicional. Sua arquitetura aparece na Figura 2.32.
Figura 2.32 Exemplo de arquitetura de um sistema PCIe com tre
s portas PCIe.
CPU
Cache
Memória
Complexo raiz
Porta 1 Porta 2 Porta 3
Dispositivo
PCIe
Switch
Dispositivo
PCIe
Ponte para PCI
Barramento PCI
Dispositivo
PCIe
Dispositivo
PCIe
Dispositivo
PCIe
Dispositivo
PCIe
árias coisas se destacam de imediato sobre o PCe. Primeiro, as conexões entre os dispositivos são seriais,
ou seja, 1 bit de largura em vez de 8, 16, 32 ou 64 bits. Embora se possa pensar que uma conexão de 64 bits teria
uma largura de banda mais alta do que uma conexão de 1 bit, na prática, as diferenças no tempo de propagação
dos 64 bits, chamadas de skew (distorção), significa que precisam ser usadas velocidades relativamente baixas.
Com uma conexão serial, velocidades muito mais altas podem ser usadas, e isso compensa bastante a perda de
paralelismo. Os barramentos PC trabalham com uma taxa de clock máxima de 66 MHz. Com 64 bits transferidos
por ciclo, a taxa de dados é de 528 MB/s. Com uma taxa de clock de 8 GHz, até mesmo com transferência serial, a
taxa de dados do PCe é de 1 GB/s. Além do mais, os dispositivos não estão limitados a um único par de fios para
se comunicarem com o complexo raiz ou com um switch. Um dispositivo pode ter até 32 pares de fios, chamados
de lanes (pistas). Essas pistas não são síncronas, de modo que a distorção não é importante aqui. A maioria das
placas-mãe tem um encaixe de 16 pistas para a placa gráfica, que no PCe 3.0 dará à placa gráfica uma largura
de banda de 16 GB/s, cerca de 30 vezes mais rápida do que uma placa gráfica PC pode oferecer. Essa largura de
banda é necessária para aplicações cada vez mais exigentes, como gráficos em 3D.
Segundo, toda a comunicação é ponto a ponto. Quando a CPU quer falar com um dispositivo, ela lhe envia
um pacote e, em geral, recebe uma resposta depois. O pacote passa pelo complexo raiz, que está na placa-mãe,
e depois para o dispositivo, possivelmente por um switch (ou, se o dispositivo for um PC, por uma ponte para
PC). Essa evolução de um sistema em que todos os dispositivos escutavam o mesmo barramento para um que
utiliza comunicações ponto a ponto é semelhante ao desenvolvimento das redes Ethernet (uma rede local muito
popular), que também começou com um canal de broadcast, mas agora utiliza switches para permitir a comuni-
cação ponto a ponto.
2.4.2 Terminais
Há muitos tipos de dispositivos de E/S disponíveis. Alguns dos mais comuns são discutidos a seguir. Terminais
de computador consistem em duas partes: um teclado e um monitor. No mundo dos mainframes, essas partes
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 89
costumam ser integradas em um único dispositivo ligado ao computador principal por uma linha serial ou por
uma linha telefônica. Nos setores de reserva de passagens aéreas, bancário e em outros setores que usam mainfra-
mes, esses dispositivos ainda estão sendo usados. No mundo dos computadores pessoais, o teclado e o monitor
são dispositivos independentes. Qualquer que seja o caso, a tecnologia das duas partes é a mesma.
Teclados
Há uma grande variedade de teclados. O BM PC original vinha com um teclado munido de um contato
mecânico sob cada tecla, que dava retorno tátil e emitia um clique quando a tecla era apertada corretamente. Hoje,
os teclados mais baratos têm teclas que fazem apenas contato mecânico quando acionados. Os melhores têm uma
lâmina de material elastométrico – espécie de borracha – entre as teclas e a placa de circuito impresso que está
por baixo. Sob cada tecla há uma pequena saliência que cede quando pressionada corretamente. Um pontinho
de material condutor dentro da saliência fecha o circuito. Alguns teclados têm um ímã sob cada tecla, que passa
por uma bobina quando pressionado, induzindo assim a uma corrente que pode ser detectada. Também há vários
outros métodos em uso, mecânicos e eletromagnéticos.
Em computadores pessoais, quando uma tecla é pressionada, uma interrupção é gerada e a rotina de inter-
rupções do teclado (uma parte do software do sistema operacional) é executada. A rotina de interrupções lê um
registrador de hardware dentro do controlador de teclado para pegar o número da tecla (1 a 102) que acabou de
ser pressionada. Quando a tecla é solta, ocorre uma segunda interrupção. Assim, se um usuário pressionar SHFT,
e em seguida pressionar e soltar M, e depois soltar SHFT, o sistema operacional pode ver que o usuário quer um
“M”, e não um “m”. O tratamento de sequências de várias teclas envolvendo SHFT, CTRL e ALT é todo feito em
software (incluindo a abominável sequência CTRL-ALT-DEL, que é usada para reiniciar PCs).
Touch screens
Embora os teclados não ofereçam perigo de atrapalhar a máquina de escrever manual, há um novo sujeito
na praça quando se trata de entrada do computador: uma touch screen (tela sensível ao toque). Embora esses
dispositivos só tenham se tornado itens do mercado de massa com a introdução do iPhone da Apple em 2007,
eles são muito mais antigos. A primeira tela sensível ao toque foi desenvolvida no Royal Radar Establishment, em
Malvern, Grã-Bretanha, em 1965. Até mesmo a capacidade de encolhimento na tela, tão anunciada pelo iPhone,
vem do trabalho inicial na Universidade de Toronto em 1982. Desde então, muitas tecnologias diferentes foram
desenvolvidas e comercializadas.
Dispositivos de toque podem ser encontrados em duas categorias: opacos e transparentes. Um dispositivo
sensível ao toque opaco é o touchpad de um notebook. Um dispositivo transparente típico é a tela de um smart-
phone ou tablet. amos analisar apenas o segundo. Eles costumam ser chamados de touch screens. Os principais
tipos de touch screens são infravermelho, resistivo e capacitivo.
As telas infravermelhas são transmissores de infravermelho, como os diodos ou lasers emissores de luz
infravermelha (por exemplo) nas bordas esquerda ou superior do engaste em torno da tela e detectores nas
bordas direita e inferior. Quando um dedo, caneta ou qualquer objeto opaco bloqueia um ou mais raios, o
detector correspondente sente a queda no sinal e o hardware do dispositivo pode dizer ao sistema operacional
quais raios foram bloqueados, permitindo que ele calcule a coordenadas (x, y) do dedo ou caneta. Embora
esses dispositivos já tenham sido usados há algum tempo em quiosques e outras aplicações, eles não usados
para dispositivos móveis.
Outra tecnologia antiga consiste em touch screens resistivas. Estas consistem em duas camadas, sendo a
superior flexível. Ela contém uma grande quantidade de fios horizontais. A inferior contém fios verticais. Quando
um dedo ou outro objeto pressiona um ponto na tela, um ou mais dos fios entra em contato com os fios perpen-
diculares na camada inferior. Os circuitos eletrônicos do dispositivo possibilitam a leitura de qual área foi pres-
sionada. Essas telas não são caras para se montar, e são muito usadas em aplicações mais simples.
As duas tecnologias são boas quando a tela é pressionada por um dedo, mas têm um problema quando dois
dedos são usados. Para descrever a questão, usaremos a terminologia da touch screen infravermelha, mas a resistiva
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
90
tem a mesma dificuldade. magine que os dois dedos estejam em (3, 3) e (8, 8). Como resultado, os feixes verti-
cais x = 3 e x = 8 são interrompidos, assim como os feixes horizontais y = 3 e y = 8. Agora, imagine um cenário
diferente, com os dedos em (3, 8) e (8, 3), que são os cantos opostos do retângulo cujos ângulos são (3, 3), (8,
3), (8, 8) e (3, 8). Exatamente os mesmos feixes são bloqueados, de modo que o software não sabe qual dos dois
cenários é o correto. Esse problema é conhecido como ghosting.
Para poder detectar vários dedos ao mesmo tempo – uma propriedade exigida para os gestos de encolhimento
e expansão –, uma nova tecnologia foi necessária. Aquela usada na maioria dos smartphones e tablets (mas não em
câmeras digitais e outros dispositivos) é a touch screen capacitiva projetada. Existem vários tipos, mas o mais comum
é o tipo de capacitância mútua. Todas as touch screens que podem detectar dois ou mais pontos de contato ao
mesmo tempo são conhecidas como telas multitoque. ejamos rapidamente como elas funcionam.
Para os leitores que estão meio enferrujados em sua física do colégio, um capacitor é um dispositivo que
pode armazenar carga elétrica. Um capacitor simples tem dois condutores separados por um isolador. Nas touch
screens modernas, um padrão tipo grande com “fios” finos correndo verticalmente é separado de uma grade
horizontal por uma camada isolante fina. Quando um dedo toca na tela, ela muda a capacitância em todas as
intersecções tocadas (possivelmente afastadas). Essa mudança pode ser medida. Como uma demonstração de que
uma touch screen moderna não é como as antigas telas infravermelhas e resistivas, tente tocar em uma com uma
caneta, lápis, clipe de papel ou dedo com luva e você verá que nada acontece. O corpo humano é bom para arma-
zenar carga elétrica, como pode ser comprovado dolorosamente por qualquer um que já tenha se arrastado por
um tapete em um dia frio e seco e depois tocado em uma maçaneta de metal. nstrumentos de plástico, madeira
e metal não são tão bons quanto pessoas em termos de sua capacitância.
Os “fios” em uma touch screen não são os fios de cobre comuns, encontrados nos dispositivos elétricos
normais, pois bloqueariam a luz da tela. Em vez disso, eles são tiras finas (em geral, com 50 micra) de óxido de
índio-estanho condutor, ligadas em lados opostos de uma placa fina de vidro, que juntos formam os capacitores.
Em alguns dispositivos mais novos, a placa de vidro isolante é substituída por uma fina camada de dióxido de
silício (areia!), com as três camadas salpicadas (átomo por átomo) em algum substrato. De qualquer forma, os
capacitores são protegidos contra poeira e arranhões por uma placa de vidro acima disso, para formar a superfície
da tela a ser tocada. Quanto mais fina a placa de vidro superior, mais sensível é o desempenho, porém, mais frágil
é o dispositivo.
Em operação, tensões são aplicadas alternadamente aos “fios” horizontal e vertical, enquanto os valores de
tensão, que são afetados pela capacitância de cada intersecção, são lidos dos outros. Essa operação é repetida
muitas vezes por segundo, com as coordenadas tocadas sendo alimentadas no controlador do dispositivo como
um fluxo de pares (x, y). Mais processamento, como determinar se ocorre apontamento, compressão, expressão
ou toque, é feito pelo sistema operacional. Se você usar todos os 10 dedos e pedir a um amigo para usar os dele,
o sistema operacional terá mais trabalho, mas o hardware de toque múltiplo poderá realizar essa tarefa.
Monitores de tela plana
Os primeiros monitores de computador usavam tubos de raios catódicos (CRs – cathode ray tubes), assim
como os antigos aparelhos de televisão. Eles eram muito volumosos e pesados para serem usados em notebooks,
portanto, era preciso uma tecnologia completamente diferente para suas telas. O desenvolvimento de telas planas
ofereceu um tamanho físico necessário para os notebooks, e esses dispositivos também usavam menos potência.
Hoje, os benefícios em tamanho e potência do monitor de tela plana quase eliminaram o uso de monitores CRT.
A mais comum tecnologia de monitor de tela plana é o LC (Liquid Crystal isplay  monitor de cristal
líquido). É uma tecnologia de alta complexidade, tem muitas variações e está mudando com grande rapidez, de
modo que esta descrição será necessariamente breve e muito simplificada.
Cristais líquidos são moléculas orgânicas viscosas que fluem como um líquido, mas também têm estru-
tura espacial, como um cristal. Foram descobertos por um botânico austríaco, Friedrich Reinitzer, em 1888 e
aplicados pela primeira vez em visores (por exemplo, de calculadoras e relógios) na década de 1960. Quando
todas as moléculas estão alinhadas na mesma direção, as propriedades óticas do cristal dependem da direção e
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 91
polarização da luz incidente. Usando um campo elétrico aplicado, o alinhamento molecular e, por conseguinte,
as propriedades óticas, podem ser mudadas. Em particular, fazendo passar luz através de um cristal líquido, a
intensidade da luz que sai dele pode ser controlada por meios elétricos. Essa propriedade pode ser explorada
para construir monitores de tela plana.
Uma tela de monitor de LCD consiste em duas placas de vidro paralelas entre as quais há um volume
selado que contém um cristal líquido. Eletrodos transparentes são ligados a ambas as placas. Uma luz atrás da
placa traseira, natural ou artificial, ilumina a tela por trás. Os eletrodos transparentes ligados a cada placa são
usados para criar campos elétricos no cristal líquido. Diferentes partes da tela recebem tensões elétricas dife-
rentes para controlar a imagem apresentada. Colados às partes frontal e traseira da tela há filtros de polarização
(polaroides), pois a tecnologia do monitor requer a utilização de luz polarizada. A montagem geral é mostrada
na Figura 2.33(a).
Figura 2.33 (a) Construc
a
o de uma tela de LCD. (b) Os sulcos nas placas traseira e frontal sa
o perpendiculares uns aos outros.
(a) (b)
y
z
Cristal líquido
Placa de vidro traseira
Eletrodo traseiro
Polaroide
traseiro
Placa de vidro frontal
Eletrodo frontal
Polaroide frontal
Fonte
de luz
Escura
Brilhante
Notebook
Embora muitos tipos de monitores de LCD estejam em uso, agora vamos considerar um tipo particular
de visor, o N (wisted Nematic  nemático torcido), como exemplo. Nesse monitor, a placa traseira contém
minúsculos sulcos horizontais, e a frontal, minúsculos sulcos verticais, como ilustrado na Figura 2.33(b). Na
ausência de um campo elétrico, as moléculas do LCD tendem a se alinhar com os sulcos. Uma vez que os alinha-
mentos frontal e traseiro estão a 90 graus entre si, as moléculas (e, portanto, a estrutura cristalina) ficam torcidas
entre as placas traseira e frontal.
Na parte de trás do monitor há um polaroide horizontal que permite apenas a passagem de luz polarizada
horizontalmente. Na parte da frente do visor há um polaroide vertical que permite apenas a passagem de luz
polarizada verticalmente. Se não houvesse nenhum líquido presente entre as placas, a luz polarizada hori-
zontalmente que entrasse pelo polaroide traseiro seria bloqueada pelo polaroide frontal, produzindo uma tela
uniformemente negra.
Contudo, a estrutura cristalina torcida das moléculas do LCD guia a luz na passagem e gira sua polarização,
fazendo com que ela saia na vertical. Portanto, na ausência de um campo elétrico, a tela de LCD é uniformemente
brilhante. Aplicando uma tensão elétrica em partes selecionadas da placa, a estrutura torcida pode ser destruída,
bloqueando a luz nesses locais.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
92
Há dois esquemas que podem ser usados para aplicar a tensão elétrica. Em um monitor de matriz passiva (de
baixo custo), ambos os eletrodos contêm fios paralelos. Em um monitor de 1.920 × 1.080, por exemplo, o eletrodo
traseiro poderia ter 1.920 fios verticais e o frontal poderia ter 1.080 horizontais. Aplicando-se uma tensão elétrica
em um dos fios verticais e em seguida fazendo-se pulsar um dos horizontais, a tensão em uma posição de pixel sele-
cionada pode ser mudada, fazendo-a escurecer por um curto espaço de tempo. Um pixel (aglutinação das palavras
“picture” e “element”) é um ponto colorido a partir do qual todas as imagens digitais são construídas. Repetindo-se
esse pulso para o próximo pixel e então para o seguinte, pode-se pintar uma linha escura de varredura. Em geral, a
tela inteira é pintada 60 vezes por segundo, para enganar o olho e fazê-lo pensar que ali há uma imagem constante.
O outro esquema de ampla utilização é o monitor de matriz ativa. É mais caro, mas produz melhor imagem.
Em vez de apenas dois conjuntos de fios perpendiculares, ele tem um minúsculo elemento comutador em cada
posição de pixel em um dos eletrodos. Desligando e ligando esses elementos, pode-se criar um padrão de tensão
elétrica arbitrário na tela, o que permite um padrão de bits também arbitrário. Os elementos comutadores são
denominados transistores de película fina (F  hin Film ransistors) e os monitores de tela plana que os
utilizam costumam ser denominados monitores F. Agora, a maioria dos notebooks e monitores de tela plana
para desktops utiliza a tecnologia TFT.
Até aqui, descrevemos como funciona um monitor monocromático. Basta dizer que monitores coloridos
usam os mesmos princípios gerais dos monocromáticos, mas os detalhes são muito mais complicados. Filtros
ópticos são usados para separar a luz branca em componentes vermelha, verde e azul em cada posição de pixel, de
modo que estes possam ser exibidos independentemente. Toda cor pode ser obtida por uma superposição dessas
três cores primárias.
Outras tecnologias de tela estão surgindo. Uma das mais promissoras é a tela OLE (Organic Light Emitting
iode – diodo orgânico emissor de luz). Ela consiste em camadas de moléculas orgânicas carregadas eletrica-
mente, dispostas entre dois eletrodos em forma de sanduíche. As mudanças de tensão fazem com que as molécu-
las sejam excitadas e se movam para estados de energia mais altos. Quando elas retornam ao seu estado normal,
emitem luz. Outros detalhes estão fora do escopo deste livro (e de seus autores).
RAM de v
deo
Quase todos os monitores são renovados de 60 a 100 vezes por segundo por uma memória especial, denominada
RM de vídeo (memória de acesso aleatório de vídeo), embutida na placa controladora do monitor. Essa memória tem
um ou mais mapas de bits que representam a imagem da tela. Em uma tela com, por exemplo, 1.920 × 1.080 elementos
de imagem, denominados pixels, uma RAM de vídeo conteria 1.920 × 1.080 valores, um para cada pixel. Na verdade,
ela poderia conter muitos desses mapas de bits, para permitir a passagem rápida de uma imagem para outra.
Em um monitor comum, cada pixel seria representado como um valor RGB (red/green/blue) de 3 bytes, um
para cada intensidade das componentes vermelha, verde e azul da cor do pixel (monitores de primeira linha usam
10 ou mais bits por cor). Pelas leis da física, sabe-se que qualquer cor pode ser obtida por uma superposição linear
de luzes vermelha, verde e azul.
Uma RAM de vídeo com 1.920 × 1.080 pixels a 3 bytes/pixel requer mais de 6,2 MB para armazenar a imagem
e uma boa quantidade de tempo de CPU para fazer qualquer coisa com ela. Por essa razão, alguns computadores
adotam uma solução de conciliação usando um número de 8 bits para indicar a cor desejada. Então, esse número
é usado como um índice para uma tabela de hardware denominada paleta de cores, que contém 256 entradas,
cada uma com um valor RGB de 24 bits. Esse projeto, denominado cor indexada, reduz em dois terços o tamanho
de memória da RAM de vídeo, mas permite somente 256 cores na tela ao mesmo tempo. Em geral, cada janela
na tela tem seu próprio mapeamento. Porém, com apenas uma paleta de cores em hardware, quando há várias
janelas presentes, muitas vezes apenas a janela corrente apresenta suas cores corretamente. Paletas de cores com
216
entradas também são usadas, mas o ganho aqui é de apenas 1/3.
Monitores de vídeo com mapas de bits requerem grande quantidade de largura de banda. Para apresentar
multimídia em tela cheia, com todas as cores em um monitor de 1.920 × 1.080, é preciso copiar 6,2 MB de dados
para a RAM de vídeo para cada quadro. Quando o vídeo é de movimento total, é preciso uma taxa de no mínimo
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 93
25 quadros por segundo, o que resulta uma taxa total de dados de 155 MB/s. Essa carga é mais do que o barra-
mento PC original podia manipular (132 MB/s), mas o PCe pode tratar disso com facilidade.
2.4.3 Mouses
À medida que o tempo passa, os computadores estão sendo usados por pessoas menos versadas sobre o
modo de funcionamento desses equipamentos. Máquinas da geração ENAC só eram empregadas pelas pessoas
que as construíram. Na década de 1950, computadores eram utilizados apenas por programadores profissionais
altamente treinados. Agora, são amplamente usados por pessoas que precisam fazer algum trabalho e não sabem
muito (ou nem querem saber) sobre como funcionam os computadores ou como são programados.
Antigamente, a maioria dos computadores tinha interfaces de linha de comando, para as quais os usuários digi-
tavam comandos. isto que quem não é especialista quase sempre acha que interfaces de linha de comando não são
amigáveis ao usuário – se não absolutamente hostis –, muitos fabricantes desenvolveram interfaces do tipo “apontar e
clicar”, tais como as do Macintosh e do Windows. Usar esse modelo pressupõe que haja um modo de apontar algo na
tela. O meio mais comum de permitir que usuários apontem algo na tela é um mouse.
Um mouse é um caixinha de plástico que fica sobre a mesa, ao lado do teclado. Quando ela é movimentada
sobre a mesa, um pequeno ponteiro também se movimenta na tela, permitindo que os usuários apontem itens. O
mouse tem um, dois ou três botões na parte de cima, que possibilitam aos usuários selecionar itens apresentados
em menus. Muita polêmica já se levantou por causa de discussões sobre o número de teclas que um mouse deve
ter. Usuários ingênuos preferem uma só (não há como apertar a tecla errada se houver apenas uma), mas os sofis-
ticados gostam do poder conferido por várias teclas para fazer coisas imaginativas.
Três tipos de mouses foram produzidos: mecânicos, ópticos e óptico-mecânicos. Os primeiros tinham duas
rodinhas de borracha para fora da parte inferior do corpo com eixos perpendiculares entre si. Quando o mouse
era movimentado em paralelo com seu eixo principal, uma roda girava. Quando ele era movimentado ao longo
da perpendicular de seu eixo principal, a outra roda girava. Cada rodinha comandava um resistor variável (poten-
ciômetro). Medindo as alterações na resistência era possível ver como cada roda tinha girado e assim calcular a
distância que o mouse tinha percorrido em cada direção. Depois, esse projeto foi substituído em grande parte por
outro, no qual, em vez de rodinhas, era usada uma pequena esfera projetada um pouco para fora do fundo do
mouse. Ele é mostrado na Figura 2.34.
Figura 2.34 Utilizac
a
o do mouse para apontar itens de menu.
Ponteiro controlado por mouse
Janela Menu
Recortar
Colar
Copiar
Botões do mouse
Mouse
Bola de borracha
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
94
O segundo tipo de mouse é o óptico. Esse tipo não tem rodinhas nem esferas. Em vez delas, tem um LE
(Light Emitting iode  diodo emissor de luz) e um fotodetector na parte de baixo. Os primeiros mouses
ópticos exigiam uma almofada plástica especial que continha uma grade retangular de linhas espaçadas muito
próximas umas das outras para detectar quantas linhas tinham sido atravessadas e, assim, a que distância o
mouse se movimentou. Os mouses ópticos modernos contêm um LED que ilumina as imperfeições da superfí-
cie, junto com uma pequena câmera de vídeo que registra uma pequena imagem (em geral, 18 × 18 pixels) até
1.000 vezes por segundo. magens consecutivas são comparadas para ver a que distância o mouse se moveu.
Alguns mouses ópticos utilizam um laser no lugar de um LED para iluminação. Eles são mais precisos, mas
também mais caros.
O terceiro tipo de mouse é o óptico-mecânico. Assim como o mouse mecânico mais novo, ele tem uma esfera
que gira dois eixos alinhados a 90 graus em relação um ao outro. Os eixos estão conectados a decodificadores com
fendas que permitem a passagem da luz. Quando o mouse se movimenta, os eixos giram e pulsos de luz atingem
os detectores sempre que aparece uma fenda entre um LED e seu detector. O número de pulsos detectados é pro-
porcional à quantidade de movimento.
Embora mouses possam ser montados de várias maneiras, um arranjo comum é enviar uma sequência de 3
bytes ao computador toda vez que o mouse se movimenta a uma distância mínima (por exemplo, 0,01 polegada),
às vezes denominada mickey. Em geral, esses caracteres vêm em uma linha serial, um bit por vez. O primeiro byte
contém um inteiro com sinal que informa quantas unidades o mouse se moveu na direção x desde a última vez.
O segundo dá a mesma informação para movimento na direção y. O terceiro contém o estado corrente das teclas
do mouse. Às vezes, são usados 2 bytes para cada coordenada.
No computador, um software de baixo nível aceita essas informações à medida que chegam e converte os
movimentos relativos enviados pelo mouse em uma posição absoluta. Em seguida, ele apresenta na tela uma
seta correspondente à posição onde o mouse está. Quando a seta indicar o item adequado, o usuário clica no
botão do mouse e então o computador pode interpretar qual item foi selecionado, por saber onde a seta está
posicionada na tela.
2.4.4 Controladores de jogos
Os videogames costumam ter exigências muito altas de E/S do usuário e, no mercado de console de vídeo,
dispositivos de entrada especializados têm sido desenvolvidos. Nesta seção, veremos dois desenvolvimentos
recentes em controladores para videogame, o Nintendo Wiimote e o Microsoft Kinect.
Controlador Wiimote
Lançado em 2006 com o console de jogos Nintendo Wii, o controlador Wiimote contém botões tradicionais
para jogos e mais uma capacidade de sensibilidade dupla ao movimento. Todas as interações com o Wiimote
são enviadas em tempo real ao console de jogos, usando um rádio Bluetooth interno. Os sensores de movimento
no Wiimote permitem que ele sinta seu próprio movimento nas três dimensões e mais; quando apontado para a
televisão, ele oferece uma capacidade minuciosa para apontar.
A Figura 2.35 ilustra como o Wiimote executa essa função de sensibilidade ao movimento. O rastrea-
mento do movimento do Wiimote em três dimensões é realizado com um acelerômetro interno de 3 eixos.
Esse dispositivo contém três massas pequenas, cada qual podendo se mover nos eixos x, y e z (com relação
ao chip do acelerômetro). Elas se movem em proporção ao grau de aceleração em seu eixo particular, o
que muda a capacitância da massa em relação a uma parede fixa de metal. Medindo as três capacitâncias
variáveis, é possível sentir a aceleração em três dimensões. Usando essa tecnologia e algum cálculo clássico,
o console Wii pode rastrear o movimento do Wiimote no espaço. Ao movimentar o Wiimote para atingir
uma bola de tênis virtual, esse movimento é rastreado enquanto você se desloca em direção à bola e, se você
virou o pulso no último momento para atingir a bola por cima, os acelerômetros do Wiimote também notarão
esse movimento.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 95
Figura 2.35 Sensores de movimento do controlador de videogame Wiimote.
z
y
x
Barra de sensor
Câmera
Acelerômetro de 3 eixos
Embora os acelerômetros funcionem bem para acompanhar o movimento do Wiimote enquanto ele se deslo-
ca em três dimensões, eles não podem oferecer a sensibilidade de movimento detalhada necessária para controlar
um ponteiro na tela da televisão. Os acelerômetros sofrem com pequenos erros inevitáveis em suas medições de
aceleração, de modo que, com o tempo, o local exato do Wiimote (com base na integração de suas acelerações)
se tornará cada vez menos preciso.
Para oferecer a sensibilidade de movimento com precisão, o Wiimote utiliza uma tecnologia de visão de
computador inteligente. Acima da televisão há uma “barra de sensor” que contém LEDs a uma distância fixa.
No Wiimote há uma câmera que, quando apontada na barra de sensor, pode deduzir a distância e orientação em
relação à televisão. Como os LEDs da barra de sensor estão afastados a certa distância, sua distância vista pelo
Wiimote é proporcional àquela entre o Wiimote e a barra de sensor. O local da barra de sensor no campo de visão
do Wiimote indica a direção que este aponta em relação à televisão. Observando essa orientação continuamente,
é possível dar suporte a uma capacidade de apontamento minucioso sem os erros de posição inerentes aos ace-
lerômetros.
Controlador Kinect
O Microsoft Kinect leva as capacidades de visão dos controladores de jogos a um nível inteiramente novo.
Esse dispositivo usa apenas a visão do computador para determinar as interações do usuário com o console de
jogos. Ele funciona sentindo a posição do usuário na sala, mais a orientação e o movimento de seu corpo. Os jogos
são controlados por movimentos predeterminados de suas mãos, braços e qualquer outra coisa que os projetistas
do jogo acreditarem que você deva mexer a fim de controlar seu jogo.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
96
A capacidade de sentir do Kinect é baseada em uma câmera de profundidade combinada com uma câmera de
vídeo. A câmera de profundidade calcula a distância do objeto no campo de visão do Kinect. Ela faz isso emitindo
uma matriz bidimensional de pontos a laser infravermelho, depois capturando seus reflexos com uma câmera
infravermelha. Usando uma técnica de visão do computador chamada “iluminação estruturada”, o Kinect pode
determinar a distância dos objetos em seu campo de visão com base em como o conjunto de pontos infraverme-
lhos é agitado pelas superfícies iluminadas.
A informação de profundidade é combinada com a informação de textura retornada da câmera de vídeo
para produzir um mapa de profundidade texturizado. Esse mapa pode então ser processado pelos algoritmos
de visão do computador para localizar a pessoa na sala (até mesmo reconhecendo seus rostos) e a orientação e
movimento de seu corpo. Depois de processar, a informação sobre as pessoas na sala é enviada ao console do
jogo, que usa esses dados para controlar o videogame.
2.4.5 Impressoras
Após o usuário preparar um documento ou buscar uma página na Web, muitas vezes quer imprimir seu
trabalho, de modo que todos os computadores podem ser equipados com uma impressora. Nesta seção, descre-
veremos alguns dos tipos mais comuns de impressoras.
Impressoras a laser
Talvez o desenvolvimento mais interessante da impressão desde que Johann Gutenberg inventou o tipo
móvel no século  é a impressora a laser. Esse dispositivo combina uma imagem de alta qualidade, excelente
flexibilidade, grande velocidade e custo moderado em um único periférico compacto. mpressoras a laser usam
quase a mesma tecnologia das máquinas fotocopiadoras. Na verdade, muitas empresas fabricam equipamentos
que combinam cópia e impressão (e, às vezes, também fax).
A tecnologia básica é ilustrada na Figura 2.36. O coração da impressora é um tambor rotativo de precisão (ou
uma correia, em alguns sistemas de primeira linha). No início de cada ciclo de página, ele recebe uma carga de até
cerca de 1.000 volts e é revestido com um material fotossensível. Então, a luz de um laser passa pelo comprimento
do tambor, refletindo-a de um espelho octogonal rotativo. O feixe de luz é modulado para produzir um padrão de
pontos escuros e claros. Os pontos atingidos pelo feixe perdem sua carga elétrica.
Figura 2.36 Operac
a
o de uma impressora a laser.
Laser
Espelho octogonal
rotativo
Tambor pulverizado e carregado
Feixe de luz
atinge o tambor Tambor
Toner
Raspador
Dispensador
Papel em
branco
Roletes
aquecidos
Saída
empilhada
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 97
Após pintar uma linha de pontos, o tambor gira uma fração de um grau para permitir que a próxima linha
seja pintada. Com o decorrer da rotação, a primeira linha de pontos chega ao toner, um reservatório que contém
um pó negro eletrostaticamente sensível. O toner é atraído por aqueles pontos que ainda estão carregados, for-
mando uma imagem visual daquela linha. Um pouco mais adiante na trajetória de transporte, o tambor revestido
de toner é pressionado contra o papel, transferindo o pó preto para ele. Em seguida, o papel passa por rolamentos
aquecidos que fundem permanentemente o toner à superfície do papel, fixando a imagem. Em um ponto mais
adiante de sua rotação, o tambor é descarregado e raspado para limpar qualquer resíduo de toner, preparando-o
para receber nova carga elétrica e revestimento para imprimir a próxima página.
Nem é preciso dizer que esse processo é uma combinação extremamente complexa de física, química,
engenharia mecânica e engenharia ótica. Ainda assim, há vários fabricantes no mercado que oferecem conjuntos
complexos denominados mecanismos de impressão. Fabricantes de impressoras a laser combinam os mecanis-
mos de impressão com sua própria eletrônica e software próprio para montar uma impressora completa. A parte
eletrônica consiste em uma CPU rápida embutida junto com megabytes de memória para conter um mapa de bits
de uma página inteira e numerosas fontes, algumas delas embutidas, outras carregadas por download. Grande
parte das impressoras aceita comandos que descrevem as páginas a serem impressas (ao contrário de apenas
aceitar mapas de bits preparados pela CPU principal). Esses comandos são dados em linguagens como a PCL
da HP e PostScript da Adobe ou PDF
, que são linguagens de programação completas, embora especializadas.
mpressoras a laser de 600 dpi ou mais podem executar um trabalho razoável na impressão de fotografias em
preto e branco, mas a tecnologia é mais complicada do que pode parecer à primeira vista. Considere uma fotogra-
fia digitalizada em 600 dpi que deve ser impressa por uma impressora de 600 dpi. A imagem contém 600 × 600
pixels/polegada, cada um consistindo em um valor de cinza que varia de 0 (branco) a 255 (preto). A impressora
também pode imprimir 600 dpi, mas cada pixel impresso é ou preto (toner presente) ou branco (nenhum toner
presente). alores cinza não podem ser impressos.
A solução habitual para imprimir imagens com valores de cinza é usar a técnica do meio-tom (retícula), a mesma
empregada para imprimir cartazes comerciais. A imagem é desmembrada em células de meios-tons, em geral com 6 ×
6 pixels. Cada célula pode conter entre 0 e 36 pixels pretos. O olho percebe uma célula com muitos pixels como mais
escura do que uma com menos pixels. alores de cinza na faixa de 0 a 255 são representados dividindo essa faixa em
37 zonas. alores de 0 a 6 estão na zona 0, valores de 7 a 13 estão na zona 1 e assim por diante (a zona 36 é um pouco
menor do que as outras porque 256 não é divisível exatamente por 37). Sempre que é encontrado um valor de cinza
na zona 0, sua célula de meio-tom sobre o papel é deixada em branco, como ilustrado na Figura 2.37(a). Um valor de
zona 1 é impresso como 1 pixel negro. Um valor de zona 2 é impresso como 2 pixels negros, conforme mostra a Figura
2.37(b). Outros valores de zonas são mostrados nas figuras 2.37(c)–(f). Claro que pegar uma fotografia digitalizada
a 600 dpi e usar essa técnica de meio-tom reduz a resolução efetiva a 100 células/polegada, denominada frequência
de tela de meio-tom, medida por convenção em lpi (lines per inch  linhas por polegada).
Figura 2.37 Pontos de meio-tom para va
rias faixas de escala de cinza. (a) 0–6. (b) 14–20. (c) 28–34. (d) 56–62. (e) 105–111.
(f) 161–167.
(a) (b) (c) (d) (e) (f)
Impressa
o colorida
Embora a maioria das impressoras a laser seja monocromática, impressoras a laser coloridas estão se tor-
nando mais comuns, de modo que talvez seja útil dar aqui alguma explicação sobre a impressão colorida (que
também se aplica a impressoras a jato de tinta e outras). Como você poderia imaginar, isso não é trivial. magens
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
98
coloridas podem ser vistas de duas maneiras: por luz transmitida e por luz refletida. magens por luz transmiti-
da, como as produzidas em monitores, são compostas por superposição linear das três cores primárias aditivas:
vermelho, verde e azul.
Ao contrário, imagens por luz refletida, como fotografias em cores e fotos em revistas de papel lustroso,
absorvem certos comprimentos de onda de luz e refletem o resto. Elas são compostas por uma superposição linear
das três cores subtrativas primárias, ciano (toda cor vermelha absorvida), magenta (toda cor verde absorvida) e
amarela (toda cor azul absorvida). Em teoria, toda cor pode ser produzida misturando as tintas ciano, amarela e
magenta. Na prática, é difícil conseguir essas tintas com pureza suficiente para absorver toda a luz e produzir um
negro verdadeiro. Por essa razão, praticamente todos os sistemas de impressão em cores usam quatro tintas: ciano,
magenta, amarela e negra. Esses sistemas são denominados impressoras CMYK. O K é geralmente associado à
cor negra (blacK), porém, ele é a placa chave com a qual as placas de cores são alinhadas em impressoras con-
vencionais de quatro cores. Monitores, ao contrário, usam luz transmitida e o sistema RGB para produzir cores.
O conjunto completo de cores que um monitor ou uma impressora podem produzir é denominado sua gama.
Nenhum dispositivo tem uma gama que se iguale à do mundo real, já que cada cor vem em 256 intensidades no
máximo, o que dá apenas 16.777.216 cores discretas. mperfeições na tecnologia reduzem ainda mais esse total e
as restantes nem sempre estão uniformemente espaçadas no espectro de cores. Além do mais, a percepção da cor
tem muito a ver com o modo de funcionamento dos bastões e cones na retina, e não apenas com a física da luz.
Como consequência dessas observações, converter uma imagem colorida que parece boa na tela em uma
imagem impressa idêntica está longe de ser trivial. Entre os problemas estão:
1. Monitores em cores usam luz transmitida; impressoras em cores usam luz refletida.
2. Monitores produzem 256 intensidades por cor; impressoras têm de usar meios-tons.
3. Monitores têm um fundo negro; o papel tem um fundo claro.
4. As gamas RGB de um monitor e as gamas CMYK de uma impressora são diferentes.
Obter imagens impressas em cores que reproduzem os tons do mundo real (ou até mesmo os das imagens
na tela) requer calibração de dispositivos, software sofisticado e considerável conhecimento técnico e experiência
da parte do usuário.
Impressoras a jato de tinta
Para impressão doméstica de baixo custo, as impressoras a jato de tinta são as favoritas. A cabeça de impres-
são móvel, que mantém os cartuchos de tinta, é varrida horizontalmente pelo papel por uma correia, enquanto a
tinta é espirrada por minúsculos esguichos. As gotículas de tinta têm um volume de mais ou menos 1 picolitro,
de modo que 100 milhões delas formam uma única gota d’água.
mpressoras a jato de tinta podem ter duas variedades: piezelétricas (usadas pela Epson) e térmicas (usadas
pela Canon, HP e Lexmark). As impressoras a jato de tinta piezelétricas possuem um tipo especial de cristal
próximo de sua câmara de tinta. Quando uma tensão elétrica é aplicada ao cristal, ela se deforma ligeiramente,
forçando uma gotícula de tinta a sair pelo esguicho. Quanto maior a tensão, maior a gotícula, permitindo que o
software controle seu tamanho.
mpressoras a jato de tinta térmicas (também chamadas impressoras a jato de bolhas) contêm um minúsculo
resistor dentro de cada esguicho. Quando uma tensão elétrica é aplicada ao resistor, ele se aquece extremamente
rápido, elevando de imediato a temperatura da tinta que encosta nele até o ponto de ebulição, até que a tinta se
vaporize para formar uma bolha de gás. A bolha de gás ocupa mais volume do que a tinta que a criou, produzindo
pressão no esguicho. O único lugar para onde a tinta pode sair é pela frente do esguicho, para o papel. O esguicho
é então resfriado e o vácuo resultante suga outra gota de tinta do cartucho. A velocidade da impressora é limitada
pela velocidade com que o ciclo aquecer/resfriar pode ser repetido. As gotículas são todas do mesmo tamanho,
mas menores do que as usadas pelas impressoras piezelétricas.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 99
As impressoras a jato de tinta normalmente possuem resoluções de pelo menos 1.200 dpi (dots per inch –
pontos por polegada) e, no máximo, 4.800 dpi. Elas são baratas, silenciosas e possuem boa qualidade, apesar
de também serem lentas, e utilizam cartuchos de tinta caros. Quando a melhor das impressoras a jato de tinta
de alta qualidade é usada para imprimir fotografia em alta resolução profissional com papel fotográfico espe-
cialmente lustroso, os resultados são parecidos com a fotografia convencional, até mesmo com impressões de
20 × 25 cm.
Para obter melhores resultados, é preciso usar tinta e papel especiais. intas à base de corantes consistem em
corantes coloridos dissolvidos em uma base fluida. Elas dão cores brilhantes e fluem com facilidade. Sua principal
desvantagem é que desbotam quando expostas à luz ultravioleta, tal como a contida na luz solar. intas à base
de pigmentos contêm partículas sólidas de pigmentos suspensas em uma base fluida, que evapora do papel dei-
xando ali o pigmento. Não desbotam com o tempo, mas não são tão brilhantes como as tintas à base de corantes
e as partículas de pigmento tendem a entupir os bicos injetores, que requerem limpeza periódica. Para imprimir
fotografias, é preciso papel lustroso ou revestido. Esses tipos de papel foram projetados especialmente para conter
as gotículas de tinta e não permitir que elas se espalhem.
Impressoras especiais
Embora impressoras a laser e a jato de tinta dominem os mercados de impressão doméstico e de escritório,
outros tipos de impressoras são usados em outras situações, com outros requisitos em termos de qualidade de
cor, preço e outras características.
Uma variante da impressora a jato de tinta é a impressora de tinta sólida. Esse tipo de impressora aceita
quatro blocos sólidos de uma tinta especial à base de cera, que são derretidos e passam para reservatórios de tinta
quente. Os tempos de partida dessas impressoras podem chegar a 10 minutos, enquanto os blocos de tinta estão
derretendo. A tinta quente é borrifada sobre o papel, onde se solidifica e se funde com o papel quando este é
forçado a passar entre dois roletes rígidos. De certa forma, ela combina a ideia de borrifar tinta das impressoras a
jato de tinta com a ideia de fundir a tinta no papel com roletes de borracha rígidos das impressoras a laser.
Outro tipo de impressora em cores é a impressora a cera. Ela tem uma larga fita encerada em quatro cores,
segmentada em faixas do tamanho de páginas. Milhares de elementos de aquecimento derretem a cera à medi-
da que o papel passa por baixo dela. A cera se funde com o papel na forma de pixels usando o sistema CMYK.
mpressoras a cera costumavam ser a principal tecnologia de impressão em cores, mas estão sendo substituídas
pelos outros tipos cujos materiais de consumo são mais baratos.
Ainda outro tipo de impressora em cores é a impressora por sublimação de corante, ou de tinta. Embora
dê a entender algo de freudiano, sublimação é o nome científico da passagem do estado sólido para o gasoso sem
passar pelo estado líquido. Gelo seco (dióxido de carbono congelado) é um material bem conhecido que sublima.
Em uma impressora por sublimação de tinta, uma base contendo os corantes CMYK passa sobre um cabeçote de
impressão térmico que contém milhares de elementos de aquecimento programáveis. As tintas são vaporizadas
instantaneamente e absorvidas por um papel especial que está próximo. Cada elemento de aquecimento pode
produzir 256 temperaturas diferentes. Quanto mais alta a temperatura, mais corante é depositado e mais intensa
é a cor. Diferente de todas as outras impressoras em cores, nessa são possíveis cores praticamente contínuas para
cada pixel, de modo que o meio-tom não é necessário. Pequenas impressoras de instantâneos muitas vezes usam o
processo de sublimação de tinta para produzir imagens fotográficas de alto grau de realismo sobre papel especial
(e caro).
Por fim, chegamos à impressora térmica, que contém uma pequena cabeça de impressão com alguma quan-
tidade de minúsculas agulhas que podem ser aquecidas. Quando uma corrente elétrica passa por uma agulha, ela
se torna muito quente depressa. Quando um papel termicamente sensível especial é empurrado pela cabeça de
impressão, os pontos são feitos no papel quando as agulhas estão quentes. Com efeito, uma impressora térmica é
como as antigas impressoras matriciais, cujos pinos eram pressionados contra uma fita tipo máquina de escrever
para formar os pontos de tinta no papel atrás da fita. As impressoras térmicas são muito usadas para imprimir
recibos em lojas, caixas eletrônicos de banco, postos de gasolina automatizados etc.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
100
2.4.6 Equipamento de telecomunicac
o
es
Hoje, grande parte dos computadores está ligada a uma rede de computadores, em geral a nternet. Para
conseguir acesso, é preciso usar equipamento especial. Nesta seção, veremos como esse equipamento funciona.
Modems
Com o crescimento da utilização de computadores nos últimos anos, é comum que um computador pre-
cise se comunicar com outro. Por exemplo, muitas pessoas têm em casa computadores pessoais que usam para
se comunicar com o que está em seu local de trabalho, com uma provedora de serviço de nternet (SP – nternet
Service Provider) ou com um sistema de home banking. Em muitos casos, a linha telefônica provê comunicação física.
Contudo, uma linha telefônica comum (ou cabo) não é adequada para transmissão de sinais de computador
que costumam representar um 0 como 0 volt e um 1 como 3 a 5 volts, conforme mostra a Figura 2.38(a). Sinais
de dois níveis sofrem considerável distorção quando transmitidos por uma linha telefônica projetada para voz,
ocasionando erros de transmissão. Todavia, um sinal de onda senoidal pura em uma frequência de 1.000 a 2.000
Hz, denominada portadora, pode ser transmitido com relativamente pouca distorção, e esse fato é explorado
como a base da maioria dos sistemas de telecomunicação.
Como as pulsações de uma onda senoidal são totalmente previsíveis, uma onda senoidal pura não transmite
nenhuma informação. Contudo, variando a amplitude, frequência ou fase, uma sequência de 1s e 0s pode ser
transmitida, como mostra a Figura 2.38. Esse processo é denominado modulação, e o dispositivo que faz isso
é denominado modem, que significa MOdulador EModulador. Na modulação de amplitude (veja a Figura
2.38(b)), são usados dois níveis de tensão elétrica (voltagem) para 0 e 1, respectivamente. Uma pessoa que esteja
ouvindo dados transmitidos a uma taxa de dados muito baixa ouviria um ruído alto para 1 e nenhum ruído para 0.
Em modulação de frequência (veja a Figura 2.38(c)), o nível de tensão elétrica (voltagem) é constante,
mas a frequência da portadora é diferente para 1 e para 0. Uma pessoa que estivesse ouvindo dados digitais
com frequência modulada ouviria dois tons, correspondentes a 0 e 1. A modulação de frequência costuma ser
denominada modulação por chaveamento de frequência.
Figura 2.38 Transmissa
o bit a bit do nu
mero bina
rio 01001011000100 por uma linha telefo
nica. (a) Sinal de dois n
veis.
(b) Modulac
a
o de amplitude. (c) Modulac
a
o de freque
ncia. (d) Modulac
a
o de fase.
(a)
(b)
(c)
(d)
V1
V2
0 1 0 0 1 0 1 1 0 0 0 1 0 0
Tempo
Tensão
Alta
amplitude
Baixa
amplitude
Frequência
alta
Frequência
baixa
Mudança
de fase
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 101
Em modulação de fase simples (veja Figura 2.38(d)), a amplitude e a frequência não mudam, mas a fase da
portadora é invertida 180 graus quando os dados passam de 0 para 1 ou de 1 para 0. Em sistemas de fase modulada
mais sofisticados, no início de cada intervalo de tempo indivisível, a fase da portadora é bruscamente mudada
para 45, 135, 225 ou 315 graus, para permitir 2 bits por intervalo de tempo, denominado codificação de fase
dibit. Por exemplo, uma mudança de fase de 45 graus poderia representar 00, uma mudança de fase de 135
graus poderia representar 01 e assim por diante. Também existem outros esquemas para transmitir 3 ou mais
bits por intervalo de tempo. O número de intervalos de tempo, isto é, o número de mudanças de sinal por
segundo, é uma taxa de bauds. Com 2 ou mais bits por intervalo, a taxa de bits ultrapassará a taxa de bauds.
Muitos confundem os dois termos. Novamente: a taxa de bauds é o número de vezes que o sinal muda por
segundo, enquanto a taxa de bits é o número de bits transmitidos por segundo. A taxa de bits geralmente é um
múltiplo da taxa de bauds, mas teoricamente ela pode ser menor.
Se os dados a serem transmitidos consistirem em uma série de caracteres de 8 bits, seria desejável ter uma
conexão capaz de transmitir 8 bits simultaneamente – isto é, oito pares de fios. Como as linhas telefônicas ofe-
recem apenas um canal, os bits têm de ser enviados de modo serial, um após o outro (ou em grupos de dois se
estiver sendo usada a codificação dibit). O dispositivo que aceita caracteres de um computador na forma de sinais
de dois níveis, um bit por vez, e transmite os bits em grupos de um ou dois, em forma de amplitude, frequência
ou fase modulada, é o modem. Para marcar o início e o final de cada caractere, é enviado um caractere de 8 bits
precedido por um bit de início e seguido por um bit de fim, totalizando 10 bits.
O modem que está transmitindo envia os bits individuais dentro de um caractere a intervalos de tempo
regularmente espaçados. Por exemplo, 9.600 bauds implica uma mudança de sinal a cada 104 μs. Um segundo
modem na extremidade receptora é usado para converter uma portadora modulada em um número binário. Como
os bits chegam ao receptor a intervalos regulares, uma vez que o modem receptor tenha determinado o início do
caractere, seu clock o informa quando amostrar a linha para ler os bits que estão entrando.
Modems modernos funcionam a taxas de dados na faixa de 56 kbps, normalmente a taxas muito mais baixas.
Eles usam uma combinação de técnicas para enviar múltiplos bits por baud, modulando a amplitude, a frequência
e a fase. Quase todos eles são full-duplex, o que quer dizer que podem transmitir em ambas as direções ao mesmo
tempo (usando frequências diferentes). Modems ou linhas de transmissão que só podem transmitir em uma dire-
ção por vez (como uma ferrovia com uma única linha que pode transportar trens em direção ao norte ou trens em
direção ao sul, mas não fazê-lo ao mesmo tempo) são denominados half-duplex. Linhas que só podem transmitir
em uma direção são linhas simplex.
Linhas digitais de assinante (DSL  Digital Subscriber Lines)
Quando a indústria da telefonia chegou por fim aos 56 kbps, ela se congratulou por um trabalho bem-feito.
Enquanto isso, a indústria da T a cabo estava oferecendo velocidades de até 10 Mbps em cabos compartilhados e
as operadoras de satélites estavam planejando oferecer mais de 50 Mbps. À medida que o acesso à nternet tornou-
-se uma parte cada vez mais importante de seus negócios, as telcos (telephone companies  empresas de telefonia)
começaram a perceber que precisavam de um produto mais competitivo do que linhas discadas. A resposta dessas
empresas foi começar a oferecer um novo serviço digital de acesso à nternet. Serviços com mais largura de banda
do que o serviço telefônico padrão às vezes são denominados serviços de banda larga, embora, na realidade, o termo
seja mais um conceito de marketing do que qualquer outra coisa. Por um ponto de vista estritamente técnico, banda
larga significa que existem vários canais de sinalização, enquanto banda base significa que há somente um. Assim,
teoricamente, a Ethernet a 10 gigabits, que é muito mais distante do que qualquer serviço de “banda larga” oferecido
pela companhia telefônica, não é banda larga de forma alguma, pois tem apenas um canal de sinalização.
De início, havia muitas ofertas que se sobrepunham, todas sob o mesmo nome geral de xSL (igital
Subscriber Line), para vários x. Mais adiante, discutiremos o serviço que provavelmente vai se tornar o mais
popular desses, o SL (symmetric SL  SL assimétrico). isto que o ADSL ainda está sendo desenvolvido
e nem todos os padrões estão totalmente em vigor, alguns dos detalhes dados mais adiante podem mudar com
o tempo, mas o quadro básico deve continuar válido. Para obter mais informações sobre ADSL, veja Summers,
1999; e etter et al., 2000.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
102
A razão por que modems são tão lentos é que os telefones foram inventados para transmitir a voz humana
e todo o sistema foi cuidadosamente otimizado para essa finalidade. Dados sempre foram filhos adotivos. A
linha, denominada loop local, de cada assinante da companhia telefônica é tradicionalmente limitada a cerca
de 3.000 Hz por um filtro na central da empresa de telecomunicações. É esse filtro que limita a taxa de dados.
A largura de banda real do loop local depende de seu comprimento, mas, para distâncias típicas de alguns qui-
lômetros, 1,1 MHz é viável.
O método mais comum da oferta de ADSL é ilustrado na Figura 2.39. Na verdade, o que ele faz é remover o
filtro e dividir o espectro disponível de 1,1 MHz no loop local em 256 canais independentes de 4.312,5 Hz cada. O
canal 0 é usado para POS (Plain Old elephone Service  serviço telefônico normal). Os canais de 1 a 5 não são
usados para evitar que o sinal de voz e os sinais de dados interfiram uns com os outros. Dos 250 canais restantes,
um é usado para controle na direção da empresa de telefonia e outro para controle na direção do usuário. O resto
está disponível para dados do usuário. O ADSL equivale a ter 250 modems.
Figura 2.39 Operac
a
o de ADSL.
Direção do usuário
Potência
256 canais de 4 kHz
Voz Direção da empresa
Em princípio, cada um dos canais remanescentes pode ser usado para um fluxo de dados full-duplex, mas,
na prática, harmônicos, linhas cruzadas e outros efeitos mantêm os sistemas bem abaixo do limite teórico. Cabe
ao provedor determinar quantos canais são usados na direção da empresa e quantos na direção do usuário. Uma
proporção de 50–50 é tecnicamente possível, mas a maioria das provedoras aloca cerca de 80%–90% da largura
de banda na direção do usuário, uma vez que eles descarregam mais dados do que carregam. Essa opção deu
origem ao “A” em ADSL (de Assimétrico). Uma divisão comum são 32 canais na direção da empresa e o resto na
direção do usuário.
A qualidade da linha é monitorada constantemente dentro de cada canal e a taxa de dados é ajustada confor-
me necessário, portanto, canais diferentes podem ter taxas de dados diferentes. Os dados propriamente ditos são
enviados usando uma combinação de modulação de amplitude e de fase com até 15 bits por baud. Por exemplo,
com 224 canais na direção do usuário e 15 bits/baud a 4.000 bauds, a largura de banda na direção do usuário é
13,44 Mbps. Na prática, a relação sinal/ruído nunca é boa o suficiente para alcançar essa taxa, mas 4–8 Mbps é
possível em distâncias curtas por loops de alta qualidade.
Uma configuração ADSL típica é mostrada na Figura 2.40. Nesse esquema, o usuário ou um técnico da com-
panhia telefônica deve instalar um NI (Network Interface evice  dispositivo de interface de rede) na casa
ou escritório do cliente. Essa caixinha de plástico marca o final da propriedade da companhia telefônica e o início
da propriedade do cliente. Próximo ao ND (ou às vezes combinado com ele) há um divisor, um filtro analógico
que separa a faixa de 0–4.000 Hz usada pelo POTS dos dados. O sinal do POTS é direcionado ao telefone ou apa-
relho de fax e o sinal de dados é direcionado a um modem ADSL. Na verdade, o modem ADSL é um processador
de sinais digitais que foi montado para agir como 250 modems funcionando em paralelo a frequências diferentes.
Uma vez que a maioria dos modems ADSL é externa, o computador deve estar conectado a ele em alta velocidade.
sso costuma ser feito com a instalação de uma placa Ethernet no computador e operação de uma Ethernet muito
curta de dois nós que contém apenas o computador e o modem ADSL. (Ethernet é um padrão de rede local popular
e barato.) Por vezes, usa-se a porta USB em vez da Ethernet. Sem dúvida, haverá placas internas de modem ADSL
disponíveis no futuro.
0 25 1.100 kHz
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 103
Figura 2.40 Configurac
a
o t
pica de equipamento ADSL.
Comutador
de voz
Codec
Divisor
DSLAM
Para o ISP
Escritório da companhia telefônica
Linha
telefônica
Telefone
Divisor
Computador
Modem
ADSL
Ethernet
Casa ou escritório do cliente
NID
Na outra extremidade da linha, no lado da empresa telefônica está instalado um divisor correspondente, no
qual a parte da voz é filtrada e enviada ao comutador de voz normal. O sinal acima de 26 kHz é direcionado para
um novo tipo de dispositivo denominado SLM (igital Subscriber Line ccess Multiplexer  multiplexador
de acesso de linha digital de assinante), que contém o mesmo tipo de processador de sinal digital que o modem
ADSL. Uma vez recuperado o sinal digital em um fluxo de bits, são formados pacotes e enviados à SP
.
Internet por cabo
Muitas empresas de T agora estão oferecendo acesso à nternet por meio de seus cabos. Como a tecnologia
é muito diferente da ADSL, vale a pena fazer uma breve descrição. Em cada cidade, a operadora por cabo tem
uma central e uma grande quantidade de caixas cheias de dispositivos eletrônicos denominados terminais de
distribuição (headends) distribuídos por todo o seu território. Os terminais de distribuição estão conectados à
central por cabos de alta largura de banda ou de fibra ótica.
Cada terminal tem um ou mais cabos que passam por centenas de casas e escritórios. Cada cliente da prove-
dora por cabo está ligado ao cabo que passa por sua casa ou escritório. Assim, centenas de usuários compartilham
o mesmo cabo até o terminal. Em geral, o cabo tem uma largura de banda de mais ou menos 750 MHz. Esse
sistema é radicalmente diferente do ADSL porque cada usuário de telefone tem uma linha privada (isto é, não
compartilhada) com a central telefônica. Contudo, na prática, ter seu próprio canal de 1,1 MHz com uma empresa
de telefonia não é muito diferente do que compartilhar uma porção de 200 MHz do espectro do cabo que chega
ao terminal com 400 usuários, metade dos quais não o estará usando em qualquer dado momento. Porém, isso
significa que um usuário de nternet por cabo conseguirá um serviço muito melhor às 4h00 do que às 16h00,
enquanto o serviço ADSL é constante durante o dia inteiro. Quem quiser obter um serviço ideal de nternet por
cabo deveria se mudar para uma vizinhança rica (casas mais afastadas uma da outra, portanto, menos usuários
por cabo) ou para um bairro pobre (onde ninguém pode pagar pelo serviço de nternet).
Uma vez que o cabo é um meio compartilhado, determinar quem pode enviar quando e em qual frequência
é uma questão importante. Para ver como isso funciona, temos de fazer um breve resumo do modo de funciona-
mento de uma T a cabo. Nos Estados Unidos, os canais de televisão a cabo ocupam a região de 54 a 550 MHz
(exceto para rádio FM, de 88 a 108 MHz). Esses canais têm 6 MHz de largura, incluindo faixas de proteção para impe-
dir vazamento de sinal entre canais. Na Europa, a extremidade baixa é normalmente 65 MHz e os canais têm de 6 a 8
MHz de largura para a resolução mais alta exigida por PAL e SECAM; porém, quanto ao mais, o esquema de alocação
é similar. A porção inferior da banda não é usada para transmissão de televisão.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
104
Quando as empresas por cabo lançaram a nternet por cabo, tinham dois problemas a resolver:
1. Como acrescentar acesso à nternet sem interferir com programas de T.
2. Como ter tráfego bidirecional quando os amplificadores são inerentemente unidirecionais.
As soluções são as seguintes. Cabos modernos têm uma largura de banda de pelo menos 550 MHz, muitas
vezes até 750 MHz ou mais. Os canais ascendentes (isto é, do usuário ao terminal de distribuição) entram na
faixa de 5–42 MHz (um pouco mais alta na Europa), e o tráfego descendente (isto é, do terminal de distribuição
ao usuário) usa as frequências da extremidade alta, como ilustrado na Figura 2.41.
Figura 2.41 Alocac
a
o de freque
ncia em um sistema t
pico de TV a cabo usado para acesso a
 Internet.
0 108 550 750 MHz
5 42 54 88
Dados
ascendentes
Dados descendentes
Frequências
ascendentes
Frequências descendentes
TV FM TV
Note que, como os sinais de T são todos descendentes, é possível usar amplificadores ascendentes que
funcionam apenas na região de 5 a 42 MHz, e amplificadores descendentes que só funcionam a 54 MHz e acima,
conforme mostra a figura. Assim, obtemos uma assimetria nas larguras de banda ascendente e descendente, por-
que há mais espectro disponível acima da banda da televisão do que abaixo dela. Por outro lado, a maior parte
do tráfego será provavelmente na direção descendente, portanto, as operadoras por cabo não estão infelizes com
essas coisas da vida. Como vimos antes, empresas de telefonia costumam oferecer um serviço DSL assimétrico,
ainda que não tenham nenhuma razão técnica para fazê-lo.
O acesso à nternet requer um modem por cabo, um dispositivo que tem duas interfaces: uma com o compu-
tador e outra com a rede a cabo. A interface computador-modem a cabo é direta. Em geral, é Ethernet, exatamente
como na ADSL. No futuro, o modem inteiro poderá se resumir a uma pequena placa inserida no computador,
exatamente como nos antigos modems por telefone.
A outra extremidade é mais complicada. Grande parte do padrão por cabo lida com engenharia de rádio, uma
questão que está muito além do escopo deste livro. A única parte que vale a pena mencionar é que modems por
cabo, assim como os ADSL, estão sempre ligados. Eles estabelecem uma conexão quando são ligados e a mantêm
enquanto houver energia, porque operadoras por cabo não cobram por tempo de conexão.
Para entender melhor como elas funcionam, vamos ver o que acontece quando um modem por cabo é ins-
talado e ligado. O modem faz uma varredura dos canais descendentes em busca de um pacote especial lançado
periodicamente pelo terminal de distribuição para fornecer parâmetros do sistema aos modems que acabaram de
entrar em linha. Quando achar esse pacote, o novo modem anuncia sua presença em um dos canais ascendentes. O
terminal de distribuição responde designando o modem a seus canais ascendente e descendente. Essas designações
podem ser mudadas mais tarde se o terminal de distribuição achar necessário equilibrar a carga.
O modem determina sua distância em relação ao terminal de distribuição enviando um pacote especial e
observando quanto tempo demora para obter uma resposta. Esse processo é denominado ranging. É importante
que o modem conheça sua distância para ajustar o modo como os canais ascendentes operam e para acertar sua
temporização. Eles são divididos em mini-intervalos de tempo. Cada pacote ascendente deve se ajustar a um ou
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 105
mais mini-intervalos de tempo consecutivos. O terminal de distribuição anuncia periodicamente o início de uma
nova rodada de mini-intervalos, mas o tiro de largada não é ouvido por todos os modems simultaneamente por
causa do tempo de propagação pelo cabo. Sabendo a que distância está do terminal de distribuição, cada modem
pode calcular há quanto tempo o primeiro mini-intervalo de fato começou. O comprimento do mini-intervalo
depende da rede. Uma carga útil típica é 8 bytes.
Durante a inicialização, o terminal de distribuição também designa cada modem a um mini-intervalo que será
usado para requisitar largura de banda ascendente. Como regra, múltiplos modems serão designados ao mesmo
mini-intervalo, o que leva à disputa. Quando um computador quer enviar um pacote, ele o transfere ao modem,
que então requisita o número necessário de mini-intervalos para ele. Se a requisição for aceita, o terminal de
distribuição manda um reconhecimento pelo canal descendente, informando ao modem quais mini-intervalos
foram reservados para seu pacote. Então, o pacote é enviado, começando no mini-intervalo a ele alocado. Pacotes
adicionais podem ser requisitados usando um campo no cabeçalho.
Por outro lado, se houver disputa para o mini-intervalo requisitado, nenhum reconhecimento será enviado e
o modem espera um tempo aleatório, e tenta mais uma vez. Após cada uma dessas tentativas sucessivas malsuce-
didas, o tempo aleatório é duplicado para distribuir a carga quando o tráfego estiver pesado.
Os canais descendentes são gerenciados de modo diferente dos canais ascendentes. Uma razão é que há só
um remetente (o terminal de distribuição), portanto, não há nenhuma disputa e nenhuma necessidade de mini-
-intervalos que, na verdade, é apenas um modo de multiplexação por divisão estatística. Outra razão é que o
tráfego descendente costuma ser muito maior do que o ascendente, portanto, é um pacote de tamanho fixo de
204 bytes. Parte dele é um código de correção de erros Reed-Solomon e algumas outras informações de controle,
sobrando 184 bytes de carga útil para o usuário. Esses números foram escolhidos por compatibilidade com a
televisão digital, que usa MPEG-2, de modo que os canais de T e os canais descendentes sejam formatados do
mesmo modo. O aspecto lógico das conexões é mostrado na Figura 2.42.
Figura 2.42 Detalhes t
picos dos canais ascendente e descendente na Ame
rica do Norte. QAM-64 (Quadrature Amplitude Modulation –
modulac
a
o de amplitude em quadratura) permite 6 bits/Hz, mas funciona somente em altas freque
ncias. QPSK (Quadrature
Phase Shift Keying – modulac
a
o por chaveamento de fase em quadratura) funciona em baixas freque
ncias, mas permite
apenas 2 bits/Hz.
Canal ascendente com contenção:
9 Mbps usando QPSK e mini-intervalos de
8 bytes
Cabo coaxial Canal descendente sem contenção: 27 Mbps
usando QAM-64 e cargas úteis de 184 bytes
Fibra
Terminal
Pacote
Modem
ISP
oltando à inicialização do modem, uma vez concluída a ranging e obtida a designação de seu canal ascendente,
canal descendente e mini-intervalo, ele está liberado para começar a enviar pacotes. Esses pacotes vão até o terminal
de distribuição, que os retransmite por um canal dedicado até a central da operadora por cabo e então até o SP (que
pode ser a própria empresa por cabo). O primeiro pacote é dirigido à SP e requisita um endereço de rede (tecni-
camente, um endereço P) que é designado dinamicamente. O pacote também requisita e obtém um horário exato.
A próxima etapa envolve segurança. Uma vez que o cabo é um meio compartilhado, quem quiser se dar ao
trabalho pode ler todo o tráfego que passar por ele. Para evitar que qualquer um bisbilhote seus vizinhos (lite-
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
106
ralmente), todo o tráfego é criptografado em ambas as direções. Parte do procedimento de inicialização envolve
estabelecer chaves criptográficas. A princípio, poderíamos pensar que conseguir que dois estranhos, o terminal
de distribuição e o modem, combinem uma chave secreta em plena luz do dia com milhares de pessoas vigiando
seria algo difícil. Acontece que não é, mas a técnica usada (o algoritmo Diffie-Hellman) está fora do escopo deste
livro. Uma discussão sobre esse algoritmo é dada em Kaufman et al. (2002).
Por fim, o modem tem de registrar (fazer login) e fornecer seu identificador exclusivo pelo canal seguro.
Nesse ponto, está concluída a inicialização. Agora, o usuário pode se conectar com o SP e começar a trabalhar.
Há muito mais a ser dito sobre modems a cabo. Algumas referências relevantes são: Adams e Dulchinos, 2001;
Donaldson e Jones, 2001; Dutta-Roy, 2001.
2.4.7 Ca
meras digitais
Uma utilização cada vez mais popular de computadores é a fotografia digital, o que transforma câmeras
digitais em uma espécie de periférico de computador. amos descrever rapidamente como isso funciona.
Todas as câmeras têm uma lente que forma uma imagem do sujeito no fundo da câmera. Em um equipamen-
to convencional, o fundo da câmera está coberto por uma película fotográfica sobre a qual é formada uma
imagem latente quando a luz a atinge. Essa imagem latente pode ficar visível pela ação de certos produtos
químicos presentes no líquido de revelação, ou revelador. Uma câmera digital funciona da mesma maneira,
exceto que o filme é substituído por um arranjo retangular de CCs (Charge-Coupled evices  disposi-
tivos de carga acoplada) sensíveis à luz. (Algumas câmeras digitais usam CMOS [Complementary Metal-
-Oxyde Semiconductor – semicondutor de óxido metálico complementar], mas aqui vamos nos concentrar
nos CCDs, que são mais comuns.)
Quando a luz atinge um CCD, ele adquire uma carga elétrica. Quanto mais luz, mais carga. A carga pode ser
lida em um conversor analógico para digital como um inteiro de 0 a 255 (em câmeras mais baratas) ou de 0 a
4.095 (em câmeras reflex digitais de uma lente). A configuração básica é mostrada na Figura 2.43.
Figura 2.43 Ca
mera digital.
R R
B
R R
B B
B
G
G
G
G
G
G G
G
Um pixel é composto
de quatro CCDs, um
vermelho (R), um azul
(B) e dois verdes (G).
Lente Diafragma
Arranjo de
CCDs
CPU
RAM
Memória flash
Câmera digital
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 107
Cada CCD produz um único valor, independente da cor da luz que o atinge. Para formar imagens colo-
ridas, os CCDs são organizados em grupos de quatro elementos. Um filtro Bayer é colocado no topo do
CCD de modo a permitir que somente a luz vermelha atinja um dos quatro em cada grupo, apenas a luz azul
atinja um outro e só a luz verde atinja os outros dois. São usados dois CCDs para a luz verde porque utilizar
quatro CCDs para representar um pixel é muito mais conveniente do que usar três, e o olho é mais sensível
à luz verde do que à vermelha ou à azul. Quando um fabricante afirma que uma câmera tem, por exemplo,
6 milhões de pixels, ele está mentindo. A câmera tem 6 milhões de CCDs que, juntos, formam 1,5 milhão
de pixels. A imagem será lida como um arranjo de 2.828 × 2.121 pixels (em câmeras de baixo preço) ou de
3.000 × 2.000 pixels (em SLRs digitais), mas os pixels extras são produzidos por interpolação pelo software
dentro da câmera.
Quando o botão do obturador da câmera é pressionado, o software no equipamento realiza três tare-
fas: ajusta o foco, determina a exposição e efetua o equilíbrio do branco. O autofoco funciona analisando a
informação de alta frequência na imagem e então movimentando a lente até que ela seja maximizada, para
dar o máximo de detalhe. A exposição é determinada medindo a luz que cai sobre os CCDs e então ajustando
o diafragma da lente e o tempo de exposição para fazer a intensidade da luz cair no meio da faixa de alcance
dos CCDs. Ajustar o equilíbrio do branco tem a ver com medir o espectro da luz incidente para efetuar as
necessárias correções de cor mais tarde.
Então, a imagem é lida com base nos CCDs e armazenada como um arranjo de pixels na RAM interna da
câmera. SLRs de primeira linha usados por fotojornalistas podem fotografar oito quadros de alta resolução por
segundo por 5 segundos, e precisam de cerca de 1 GB de RAM interna para armazenar as imagens antes de
processá-las e armazená-las permanentemente. Câmeras mais baratas têm menos RAM, mas ainda assim têm boa
quantidade.
Na fase de pós-captura, o software da câmera aplica correção da cor por equilíbrio do branco para compensar
a luz avermelhada ou azulada (por exemplo, de um objeto na sombra ou da utilização de um flash). Em seguida,
ele aplica um algoritmo para reduzir ruído e outro para compensar CCDs defeituosos. Logo após, o software
tenta dar melhor definição à imagem (a menos que essa característica esteja desativada), procurando contornos e
aumentando o gradiente de intensidade ao redor deles.
Por fim, a imagem pode ser comprimida para reduzir a quantidade de armazenagem requerida. Um formato
comum é o JPEG (Joint Photographic Experts Group  grupo associado de especialistas em fotografia), no qual
uma transformada de Fourier espacial bidimensional é aplicada e alguns dos componentes de alta frequência são
omitidos. O resultado dessa transformação é que a imagem requer um número menor de bits de armazenagem,
mas perdem-se os detalhes mais sutis.
Quando todo processamento interno à câmera estiver concluído, a imagem é gravada no meio de armaze-
nagem, em geral uma memória rápida ou um minúsculo disco rígido removível denominado microdrive. O pós-
-processamento e a gravação podem levar vários segundos por imagem.
Quando o usuário chega em casa, a câmera pode ser conectada a um computador, em geral usando, por
exemplo, uma entrada USB ou um cabo específico. Então, as imagens são transferidas da câmera para o disco
rígido do computador. Usando software especial, tal como o Adobe Photoshop, o usuário pode recortar a imagem,
ajustar brilho, contraste e equilíbrio de cor, destacar, escurecer ou remover porções da imagem e aplicar diversos
filtros. Quando ele estiver contente com o resultado, os arquivos podem ser impressos em uma impressora em
cores, enviados pela nternet a uma loja especializada para fazer o acabamento ou gravados em um CD-ROM ou
DD para armazenagem em arquivo e subsequente impressão.
A quantidade de capacidade computacional, RAM, espaço em disco rígido e software em uma câmera digital
SLR é estarrecedora. Além de o computador ter de fazer todas as coisas mencionadas, ainda precisa se comunicar
com a CPU na lente e com a CPU na memória rápida, renovar a imagem na tela LCD e gerenciar todos os botões,
engrenagens, luzes, mostradores e dispositivos da câmera em tempo real. Esse sistema embutido é extremamente
poderoso e muitas vezes rivaliza com um computador de mesa de apenas alguns anos atrás.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
108
2.4.8 Co
digos de caracteres
Cada computador tem um conjunto de caracteres que ele usa. O conjunto mínimo contém as 26 letras
maiúsculas, as 26 letras minúsculas, os algarismos de 0 a 9 e um conjunto de símbolos especiais, como espaço,
sinal de menos, vírgula e retorno ao início da linha.
Para transferir esses caracteres para o computador, um número é designado a cada um, por exemplo, a
= 1, b = 2, ..., z = 26, + = 27, – = 28. O mapeamento de caracteres para números inteiros é denominado código
de caracteres. É essencial que computadores que se comunicam usem o mesmo código ou não conseguirão se
entender. Por essa razão, foram desenvolvidos padrões. A seguir, examinaremos dois dos mais importantes.
ASCII
Um código de ampla utilização é denominado SCII (merican Standard Code for Information Interchange 
código padrão americano para troca de informações). Cada caractere ASC tem 7 bits, o que permite 128
caracteres no total. Porém, como os computadores são orientados a byte, cada caractere ASC é armazenado em
um byte separado. A Figura 2.44 mostra o código ASC. Os códigos de 0 a 1F (hexadecimal) são caracteres de
controle e não são impressos. Os códigos de 128 a 255 não fazem parte do ASC, mas o BM PC os definiu para
serem caracteres especiais, como os smileys, e a maioria dos computadores tem suporte para eles.
Figura 2.44 O conjunto de caracteres ASCII.
Hexa Nome Significado Hexa Nome Significado
0 NUL Null 10 DLE Data Link Escape
1 SOH Start Of Heading 11 DC1 Device Control 1
2 STX Start Of TeXt 12 DC2 Device Control 2
3 ETX End Of TeXt 13 DC3 Device Control 3
4 EOT End Of Transmission 14 DC4 Device Control 4
5 ENQ Enquiry 15 NAK Negative AcKnowledgement
6 ACK ACKnowledgement 16 SYN SYNchronous idle
7 BEL BELl 17 ETB End of Transmission Block
8 BS BackSpace 18 CAN CANcel
9 HT Horizontal Tab 19 EM End of Medium
A LF Line Feed 1A SUB SUBstitute
B VT Vertical Tab 1B ESC ESCape
C FF Form Feed 1C FS File Separator
D CR Carriage Return 1D GS Group Separator
E SO Shift Out 1E RS Record Separator
F SI Shift In 1F US Unit Separator
Hexa Car Hexa Car Hexa Car Hexa Car Hexa Car Hexa Car
20 Espaço 30 0 40 @ 50 P 60 ' 70 p
21 ! 31 1 41 A 51 Q 61 a 71 q
22 " 32 2 42 B 52 R 62 b 72 r
23 # 33 3 43 C 53 S 63 c 73 s
24 $ 34 4 44 D 54 T 64 d 74 t
25 % 35 5 45 E 55 U 65 e 75 u
26 & 36 6 46 F 56 V 66 f 76 v
27 ' 37 7 47 G 57 W 67 g 77 w
28 ( 38 8 48 H 58 X 68 h 78 x
29 ) 39 9 49 I 59 Y 69 i 79 y
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 109
Hexa Car Hexa Car Hexa Car Hexa Car Hexa Car Hexa Car
2A * 3A : 4A J 5A Z 6A j 7A z
2B + 3B ; 4B K 5B [ 6B k 7B {
2C , 3C < 4C L 5C  6C l 7C |
2D - 3D = 4D M 5D ] 6D m 7D }
2E . 3E > 4E N 5E ^ 6E n 7E ~
2F / 3F ? 4F O 5F _ 6F o 7F DEL
Muitos dos caracteres de controle ASC são destinados à transmissão de dados. Por exemplo, uma men-
sagem pode ser composta de um caractere SOH (start of header – início de cabeçalho), um caractere ST (start
of text – início de texto), o texto em si, um caractere ET (end of text – fim do texto) e então um caractere EOT
(end of transmission – fim da transmissão). Contudo, na prática, as mensagens enviadas por linhas telefônicas e
redes são formatadas de modo muito diferente, de modo que os caracteres ASC de controle de transmissão já
não são muito usados.
Os caracteres de impressão ASC são diretos. ncluem as letras maiúsculas e minúsculas, dígitos, sinais de
pontuação e alguns símbolos matemáticos.
Unicode
A indústria do computador se desenvolveu em grande parte nos Estados Unidos, o que levou ao conjunto
de caracteres ASC. Esse código é bom para a língua inglesa, mas não tão bom para outros idiomas. O francês
precisa de acentos (por exemplo, système); o alemão precisa de sinais diacríticos (por exemplo, für) e assim por
diante. Algumas línguas europeias têm certas letras que não se encontram no ASC, tais como a alemã ß e a
dinamarquesa ø. Alguns idiomas têm alfabetos inteiramente diferentes (por exemplo, russo e árabe), e algumas
poucas línguas não têm alfabeto algum (por exemplo, a chinesa). Como os computadores se espalharam pelos
quatro cantos do mundo e como os fabricantes de software querem vender produtos em países onde a maioria
dos usuários não fala inglês, é preciso um novo conjunto de caracteres.
A primeira tentativa de ampliar o ASC foi o S 646, que acrescentou mais 128 caracteres ao ASC, trans-
formando-o em um código de 8 bits denominado Latin-1. A maioria dos caracteres adicionais eram letras latinas
com acentos e sinais diacríticos. A próxima tentativa foi o S 8859, que introduziu o conceito de uma página de
código, um conjunto de 256 caracteres para um idioma particular ou grupo de idiomas. O S 8859-1 é Latin-1.
O S 8859-2 trata dos idiomas eslavos baseados no latim (por exemplo, tcheco, polonês e húngaro). O S 8859-3
contém os caracteres necessários para os idiomas turco, maltês, esperanto, galego e assim por diante. O problema
da abordagem da página de código é que o software tem de manter controle da página em que está; é impossível
misturar idiomas nas páginas e o esquema não cobre a língua japonesa nem a chinesa.
Um grupo de empresas de computadores resolveu esse problema formando um consórcio para criar um novo
sistema, denominado Unicode, e transformando-o em um Padrão nternacional (S 10646). Agora, o Unicode é
suportado por algumas linguagens de programação (por exemplo, Java), alguns sistemas operacionais (por exem-
plo, Windows) e muitas aplicações.
A ideia que fundamenta o Unicode é designar a cada caractere e símbolo um valor único de 16 bits, deno-
minado ponto de código. Não são usados caracteres multibytes nem sequências de escape. Símbolos de 16 bits
simplificam a escrita do software.
Com símbolos de 16 bits, o Unicode tem 65.536 pontos de código. isto que todos os idiomas do mundo usam
cerca de 200 mil símbolos, os pontos de código são um recurso escasso que deve ser alocado com grande cuidado.
Para acelerar a aceitação do Unicode, o consórcio teve a brilhante ideia de usar Latin-1 como pontos de código 0 a
255, o que facilita a conversão entre ASC e Unicode. Para evitar desperdiçar pontos de código, cada sinal diacrítico
tem seu próprio ponto de código. Cabe ao software combinar sinais diacríticos com seus vizinhos para formar novos
caracteres. Embora isso aumente o trabalho do software, economiza preciosos pontos de código.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
110
O espaço do ponto de código é dividido em blocos, cada qual um múltiplo de 16 pontos de código. Todo alfa-
beto importante em Unicode tem uma sequência de zonas consecutivas. Alguns exemplos (e o número de pontos
de código alocados) são latim (336), grego (144), cirílico (256), armênio (96), hebraico (112), devanágari (128),
gurmuqui (128), oriá (128), telugo (128) e canará (128). Note que cada um desses idiomas recebeu um número
maior de pontos de código do que número de letras que possui. Essa opção foi escolhida em parte porque muitas
línguas têm várias formas para cada letra. Por exemplo, cada letra em português tem duas formas – minúscula e
MAÚSCULA. Alguns idiomas têm três ou mais formas, possivelmente dependendo de a letra estar no início, no
meio ou no final de uma palavra.
Além desses alfabetos, foram designados pontos de código para sinais diacríticos (112), sinais de pontuação
(112), subscritos e sobrescritos (48), símbolos monetários (48), símbolos matemáticos (256), formas geomé-
tricas (96) e sinais variados (dingbats) (192).
Depois desses, vêm os símbolos necessários para as línguas chinesa, japonesa e coreana. Primeiro, há 1.024
símbolos fonéticos (por exemplo, katakana e bopomofo) e, em seguida, os ideogramas han unificados (20.992)
usados em chinês e japonês, e as sílabas hangul do idioma coreano (11.156).
Para permitir que os usuários inventem caracteres especiais para finalidades especiais, 6.400 pontos de códi-
go foram designados para uso local.
Embora o Unicode solucione muitas dificuldades associadas com a internacionalização, ele não resolve (nem
tenta resolver) todos os problemas do mundo. Por exemplo, enquanto o alfabeto latino está em ordem alfabética,
os ideogramas han não estão na ordem do dicionário. Por conseguinte, um programa em inglês pode procurar cat
e dog em ordem alfabética simplesmente comparando o valor Unicode de seu primeiro caractere. Um programa
em japonês precisa de tabelas externas para interpretar qual dos dois símbolos vem antes do outro no dicionário.
Outra questão é que surgem novas palavras o tempo todo. Há 50 anos ninguém falava de applets, ciberespaço,
gigabytes, lasers, modems, smileys ou videoteipes. Acrescentar novas palavras em inglês não requer novos pontos
de código, mas adicioná-las em japonês, sim. Além de novas palavras técnicas, há uma demanda para adicionar
no mínimo 20 mil novos nomes de pessoas e lugares (a maioria chineses). Os cegos acham que o braille deveria
estar presente e grupos de interesse especial de todos os tipos querem o que entendem como pontos de código a
que têm direito. O consórcio Unicode estuda e decide todas as novas propostas.
O Unicode usa o mesmo ponto de código para caracteres que parecem quase idênticos mas têm significados
diferentes ou são escritos de maneira ligeiramente diferente em japonês e chinês (como se processadores de texto
em inglês sempre escrevessem blue como blew, porque têm o mesmo som). Há quem considere isso uma otimização
para economizar pontos de código escassos; outros o veem como imperialismo cultural anglo-saxão (e você acha que
designar 16 bits para caracteres não foi uma decisão muito política?). Para piorar as coisas, um dicionário japonês
completo tem 50 mil kanji (excluindo nomes), portanto, com apenas 20.992 pontos de código disponíveis para os
ideogramas han, escolhas tiveram de ser feitas. Nem todos os japoneses acham que um consórcio de fabricantes de
computadores – mesmo que alguns deles sejam japoneses – é o fórum ideal para fazer essas escolhas.
Adivinha só: 65.536 pontos de código não foram suficientes para satisfazer a todos, de modo que, em 1996,
16 planos adicionais de 16 bits cada foram acrescentados, expandindo o número total de caracteres para 1.114.112.
UTF-8
Embora melhor que o ASC, o Unicode por fim esgotou os pontos de código e também requer 16 bits por
caractere para representar o texto ASC puro, o que é um desperdício. Por conseguinte, outro esquema de codifi-
cação foi desenvolvido para resolver essas questões. Ele é denominado Formato de ransformação UF-8 UCS,
em que UCS significa Universal Character Set (conjunto de caracteres universal), que é Unicode na essência.
Códigos UTF-8 têm tamanho variável, de 1 a 4 bytes, e podem codificar cerca de dois bilhões de caracteres. Ele
é o conjunto de caracteres dominante em uso na Web.
Uma das propriedades interessantes do UTF-8 é que os códigos de 0 a 127 são os caracteres ASC, permitin-
do que sejam expressos em 1 byte (contra os 2 bytes do Unicode). Para caracteres que não são ASC, o bit de alta
ordem do primeiro byte é definido como 1, indicando que virão 1 ou mais bytes adicionais. No fim, seis formatos
diferentes são usados, conforme ilustra a Figura 2.45. Os bits marcados com “d” são bits de dados.
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 111
Figura 2.45 O esquema de codificac
a
o UTF-8.
Bits Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6
7 0ddddddd
11 110ddddd 10dddddd
16 1110dddd 10dddddd 10dddddd
21 11110ddd 10dddddd 10dddddd 10dddddd
26 111110dd 10dddddd 10dddddd 10dddddd 10dddddd
31 1111110d 10dddddd 10dddddd 10dddddd 10dddddd 10dddddd
O UTF-8 tem uma série de vantagens em relação ao Unicode e outros esquemas. Primeiro, se um programa
ou documento utiliza apenas caracteres que estão no conjunto ASC, cada um pode ser representado em 8 bits.
Segundo, o primeiro byte de cada caractere UTF-8 determina exclusivamente o número de bytes deste. Terceiro,
os bytes de continuação em um caractere UTF-8 sempre começam com 10, enquanto o byte inicial nunca começa
assim, tornando o código autossincronizável. Em particular, no caso de um erro de comunicação ou memória,
sempre é possível prosseguir e achar o início do próximo caractere (supondo que ele não tenha sido danificado).
Em geral, o UTF-8 é usado para codificar apenas os 17 planos Unicode, embora o esquema tenha muito
mais de 1.114.112 pontos de código. Porém, se os antropólogos descobrirem novas tribos em Nova Guiné (ou em
outro lugar) cujos idiomas ainda não sejam conhecidos (ou se, no futuro, fizermos contato com extraterrestres),
o UTF-8 conseguirá acrescentar seus alfabetos ou ideogramas.
2.5 Resumo
Sistemas de computadores são compostos por três tipos de componentes: processadores, memórias e dispo-
sitivos de E/S. A tarefa de um processador é buscar instruções, uma por vez, em uma memória, decodificá-las e
executá-las. O ciclo busca-decodificação-execução pode ser descrito como um algoritmo e, na verdade, às vezes ele
é executado por um interpretador de software que roda em um nível mais baixo. Para ganhar velocidade, muitos
computadores agora têm um ou mais pipelines (paralelismo) ou têm um projeto superescalar com múltiplas uni-
dades funcionais que funcionam em paralelo. Um pipeline permite que uma instrução seja dividida em etapas e as
etapas para diferentes instruções sejam executadas ao mesmo tempo. Múltiplas unidades funcionais é outra forma
de obter paralelismo sem afetar o conjunto de instruções ou a arquitetura visível ao programador ou compilador.
Sistemas com vários processadores são cada vez mais comuns. Computadores paralelos incluem processa-
dores matriciais, nos quais a mesma operação é efetuada sobre múltiplos conjuntos de dados ao mesmo tempo;
multiprocessadores, nos quais várias CPUs compartilham uma memória; e multicomputadores, nos quais cada
um dos vários computadores tem sua própria memória, mas se comunicam passando mensagens.
Memórias podem ser categorizadas como primárias ou secundárias. A memória primária é usada para conter o
programa que está sendo executado no momento. Seu tempo de acesso é curto – algumas poucas dezenas de nanos-
segundos, no máximo – e independe do endereço que está sendo acessado. Caches reduzem ainda mais esse tempo
de acesso. Eles são necessários porque as velocidades do processador são muito maiores do que as velocidades da
memória, o que significa que ter de esperar pelos acessos à memória o tempo todo atrasa bastante a execução
do processador. Algumas memórias são equipadas com códigos de correção de erros para aumentar a confiabilidade.
Memórias secundárias, ao contrário, têm tempos de acesso muito mais longos (milissegundos ou mais) e
dependem da localização dos dados que estão sendo lidos ou escritos. Fitas, discos magnéticos e discos ópticos
são as memórias secundárias mais comuns. Há muitas variedades de discos magnéticos, incluindo discos DE,
discos SCS e RADs. Entre os discos ópticos figuram CD-ROMs, CD-Rs, DDs e Blu-rays.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
112
Dispositivos de E/S são usados para transferir informações para dentro e para fora do computador. Então, são
conectados ao processador e à memória por um ou mais barramentos. Alguns exemplos são terminais, mouses,
impressoras e modems. A maioria dos dispositivos de E/S usa o código de caracteres ASC, embora o Unicode
também seja usado e o UTF-8 esteja ganhando rápida aceitação à medida que a indústria de computadores se
volta mais para a Web.
Problemas
1. Considere a operação de uma máquina que tenha
o caminho de dados da Figura 2.2. Suponha que
carregar os registradores de entrada da ULA leve
5 ns, executar a ULA demore 10 ns e armazenar o
resultado de volta no registrador de rascunho tome
5 ns. Qual é o número máximo de MPS de que
essa máquina é capaz na ausência de paralelismo
(pipelining)?
2. Qual é a finalidade da etapa 2 na lista da Seção 2.1.2?
O que aconteceria se essa etapa fosse omitida?
3. No computador 1, o tempo de execução de todas as
instruções é 10 ns. No computador 2, o tempo de
execução é de 5 ns. ocê pode afirmar com certeza
que o computador 2 é mais rápido? Discuta sua
resposta.
4. magine que você está projetando um computador de
um só chip para um sistema embutido. O chip conte-
rá toda sua memória e executará à mesma velocidade
da CPU sem penalidade de acesso. Examine cada um
dos princípios discutidos na Seção 2.1.4 e diga por
que são tão importantes (admitindo que ainda se
deseje alto desempenho).
5. Para competir com a prensa impressora recentemen-
te inventada, um mosteiro medieval decidiu produzir
em massa livros escritos em papel, reunindo um
vasto número de escribas em uma grande sala. O
superior do mosteiro então ditaria a primeira palavra
do livro a ser produzido e todos os escribas a escre-
veriam. Em seguida, ele ditaria a segunda palavra e
todos os escribas a escreveriam. Esse processo seria
repetido até que o livro inteiro fosse lido e copiado.
Com qual dos sistemas de processador paralelo dis-
cutidos na Seção 2.1.6 esse sistema é mais parecido?
6. À medida que descemos na hierarquia de memória
de cinco níveis discutida no texto, o tempo de aces-
so aumenta. Faça uma estimativa razoável da razão
entre o tempo de acesso por disco óptico e o tempo
de acesso ao registrador da memória. Suponha que o
disco já esteja on-line.
7. Sociólogos podem obter três respostas possíveis para
uma típica pergunta de levantamento como “ocê
acredita em Papai Noel?” – ou seja: sim, não, nenhu-
ma opinião. Tendo isso em mente, a Sociomagnetic
Computer Company decidiu construir um com-
putador para processar os dados do levantamento.
Esse computador tem uma memória ternária, isto
é, cada byte (tryte?) consiste em 8 trits, sendo que
um trit contém um 0, um 1 ou um 2. Quantos trits
são necessários para conter um número de 6 bits?
Escreva uma expressão para o número de trits neces-
sário para conter n bits.
8. Calcule a taxa de dados do olho humano usando
as seguintes informações. O campo visual consiste
em cerca de 106
elementos (pixels). Cada pixel pode
ser reduzido a uma sobreposição das três cores pri-
márias, cada uma com 64 intensidades. A resolução
temporal é de 100 ms.
9. Calcule a taxa de dados do ouvido humano usando
as seguintes informações. As pessoas podem ouvir
frequências de até 22 kHz. Para capturar toda a
informação em um sinal sonoro a 22 kHz, é preciso
amostrar o som a duas vezes aquela frequência, isto
é, a 44 kHz. Uma amostra de 16 bits provavelmente
basta para capturar a maioria das informações auditi-
vas (isto é, o ouvido não pode distinguir mais do que
65.535 níveis de intensidade).
10. As informações genéticas de todos os seres viventes
estão codificadas como moléculas de DNA. Uma
molécula de DNA é uma sequência linear dos quatro
nucleotídeos básicos: A, C, G e T. O genoma humano
contém cerca de 3 × 109
nucleotídeos na forma de
mais ou menos 30 mil genes. Qual é a capacidade
total de informações (em bits) do genoma humano?
Qual é a capacidade máxima de informações (em
bits) do gene médio?
11. Certocomputadorpodeserequipadocom1.073.741.824
bytes de memória. Por que um fabricante escolheria tal
número peculiar, em vez de um número fácil de lem-
brar, como 1 milhão?
12. nvente um código de Hamming de paridade par de
7 bits para os dígitos 0 a 9.
13. nvente um código para os dígitos 0 a 9 cuja distância
de Hamming seja 2.
14. Em um código de Hamming, alguns bits são “des-
perdiçados” no sentido de que são usados para
verificação, e não para informação. Qual é a porcen-
tagem de bits desperdiçados para mensagens cujo
C a p 
t u l o 2 O r g a n i z a c
 a
 o d e s i s t e m a s d e c o m p u t a d o r e s 113
comprimento total (dados + bits de verificação) é
2n
– 1? Avalie essa expressão numericamente para
valores de n de 3 a 10.
15. Um caractere ASC estendido é representado por uma
quantidade de 8 bits. A codificação de Hamming asso-
ciada a cada caractere pode então ser representada por
uma sequência de três dígitos hexa. Codifique o seguin-
te texto ASC estendido de cinco caracteres usando um
código de Hamming com paridade par: Earth. Mostre
sua resposta como uma sequência de dígitos hexa.
16. A sequência de dígitos hexa a seguir codifica carac-
teres ASC estendidos em um código de Hamming
com paridade par: 0D3 DD3 0F2 5C1 1C5 CE3.
Decodifique essa sequência e escreva os caracteres
que são codificados.
17. O disco ilustrado na Figura 2.19 tem 1.024 setores/
trilha e uma taxa de rotação de 7.200 RPM. Qual é a
taxa de transferência sustentada do disco sobre uma
trilha?
18. Um computador tem um barramento com tempo de
ciclo de 5 ns, durante o qual ele pode ler ou escrever
uma palavra de 32 bits da memória. O computador
tem um disco Ultra4-SCS que usa o barramento e
executa a 160 Mbytes/s. A CPU normalmente busca
e executa uma instrução de 32 bits a cada 1 ns. De
quanto é a desaceleração da CPU causada pelo disco?
19. magine que você esteja escrevendo a parte do geren-
ciamento de disco de um sistema operacional. ocê
representa o disco logicamente como uma sequência
de blocos desde 0 no interior até algum máximo
no exterior. À medida que são criados arquivos,
você tem de alocar setores livres. ocê poderia fazer
isso de fora para dentro ou de dentro para fora. A
estratégia que escolhe tem importância em um disco
moderno? Explique sua resposta.
20. Quanto tempo leva para ler um disco com 10 mil
cilindros, cada um com quatro trilhas de 2.048
setores? Primeiro, todos os setores da trilha 0
devem ser lidos iniciando no setor contendo 0, em
seguida, todos os setores da trilha 1 iniciando no
setor 0 e assim por diante. O tempo de rotação é
10 ms, e uma busca leva 1 ms entre cilindros adja-
centes e 20 ms para o pior caso. As passagens de
uma trilha para outra de um cilindro podem ser
feitas instantaneamente.
21. O RAD nível 3 é capaz de corrigir erros de um só bit
usando apenas um drive de paridade. Então, para que
serve o RAD nível 2? Afinal, ele só pode corrigir um
erro e precisa de mais drives para fazê-lo.
22. Qual é a exata capacidade de dados (em bytes) de um
CD-ROM modo 2 que contenha os 80 minutos de
mídia que agora são o padrão? Qual é a capacidade
para dados de usuário em modo 1?
23. Para gravar um CD-R, o laser deve pulsar entre
ligado e desligado a alta velocidade. Ao executar
em velocidade 10x em modo 1, qual é a duração do
pulso em nanossegundos?
24. Para poder colocar 133 minutos de vídeo em um
DD de um lado só e em uma única camada, é preci-
so uma razoável compressão. Calcule o fator de com-
pressão exigido. Suponha que haja 3,5 GB de espaço
disponível para a faixa de vídeo, que a resolução de
imagem é de 720 × 480 pixels com cor de 24 bits
(RGB a 8 bits cada) e as imagens são apresentadas a
30 quadros/s.
25. O Blu-ray transfere dados a 4,5 MB/s e tem uma
capacidade de 25 GB. Quanto tempo leva para ler
um disco inteiro?
26. Um fabricante anuncia que seu terminal de mapas de
bits de cor pode exibir 224
cores diferentes. Porém,
o hardware só tem 1 byte para cada pixel. Como é
possível fazer isso?
27. ocê faz parte de uma equipe científica internacio-
nal ultrassecreta, que acabou de receber a tarefa de
estudar um ser chamado Herb, um extraterrestre do
Planeta 10 que chegou recentemente aqui na Terra.
Herb lhe deu a seguinte informação sobre como
funcionam seus olhos: seu campo visual consiste em
cerca de 108
pixels. Cada pixel é basicamente uma
sobreposição de cinco “cores” (ou seja, infraver-
melho, vermelho, verde, azul e ultravioleta), cada
um com 32 intensidades. A resolução de tempo do
campo visual de Herb é de 10 ms. Calcule a taxa
de dados, em GB/s, dos olhos de Herb.
28. Um terminal de mapa de bits tem um monitor de
1.920 × 1.080. Ele é redesenhado 75 vezes por
segundo. Qual é a duração do pulso correspondente
a um pixel?
29. Usando certa fonte, uma impressora monocromáti-
ca a laser pode imprimir 50 linhas de 80 caracteres
por página. O caractere médio ocupa um quadrado
de 2 mm × 2 mm, dos quais cerca de 25% é toner. O
resto é branco. A camada de toner tem 25 micra de
espessura. O cartucho de toner da impressora mede
25 × 8 × 2 cm. Quantas páginas podem ser impres-
sas com um cartucho de toner?
30. A Hi-Fi Modem Company acabou de projetar um
novo modem de modulação em frequência que usa
64 frequências em vez de apenas 2. Cada segundo é
dividido em n intervalos de tempo iguais, cada um
deles contendo um dos 64 tons possíveis. Quantos
bits por segundo esse modem pode transmitir usando
transmissão síncrona?
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
114
31. Um usuário de nternet contratou um serviço ADSL
de 2 Mbps. O vizinho dele preferiu um serviço por
cabo que tem uma largura de banda compartilhada
de 12 MHz. O esquema de modulação em uso é
QAM-64. Há n residências ligadas ao cabo, cada uma
com um computador. Uma fração f desses compu-
tadores está on-line a qualquer dado instante. Sob
quais condições o usuário do cabo obterá melhor
serviço do que o usuário ADSL?
32. Uma câmera digital tem uma resolução de 3.000 ×
2.000 pixels, com 3 bytes/pixel para cor RGB. O fabri-
cante da câmera quer gravar uma imagem JPEG a um
fator de compressão de 5x na memória rápida em 2s.
Qual é a taxa de dados necessária?
33. Uma câmera digital de primeira linha tem um sen-
sor com 24 milhões de pixels, cada qual com 6
bytes/pixel. Quantas fotos podem ser armazenadas
em um cartão de memória rápida de 8 GB se o fator
de compressão for 5x? Suponha que 1 GB signifique
230
bytes.
34. Estime quantos caracteres, incluindo espaços, con-
tém um livro típico sobre ciência da computação.
Quantos bits são necessários para codificar um
livro em ASC com paridade? Quantos CD-ROMs
são necessários para armazenar uma biblioteca de
ciência da computação com 10 mil livros? Quantos
DDs de dupla face, dupla camada, são necessários
para a mesma biblioteca?
35. Escreva um procedimento hamming (ascii, encoded)
para converter os 7 bits de baixa ordem de ascii em
uma palavra de código de 11 bits armazenada em
encoded.
36. Escreva uma função distance (code, n, k) que recebe
uma matriz code de n caracteres de k bits cada como
entrada e retorna a distância do conjunto de carac-
teres como saída.
N
a parte inferior da hierarquia da Figura 1.2 encontramos o nível lógico digital, o real hardware do
computador. Neste capítulo, examinaremos muitos aspectos da lógica digital, como um fundamento
para o estudo de níveis mais altos em capítulos subsequentes. Esse assunto está no limiar entre a
ciência da computação e a engenharia elétrica, mas o material é independente, portanto, não há necessidade
de experiência prévia de hardware nem de engenharia para entendê-lo.
Os elementos básicos que fazem parte de todos os computadores digitais são surpreendentemente simples.
niciaremos nosso estudo examinando esses elementos básicos e também a álgebra especial de dois valores (álge-
bra booleana) usada para analisá-los. Em seguida, examinaremos alguns circuitos fundamentais que podem ser
construídos usando simples combinações de portas, entre eles os circuitos que efetuam a aritmética. O tópico que
vem depois desse é o modo como essas portas podem ser combinadas para armazenar informações, isto é, como
as memórias são organizadas. Logo após, chegamos à questão das CPUs e, em especial, de como é a interface
entre CPUs de um só chip, a memória e os dispositivos periféricos. Mais adiante neste capítulo serão estudados
diversos exemplos da indústria de computadores.
3.1 Portas e a
lgebra booleana
Circuitos digitais podem ser construídos com um pequeno número de elementos primitivos combinando-os de
inúmeras maneiras. Nas seções seguintes, descreveremos tais elementos, mostraremos como eles podem ser com-
binados e introduziremos uma poderosa técnica matemática que pode ser usada para analisar seu comportamento.
O n
vel lo
gico digital
3
Cap
tulo
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
116
3.1.1 Portas
Um circuito digital é aquele em que estão presentes somente dois valores lógicos. O normal é que um sinal
entre 0 e 0,5 volt represente um valor (por exemplo, 0 binário) e um sinal entre 1 e 1,5 volt represente o outro
valor (por exemplo, 1 binário). Não são permitidas tensões fora dessas duas faixas. Minúsculos dispositivos ele-
trônicos, denominados portas (gates), podem calcular várias funções desses sinais de dois valores. Essas portas
formam a base do hardware sobre a qual todos os computadores digitais são construídos.
Os detalhes do funcionamento interno das portas estão fora do escopo deste livro, pois pertencem ao nível de
dispositivo, que está abaixo do nível 0. Não obstante, agora vamos divagar um pouco e examinar rapidamente a
ideia básica, que não é difícil. No fundo, toda a lógica digital moderna se apoia no fato de que um transistor pode
funcionar como um comutador binário muito rápido. Na Figura 3.1(a), mostramos um transistor bipolar (repre-
sentado pelo círculo) inserido em um circuito simples. Esse transistor tem três conexões com o mundo exterior: o
coletor, a base e o emissor. Quando a voltagem de entrada, Vin, está abaixo de certo valor crítico, o transistor desliga
e age como uma resistência infinita. sso faz com que a saída do circuito, Vout, assuma um valor próximo a Vcc, uma
voltagem regulada externamente, em geral +1,5 volt para esse tipo de transistor. Quando Vin excede o valor crítico,
o transistor liga e age como um fio, fazendo Vout ficar conectado com a terra (por convenção, 0 volt).
O importante é notar que, quando Vin é baixa, Vout é alta, e vice-versa. Assim, esse circuito é um inversor, que
converte um 0 lógico em um 1 lógico e um 1 lógico em um 0 lógico. O resistor (linha serrilhada) é necessário para
limitar a quantidade de corrente drenada pelo transistor, de modo que ele não queime. O tempo típico exigido
para passar de um estado para outro é tipicamente de um nanossegundo ou menos.
Na Figura 3.1(b), dois transistores estão ligados em série. Se ambas, V1 e V2, forem altas, ambos os transisto-
res conduzirão e Vout cairá. Se qualquer das entradas for baixa, o transistor correspondente se desligará e a saída
será alta. Em outras palavras, Vout será baixa se, e somente se, ambas, V1 e V2, forem altas.
Na Figura 3.1(c), os dois transistores estão ligados em paralelo em vez de em série. Nessa configuração, se
qualquer das entradas for alta, o transistor correspondente ligará e conectará a saída com a terra. Se ambas as
entradas forem baixas, a saída permanecerá alta.
Esses três circuitos, ou seus equivalentes, formam as três portas mais simples e são denominadas portas
not, nand e nor, respectivamente. Portas not costumam ser denominadas inversoras; usaremos os dois termos
indiferentemente. Se agora adotarmos a convenção de que “alta” (Vcc volts) é um 1 lógico e “baixa” (terra) é um
0 lógico, podemos expressar o valor de saída como uma função dos valores de entrada. Os símbolos usados para
representar essas portas são mostrados nas figuras 3.2(a)-(c) junto com o comportamento funcional de cada
circuito. Nessas figuras, A e B são entradas e X é a saída. Cada linha especifica a saída para uma combinação
diferente das entradas.
Figura 3.1 (a) Inversor de transistor. (b) Porta nand. (c) Porta nor.
Coletor
+Vcc
Vout
Vin
(a)
Vout
+Vcc
+Vcc
Vout
V2
(b)
V1
V1
(c)
V2
Base Emissor
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 117
Se o sinal de saída da Figura 3.1(b) for alimentado em um circuito inversor, obtemos outro circuito com o
inverso exato da porta nand, a saber, um cuja saída é 1 se, e somente se, ambas as entradas forem 1. Esse circuito é
denominado uma porta and; seu símbolo e descrição funcional são dados na Figura 3.2(d). De modo semelhante,
a porta nor pode ser conectada a um inversor para produzir um circuito cuja saída é 1 se quaisquer das saídas, ou
ambas, for um 1, mas 0 se ambas as entradas forem 0. O símbolo e a descrição funcional desse circuito, denominado
uma porta or, são dados na Figura 3.2(e). Os pequenos círculos usados como parte dos símbolos para o inversor,
porta nand e porta nor, são denominados bolhas de inversão. Também são usadas em outros contextos para indicar
um sinal invertido.
As cinco portas da Figura 3.2 são os principais elementos de construção do nível lógico digital. A discussão
precedente deve ter deixado claro que as portas nand e nor requerem dois transistores cada, ao passo que as
portas and e or requerem três cada. Por essa razão, muitos computadores são baseados em portas nand e nor
em vez das portas mais conhecidas, and e or. (Na prática, todas as portas são executadas de modo um pouco
diferente, mas as nand e nor ainda são mais simples do que as and e or.) A propósito, vale a pena observar que
as portas podem perfeitamente ter mais de duas entradas. Em princípio, uma porta nand, por exemplo, pode ter,
arbitrariamente, muitas entradas, mas na prática não é comum encontrar mais de oito.
Embora a questão do modo como são construídas as portas pertença ao nível do dispositivo, gostaríamos de
mencionar as principais famílias de tecnologia de fabricação porque elas são citadas com muita frequência. As duas
tecnologias principais são bipolar e MOS (Metal Oxide Semiconductor – semicondutor de óxido metálico). Os
dois principais tipos bipolares são a L (ransistor-ransistor Logic – lógica transistor-transistor), que há mui-
tos anos é o burro de carga da eletrônica digital, e a ECL (Emitter-Coupled Logic – lógica de emissor acoplado),
que era usada quando se requeria uma operação de velocidade muito alta. Para circuitos de computador, o que
predomina agora é a tecnologia MOS.
Portas MOS são mais lentas do que as TTL e ECL, mas exigem bem menos energia elétrica e ocupam um
espaço muito menor, portanto, um grande número delas pode ser compactado e empacotado. Há muitas varieda-
des de MOS, entre as quais PMOS, NMOS e CMOS. Embora os modos de construção dos transistores MOS e dos
transistores bipolares sejam diferentes, sua capacidade de funcionar como comutadores eletrônicos é a mesma.
A maioria das CPUs e memórias modernas usa tecnologia CMOS, que funciona a +1,5 volt. E isso é tudo o que
diremos sobre o nível de dispositivo. O leitor interessado em continuar o estudo desse nível deve consultar as
leituras sugeridas na Sala irtual.
3.1.2 A
lgebra booleana
Para descrever os circuitos que podem ser construídos combinando portas, é necessário um novo tipo de
álgebra, no qual variáveis e funções podem assumir somente os valores 0 e 1. Essa álgebra é denominada álge-
bra booleana, nome que se deve a seu descobridor, o matemático inglês George Boole (1815–1864). Em termos
Figura 3.2 S
mbolos e comportamento funcional das cinco portas ba
sicas.
(b)
NAND
A
B
X
A B X
0 0 1
0 1 1
1 0 1
1 1 0
(c)
NOR
A
B
X
A B X
0 0 1
0 1 0
1 0 0
1 1 0
AND
A
B
X
(d)
A B X
0 0 0
0 1 0
1 0 0
1 1 1
OR
A
B
X
(e)
A B X
0 0 0
0 1 1
1 0 1
1 1 1
(a)
NOT
A
A X
X
0 1
1 0
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
118
estritos, estamos nos referindo a um tipo específico de álgebra booleana, uma álgebra de comutação, mas o termo
“álgebra booleana” é tão utilizado no lugar de “álgebra de comutação” que não faremos a distinção.
Assim como há funções na álgebra “ordinária” (isto é, a álgebra do colegial), também há funções na álge-
bra booleana. Uma função booleana tem uma ou mais variáveis de entrada e produz um resultado que depende
somente dos valores dessas variáveis. Uma função simples, f, pode ser definida ao se dizer que f(A) é 1 se A for 0
e f(A) é 0 se A for 1. Essa função é a função not da Figura 3.2(a).
Como uma função booleana de n variáveis só tem 2n
combinações possíveis de valores de entrada, ela
pode ser completamente descrita por uma tabela com 2n
linhas, na qual cada linha informa o valor da fun-
ção para uma combinação diferente de valores de entrada. Ela é denominada tabela verdade. As tabelas da
Figura 3.2 são todas exemplos de tabelas verdade. Se concordarmos em sempre listar as linhas de uma tabela
verdade em ordem numérica (base 2), isto é, para duas variáveis na ordem 00, 01, 10 e 11, a função pode ser
completamente descrita pelo número binário de 2n
bits obtido pela leitura vertical da coluna de resultado da
tabela verdade. Assim, nand é 1110, nor é 1000, and é 0001 e or é 0111. É óbvio que só existem 16 funções
booleanas de duas variáveis, correspondentes às 16 possíveis sequências de 4 bits resultantes. Por outro lado,
a álgebra ordinária tem um número infinito de funções de duas variáveis, nenhuma das quais pode ser des-
crita por meio de uma tabela de saídas para todas as entradas possíveis, porque cada variável pode assumir
qualquer valor de um número infinito de valores possíveis.
A Figura 3.3(a) mostra a tabela verdade para uma função booleana de três variáveis: M = f(A, B, C). Essa fun-
ção é a de lógica majoritária, isto é, ela é 0 se a maioria de suas entradas for 0, e 1 se a maioria de suas entradas for 1.
Embora qualquer função booleana possa ser completamente especificada dada sua tabela verdade, à medida que
aumenta o número de variáveis, essa notação fica cada vez mais trabalhosa. Portanto, costuma-se usar outra notação
no lugar dela.
Figura 3.3 (a) Tabela verdade para a func
a
o majorita
ria de tre
s varia
veis. (b) Circuito para (a).
A B C
0 0 0
0 0 1
0 1 0
0 1 1
M
0
0
0
1
1 0 0
1 0 1
1 1 0
1 1 1
0
1
1
1
(a) (b)
ABC
A
A
B
C
B C A
A
B C
ABC
ABC
ABC
M
1
4
8
5
6
7
B
2
C
3
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 119
Para ver como ocorre essa outra notação, observe que qualquer função booleana pode ser especificada ao se
dizer quais combinações de variáveis de entrada dão um valor de saída igual a 1. Para a função da Figura 3.3(a), há
quatro combinações de variáveis de entrada que fazem com que M seja 1. Por convenção, marcaremos a variável
de entrada com uma barra para indicar que seu valor é invertido. A ausência de uma barra significa que o valor
não é invertido. Além disso, usaremos a multiplicação implícita ou um ponto para representar a função booleana
AND e + para representar a função booleana OR. Assim, por exemplo, ABC assume o valor 1 somente quando A
= 1 e B = 0 e C = 1. Além disso, AB + BC é 1 somente quando (A = 1 e B = 0) ou (B = 1 e C = 0). As quatro linhas
da Figura 3.3(a) que produzem bits 1 na saída são: ABC, ABC, ABC e ABC. A função, M, é verdadeira (isto é, 1)
se qualquer uma dessas quatro condições for verdadeira; daí, podemos escrever
M = ABC + ABC + ABC + ABC
como um modo compacto de dar a tabela verdade. Assim, uma função de n variáveis pode ser descrita como se
desse uma “soma” de no máximo 2n
termos de “produtos” de n variáveis. Essa formulação é de especial impor-
tância, como veremos em breve, pois leva diretamente a uma execução da função que usa portas padronizadas.
É importante ter em mente a distinção entre uma função booleana abstrata e sua execução por um circuito
eletrônico. Uma função booleana consiste em variáveis, como A, B e C, e operadores booleanos, como AND, OR
e NOT. Ela é descrita por uma tabela verdade ou por uma função booleana como
F = ABC + ABC
Uma função booleana pode ser executada por um circuito eletrônico (muitas vezes de vários modos diferentes)
usando sinais que representam as variáveis de entrada e saída e portas como and, or e not. Em geral, empregaremos
a notação AND, OR e NOT quando nos referirmos aos operadores booleanos, e and, or e not quando nos referirmos
a portas, embora essa notação quase sempre seja ambígua em se tratando de indicar funções ou portas.
3.1.3 Execuc
a
o de func
o
es booleanas
Como já mencionamos, a formulação de uma função booleana como uma soma de até 2n
termos produtos
leva a uma possível implementação. Usando a Figura 3.3 como exemplo, podemos ver como essa implementação
é efetuada. Na Figura 3.3(b), as entradas, A, B e C, aparecem na extremidade esquerda, e a função de saída, M,
na extremidade direita. Como são necessários complementos (inversos) das variáveis de entrada, eles são gerados
tomando as entradas e passando-as pelos inversores rotulados 1, 2 e 3. Para evitar atravancar a figura, desenhamos
seis linhas verticais, três das quais conectadas às variáveis de entrada e três aos complementos dessas variáveis.
Tais linhas oferecem uma fonte conveniente para as entradas das portas subsequentes. Por exemplo, as portas 5,
6 e 7 usam A como uma entrada. Em um circuito real, essas portas provavelmente estariam ligadas direto a A sem
usar nenhum fio “vertical” intermediário.
O circuito contém quatro portas and, uma para cada termo da equação para M (isto é, uma para cada linha
da tabela verdade que tenha um bit 1 na coluna de resultado). Cada porta and calcula uma linha da tabela verda-
de, como indicado. Por fim, todos os termos produtos alimentam a porta lógica or para obter o resultado final.
O circuito da Figura 3.3(b) usa uma convenção que utilizaremos repetidas vezes neste livro: quando duas
linhas se cruzam, não há nenhuma ligação implícita a menos que haja um ponto negro bem visível na intersecção.
Por exemplo, a saída da porta 3 cruza todas as seis linhas verticais, mas está ligada apenas a C. É bom lembrar
que alguns autores usam outras convenções.
Pelo exemplo da Figura 3.3 deve ficar claro como colocar em prática um circuito para qualquer função
booleana:
1. Escreva a tabela verdade para a função.
2. Providencie inversores para gerar o complemento de cada entrada.
3. Desenhe uma porta and para cada termo que tenha um 1 na coluna de resultado.
4. Ligue as portas and às entradas adequadas.
5. Alimente a saída de todas as portas and a uma porta or.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
120
Embora tenhamos mostrado como qualquer função booleana pode ser executada usando portas not, and e
or, muitas vezes é conveniente realizar circuitos usando só um tipo de porta. Felizmente, converter circuitos gera-
dos pelo algoritmo precedente à forma nand pura ou nor pura é uma operação direta. Para fazer essa conversão,
basta que tenhamos um modo de implementar not, and e or usando um único tipo de porta. A linha superior da
Figura 3.4 mostra como todas essas três podem ser implementadas usando apenas portas nand; a fileira de baixo
mostra como isso pode ser feito usando apenas portas nor. (Essas operações são diretas, mas também há outras
maneiras.)
Um modo de implementar uma função booleana usando somente portas nand ou somente portas nor é
primeiro seguir o procedimento dado anteriormente para construí-la com not, and e or. Em seguida, substi-
tuir as portas de múltiplas entradas por circuitos equivalentes usando portas de duas entradas. Por exemplo,
A + B + C + D pode ser computada como (A + B) + (C + D), empregando três portas or de duas entradas. Por fim,
as portas not, and e or são substituídas pelos circuitos da Figura 3.4.
Figura 3.4 Construc
a
o de portas (a) not, (b) and e (c) or usando somente portas nand ou somente portas nor.
A + B
A + B
A
A
B
B
AB
AB
A
A
A
A
(a)
(b) (c)
A
B
A
B
Embora esse procedimento não resulte em circuitos ótimos, no sentido do número mínimo de portas, ele
mostra que sempre há uma solução viável. Ambas as portas, nand e nor, são denominadas completas porque qual-
quer função booleana pode ser calculada usando quaisquer das duas. Nenhuma outra porta tem essa propriedade,
o que é outra razão para elas serem preferidas como blocos de construção de circuitos.
3.1.4 Equivale
ncia de circuito
Projetistas de circuitos muitas vezes tentam reduzir o número de portas em seus produtos para reduzir a área
da placa de circuito interno necessária para executá-las, diminuir o consumo de potência e aumentar a velocidade.
Para reduzir a complexidade de um circuito, o projetista tem de encontrar outro circuito que calcule a mesma
função que o original, mas efetue essa operação com um número menor de portas (ou talvez com portas mais
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 121
simples, por exemplo, com duas em vez de com quatro entradas). A álgebra booleana pode ser uma ferramenta
valiosa na busca de circuitos equivalentes.
Como exemplo de como a álgebra booleana pode ser usada, considere o circuito e a tabela verdade para AB
+ AC mostrados na Figura 3.5(a). Embora ainda não as tenhamos discutido, muitas das regras da álgebra comum
também são válidas para a booleana. Em particular, a expressão AB + AC pode ser fatorada para A(B + C) usando
a lei distributiva. A Figura 3.5(b) mostra o circuito e a tabela verdade para A(B + C). Como duas funções são
equivalentes se, e somente se, elas tiverem a mesma saída para todas as entradas possíveis, é fácil ver pelas tabe-
las verdade da Figura 3.5 que A(B + C) é equivalente a AB + AC. Apesar dessa equivalência, o circuito da Figura
3.5(b) é claramente melhor do que o da Figura 3.5(a), pois contém menos portas.
Figura 3.5 Duas func
o
es equivalentes. (a) AB + AC. (b) A(B + C).
C
B
A A(B + C)
B + C
A
B
C
AB + AC
AB
AC
(a) (b)
A B C AB AC AB + AC
0 0 0 0 0 0
0 0 1 0 0 0
0 1 0 0 0 0
0 1 1 0 0 0
1 0 0 0 0 0
1 0 1 0 1 1
1 1 0 1 0 1
1 1 1 1 1 1
A B C A B + C A(B + C)
0 0 0 0 0 0
0 0 1 0 1 0
0 1 0 0 1 0
0 1 1 0 1 0
1 0 0 1 0 0
1 0 1 1 1 1
1 1 0 1 1 1
1 1 1 1 1 1
Em geral, um projetista de circuitos começa com uma função booleana e depois aplica a ela as leis da álgebra
booleana na tentativa de achar uma função mais simples, porém equivalente. Um circuito pode ser construído
com base na função final.
Para usar essa abordagem, precisamos de algumas identidades da álgebra booleana. A Figura 3.6 mostra
algumas das mais importantes. É interessante notar que cada lei tem duas formas que são duais uma da outra.
Permutando AND e OR e também 0 e 1, quaisquer das formas pode ser produzida com base na outra. Todas as
leis podem ser provadas com facilidade construindo suas tabelas verdade. Com exceção da lei de De Morgan, a lei
da absorção, e da forma AND da lei distributiva, os resultados são razoavelmente intuitivos. A lei de De Morgan
pode ser estendida para mais de duas variáveis, por exemplo, ABC = A + B + C.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
122
Figura 3.6 Algumas identidades da a
lgebra booleana.
Nome Forma AND Forma OR
Lei da identidade 1A = A 0 + A = A
Lei do elemento nulo 0A = 0 1 + A = 1
Lei idempotente AA = A A + A = A
Lei do inverso AA = 0 A + A = 1
Lei comutativa AB = BA A + B = B + A
Lei associativa (AB)C = A(BC) (A + B) + C = A + (B + C)
Lei distributiva A + BC = (A + B)(A + C) A(B + C) = AB + AC
Lei da absorção A(A + B) = A A + AB = A
Lei de De Morgan AB = A + B A + B = AB
A lei de De Morgan sugere uma notação alternativa. Na Figura 3.7(a), a forma AND é mostrada com negação
indicada por bolhas de inversão tanto para entrada quanto para saída. Assim, uma porta or com entradas inver-
tidas é equivalente a uma porta nand. Pela Figura 3.7(b), a forma dual da lei de De Morgan, deve ficar claro que
uma porta nor pode ser desenhada como uma porta and com entradas invertidas. Negando ambas as formas da
lei de De Morgan, chegamos às figuras 3.7(c) e (d), que mostram representações equivalentes das portas and e or.
Existem símbolos análogos para as formas de múltiplas variáveis da lei de De Morgan (por exemplo, uma porta
nand com n entradas se torna uma porta or com entradas invertidas).
Figura 3.7 S
mbolos alternativos para algumas portas: (a) nand. (b) nor. (c) and. (d) or.
(a)
AB = A + B
(c)
A + B
AB =
(b)
A + B = AB
AB
=
(d)
A + B
Usando as identidades da Figura 3.7 e as análogas para portas de múltiplas entradas é fácil converter a repre-
sentação de soma de produtos de uma tabela verdade para a forma nand pura ou nor pura. Como exemplo, con-
sidere a função ECLUSE OR da Figura 3.8(a). O circuito padrão da soma de produtos é mostrado na Figura
3.8(b). Para converter para a forma nand, as linhas que conectam a saída das portas and à entrada da porta or
devem ser redesenhadas com duas bolhas de inversão, conforme mostra a Figura 3.8(c). Por fim, usando a Figura
3.7(a), chegamos à Figura 3.8(d). As variáveis A e B podem ser geradas de A e B usando portas nand ou nor com
suas entradas interligadas. Note que as bolhas de inversão podem ser deslocadas à vontade ao longo da linha, por
exemplo, desde as saídas das portas de entrada na Figura 3.8(d) até as entradas da porta de saída.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 123
Figura 3.8 (a) Tabela verdade para a func
a
o XOR. (b)–(d) Tre
s circuitos para calcular essa tabela.
(a) (b)
A B XOR
0 0 0
0 1 1
1 0 1
1 1 0
A
B
B
A
(d)
(c)
A
B
B
A
A
B
B
A
Como observação final em relação à equivalência de circuitos, demonstraremos agora o surpreendente resul-
tado, isto é, a mesma porta física pode calcular funções diferentes dependendo das convenções usadas. Na Figura
3.9(a), mostramos a saída de certa porta, F, para diferentes combinações de entrada. Tanto entradas quanto saídas
são representadas por volts. Se adotarmos a convenção de que 0 volt é 0 lógico e 1,5 volt é 1 lógico, denomina-
da lógica positiva, obtemos a tabela verdade da Figura 3.9(b), a função AND. Contudo, se adotarmos a lógica
negativa, na qual 0 volt é 1 lógico e 1,5 volt é 0 lógico, obtemos a tabela verdade da Figura 3.9(c), a função or.
Figura 3.9 (a) Caracter
sticas ele
tricas de um dispositivo. (b) Lo
gica positiva. (c) Lo
gica negativa.
(a)
A B
0V 0V
0V 5V
5V 0V
5V 5V
F
0V
0V
0V
5V
(b)
A B
0 0
0 1
1 0
1 1
F
0
0
0
1
(c)
A B
1 1
1 0
0 1
0 0
F
1
1
1
0
Assim, a convenção escolhida para mapear voltagens para valores lógicos é crítica. A menos que especifique-
mos outra coisa, daqui em diante usaremos lógica positiva, portanto, os termos 1 lógico, verdade e tensão alta são
sinônimos, assim como 0 lógico, falso e tensão baixa.
3.2 Circuitos lo
gicos digitais ba
sicos
Nas seções anteriores vimos como executar tabelas verdade e outros circuitos simples usando portas indivi-
duais. Na prática, poucos circuitos são construídos porta por porta, embora tenha havido uma época em que isso
era comum. Hoje, os blocos de construção mais comuns são módulos que contêm várias portas. Nas próximas
seções, examinaremos esses blocos de construção mais de perto e veremos como eles podem ser construídos com
base em portas individuais.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
124
3.2.1 Circuitos integrados
Portas não são fabricadas nem vendidas individualmente, mas em unidades denominadas circuitos inte-
grados, muitas vezes denominados ICs ou chips. Um C é um pedaço quadrado de silício de tamanho variado,
dependendo de quantas portas são necessárias para executar os componentes do chip. Substratos pequenos medi-
rão cerca de 2 × 2 mm, enquanto os maiores podem ter até 18 × 18 mm. Cs costumam ser montados em pacotes
retangulares de plástico ou cerâmica, que podem ser muito maiores que os substratos que eles abrigam, se forem
necessários muitos pinos para conectar o chip ao mundo exterior. Cada pino se conecta com a entrada ou saída
de alguma porta no chip ou à fonte de energia, ou ao terra.
A Figura 3.10 mostra uma série de pacotes de C comuns, usados para os chips de hoje. Chips menores,
como os usados para microcontroladores domésticos ou chips de RAM, usarão pacotes duplos em linha
(IPs  ual Inline Packages). Um DP é um pacote com duas fileiras de pinos que se encaixam em um
soquete correspondente na placa-mãe. Os pacotes mais comuns têm 14, 16, 18, 20, 22, 24, 28, 40, 64 ou 68
pinos. Para chips grandes costumam ser usados pacotes quadrados com pinos nos quatro lados ou na parte
de baixo. Dois pacotes comuns para chips maiores são Pin Grid rrays, ou PGs, e Land Grid rrays, ou
LGs. PGAs possuem pinos na parte inferior do pacote, que se encaixam em um soquete correspondente
na placa-mãe. Soquetes PGA normalmente utilizam um mecanismo com força de inserção nula, onde uma
alavanca aplica pressão lateral sobre todos os pinos do PGA, mantendo-o firmemente no soquete PGA. LGAs,
por outro lado, possuem pequenas plataformas planas na parte inferior do chip, e um soquete LGA terá uma
capa que se encaixa sobre o LGA e aplica uma força para baixo no chip, garantindo que todas as plataformas
do LGA façam contato com as plataformas do soquete LGA.
Figura 3.10 Tipos comuns de pacotes de circuito integrado, incluindo um pacote dual-in-line, ou DIP (a), PGA (b) e LGA (c).
(c)
(b)
(a)
Como muitos pacotes de C têm forma simétrica, descobrir a orientação correta é um problema constante
com a instalação de C. DPs normalmente têm um entalhe em uma ponta, que combina com uma marca corres-
ponde no soquete DP. PGAs, em geral, possuem um pino faltando, de modo que, se você tentar inserir o PGA
no soquete incorretamente, o PGA não se encaixará. Como os LGAs não possuem pinos, a instalação correta é
imposta colocando-se um entalhe em um ou dois lados do LGA, que corresponde a um entalhe no soquete LGA.
O LGA não entrará no soquete a menos que os dois entalhes combinem.
Para todos os efeitos, todas as portas são ideais no sentido de que a saída aparece logo que a entrada é apli-
cada. Na realidade, os chips têm um atraso de porta finito que inclui o tempo de propagação de sinal pelo chip e
o tempo de comutação. Atrasos típicos são de centésimos de picossegundos a alguns nanossegundos.
A tecnologia moderna vigente permite colocar mais de 1 bilhão de transistores em um chip. Como qualquer
circuito pode ser construído com base em portas nand, você bem poderia imaginar que um fabricante poderia
produzir um chip muito geral que contivesse 500 milhões de portas nand. nfelizmente, um chip como esse neces-
sitaria de 1.500.000.002 pinos. Como o espaço-padrão entre pinos é 1 milímetro, um chip LGA teria 38 metros
de comprimento para acomodar todos esses pinos, o que talvez tivesse um efeito negativo sobre as vendas. É
claro que a única maneira de tirar proveito da tecnologia é projetar circuitos com uma alta relação porta/pino.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 125
Nas seções seguintes vamos examinar circuitos simples que combinam uma quantidade de portas internamente
para fornecer uma função útil que requer apenas um número limitado de conexões externas (pinos).
3.2.2 Circuitos combinato
rios
Muitas aplicações de lógica digital requerem um circuito com múltiplas entradas e múltiplas saídas, no qual
as saídas são determinadas exclusivamente pelas entradas em questão. Esses circuitos são denominados circuitos
combinatórios. Nem todos os circuitos têm essa propriedade. Por exemplo, um circuito que contenha elementos de
memória pode perfeitamente gerar saídas que dependem de valores armazenados, bem como de variáveis de entrada.
Um circuito que esteja executando uma tabela verdade como a da Figura 3.3(a) é um exemplo típico de um circuito
combinatório. Nesta seção, examinaremos alguns circuitos combinatórios de uso frequente.
Multiplexadores
No nível lógico, um multiplexador é um circuito com 2n
entradas de dados, uma saída de dados e n entradas
de controle que selecionam uma das entradas de dados. Essa entrada selecionada é dirigida (isto é, roteada) até a
saída. A Figura 3.11 é um diagrama esquemático de um multiplexador de oito entradas. As três linhas de controle,
A, B e C, codificam um número de 3 bits que especifica qual das oito linhas de entrada é direcionada até a porta
or e dali até a saída. Não importa qual valor esteja nas linhas de controle, sete das portas and sempre produzirão
saída 0; a outra pode produzir ou um 0 ou um 1, dependendo do valor da linha de entrada selecionada. Cada
porta and é habilitada por uma combinação diferente das entradas de controle. O circuito do multiplexador é
mostrado na Figura 3.11.
Figura 3.11 Circuito multiplexador de oito entradas.
F
D0
D1
D2
D3
D4
D5
D6
D7
A B C
A A B C
B C
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
126
Usando o multiplexador, podemos executar a função majoritária da Figura 3.3(a), como mostrado na Figura
3.12(b). Para cada combinação de A, B e C, uma das linhas de dados é selecionada. Cada entrada é ligada ou a Vcc
(1 lógico) ou ao terra (0 lógico). O algoritmo para ligar as entradas é simples: a entrada Di é a que tem o mesmo
valor da linha i da tabela verdade. Na Figura 3.3(a), as linhas 0, 1, 2 e 4 são 0, portanto, as entradas correspon-
dentes estão aterradas; as linhas restantes são 1, portanto, estão ligadas a 1 lógico. Dessa maneira, qualquer tabela
verdade de três variáveis pode ser executada usando o chip da Figura 3.12(a).
Figura 3.12 (a) Multiplexador com oito entradas. (b) O mesmo multiplexador ligado para calcular a func
a
o majorita
ria.
(a)
A B C
F
D0
D1
D2
D3
D4
D5
D6
D7
(b)
VCC
A B C
F
D0
D1
D2
D3
D4
D5
D6
D7
Acabamos de ver como um chip multiplexador pode ser usado para selecionar uma das diversas entradas e
como ele pode implementar uma tabela verdade. Outra de suas muitas aplicações é como um conversor de dados
paralelo para serial. Colocando 8 bits de dados nas linhas de entrada e então escalonando as linhas em sequência
de 000 a 111 (binário), os 8 bits são colocados em série na linha de saída. Uma utilização típica da conversão
paralela para serial é um teclado, onde cada acionamento de uma tecla define implicitamente um número de 7 ou
8 bits que deve ser enviado por um enlace serial, como USB.
O inverso de um multiplexador é um demultiplexador, que dirige sua única entrada até uma das 2n
saídas,
dependendo dos valores das n linhas de controle. Se o valor binário das linhas de controle for k, é selecionada a saída k.
Decodificadores
Como um segundo exemplo, agora vamos examinar um circuito que toma um número de n bits como entra-
da e o usa para selecionar (isto é, definir em 1) exatamente uma das 2n
linhas de saída. Tal circuito, ilustrado para
n = 3 na Figura 3.13, é denominado decodificador.
Para ver como um decodificador pode ser útil, imagine uma pequena memória que consiste em oito chips,
cada um contendo 256 MB. O chip 0 tem endereços de 0 a 256 MB, o chip 1 tem endereços de 256 MB a 512
MB e assim por diante. Quando um endereço é apresentado à memória, os 3 bits de ordem alta são usados
para selecionar um dos oito chips. Usando o circuito da Figura 3.13, esses 3 bits são as três entradas, A, B e C.
Dependendo das entradas, exatamente uma das oito linhas de saída, D0, ..., D7, é 1; o resto é 0. Cada linha de
saída habilita um dos oito chips de memória. Como só uma linha de saída é colocada em 1, apenas um chip
é habilitado.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 127
A operação do circuito da Figura 3.13 é direta. Cada porta and tem três entradas, das quais a primeira é A ou
A, a segunda é B ou B e a terceira é C ou C. Cada porta é habilitada por uma combinação diferente de entradas:
D0 por A B C, D1 por A B C, e assim por diante.
Figura 3.13 Circuito decodificador 3 para 8.
D0
D1
D2
D3
D4
D5
D6
D7
A
C
B
A
B
C
B
C
A
Comparadores
Outro circuito útil é o comparador, que compara duas palavras de entrada. O comparador simples da
Figura 3.14 toma duas entradas, A e B, cada uma de 4 bits de comprimento, e produz um 1 se elas forem
iguais e um 0 se elas não o forem. O circuito é baseado na porta OR (ECLUSE OR), que produz um 0
se suas entradas forem iguais e um 1 se elas forem diferentes. Se as duas palavras de entrada forem iguais,
todas as quatro portas xor devem produzir 0. Então, pode-se efetuar uma operação OR nesses quatro sinais;
se o resultado for 0, as palavras de entrada são iguais; caso contrário, não. Em nosso exemplo, usamos uma
porta nor como o estágio final para reverter o sentido do teste: 1 significa igual, 0 significa diferente.
3.2.3 Circuitos aritme
ticos
Chegou a hora de passar dos circuitos de uso geral discutidos anteriormente para circuitos combinatórios
usados para operações aritméticas. Começaremos com um simples deslocador de 8 bits e em seguida veremos
como são construídos os somadores e, por fim, estudaremos as unidades de lógica e aritmética, que desempenham
um papel fundamental em qualquer computador.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
128
Figura 3.14 Comparador simples de 4 bits.
A = B
A0
B0
A1
B1
A2
B2
A3
B3
porta EXCLUSIVE OR
Deslocadores
Nosso primeiro circuito aritmético é um deslocador de oito entradas e oito saídas (veja a Figura 3.15). Oito
bits de entrada são apresentados nas linhas D0, ..., D7. A saída, que é apenas a entrada deslocada de 1 bit, está
nas linhas S0, ..., S7. A linha de controle, C, determina a direção do deslocamento, 0 para a esquerda e 1 para a
direita. Quando o deslocamento for para a esquerda, um 0 é inserido no bit 7. De modo semelhante, quando o
deslocamento for para a direita, um 1 é inserido no bit 0.
Figura 3.15 Deslocador esquerda/direita de 1 bit.
C
D0 D1 D2 D3 D4 D5 D6 D7
S0 S1 S2 S3 S4 S5 S6 S7
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 129
Para ver como o circuito funciona, observe os pares de portas and para todos os bits, exceto as portas na
extremidade. Quando C = 1, o membro da direita de cada par é ligado, passando o bit de entrada correspondente
para a saída. Como a porta and da direita está ligada à entrada da porta or à sua direita, é executado um deslo-
camento para a direita. Quando C = 0, o membro da esquerda do par da porta and é ligado, o que provoca um
deslocamento para a esquerda.
Somadores
Um computador que não possa somar números inteiros é quase inimaginável. Por consequência, um circuito
de hardware para efetuar adição é uma parte essencial de toda CPU. A tabela verdade para adição de inteiros de
1 bit é mostrada na Figura 3.16(a). Há duas saídas presentes: a soma das entradas, A e B, e o transporte (vai-um)
para a posição seguinte (à esquerda). Um circuito para calcular o bit de soma e o de transporte é ilustrado na
Figura 3.16(b). Esse circuito simples é conhecido como um meio-somador.
Figura 3.16 (a) Tabela verdade para adic
a
o de 1 bit. (b) Circuito para um meio-somador.
A B Soma Transporte
A
B
0 0 0 0
0 1 1 0
1 0 1 0
1 1 0 1
Porta EXCLUSIVE OR
Soma
Transporte
Embora um meio-somador seja adequado para somar os bits de ordem baixa de duas palavras de entrada de
múltiplos bits, ele não servirá para uma posição de bit no meio da palavra porque não trata o transporte de bit
da posição à direita (vem-um). Em seu lugar, precisamos do somador completo da Figura 3.17. Pela inspeção
do circuito, deve ficar claro que um somador completo é composto de dois meios-somadores. A linha de saída
Soma é 1 se um número ímpar A, B e o vem-um (carry in) forem 1. O vai-um (carry out) é 1 se A e B forem ambos
1 (entrada esquerda para a porta or) ou se exatamente um deles for 1 e o bit de vem-um (carry in) também é 1.
Juntos, os dois meios-somadores geram a soma e também os bits de transporte.
Para construir um somador para palavras de 16 bits, por exemplo, basta repetir o circuito da Figura 3.17(b)
16 vezes. O vai-um de um bit é usado como vem-um para seu vizinho da esquerda. O vem-um do bit da extrema
direita está ligado a 0. Esse tipo de somador é denominado somador de transporte encadeado porque, na pior das
hipóteses, somando 1 a 111...111 (binário), a adição não pode ser concluída até que o vai-um tenha percorrido
todo o caminho do bit da extrema direita até o da extrema esquerda. Também existem somadores que não têm
esse atraso e, portanto, são mais rápidos – em geral, são os preferidos.
Como exemplo simples de um somador mais rápido, considere subdividir um somador de 32 bits em uma
metade inferior e uma metade superior de 16 bits cada. Quando a adição começa, o somador superior ainda não
pode trabalhar porque não sabe qual é o vem-um por 16 tempos de adição.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
130
Figura 3.17 (a) Tabela verdade para somador completo. (b) Circuito para um somador completo.
A
B
0 0 0 0
0 1 1 0
1 0 1 0
1
0
0
0
0 1 0 1
0 0 1 0
0 1 0 1
1 0 0 1
1
1
1
1
1 1 1 1
(a) (b)
Vai-um
A B Vem- Soma Vai-
-um -um
Vem-um
Soma
Contudo, considere essa modificação no circuito. Em vez de uma única metade superior, vamos dar ao
somador duas metades superiores em paralelo duplicando o hardware da metade superior. Desse modo, agora
o circuito consiste em três somadores de 16 bits: uma metade inferior e duas metades superiores, U0 e U1 que
funcionam em paralelo. Um 0 é alimentado em U0 como vai-um; um 1 é alimentado em U1 como vai-um. Agora,
ambos podem iniciar ao mesmo tempo do que a metade inferior, mas somente um estará correto. Após 16 tempos
de adição de bits, já se saberá qual é o vem-um que deve ir para a metade superior, portanto, agora já se pode
selecionar a metade superior correta com base em duas respostas disponíveis. Esse estratagema reduz o tempo de
adição por um fator de dois. Um somador como esse é denominado somador de seleção de transporte. Então, o
estratagema pode ser repetido para construir cada somador de 16 bits com base em somadores de 8 bits repetidos
e assim por diante.
Unidades lo
gica e aritme
tica
Grande parte dos computadores contém um único circuito para efetuar and, or e soma de duas palavras
de máquina. No caso típico, tal circuito para palavras de n bits é composto de n circuitos idênticos para as
posições individuais de bits. A Figura 3.18 é um exemplo simples de um circuito desses, denominado uni-
dade lógica e aritmética (UL) (rithmetic Logic Unit  LU). Ela pode calcular qualquer uma das quatro
funções – a saber, A and B, A or B, B ou A + B, dependendo de as linhas de entrada de seleção de função F0
e F1 conterem 00, 01, 10 ou 11 (binário). Note que, aqui, A + B significa a soma aritmética de A e B, e não a
operação booleana or.
O canto inferior esquerdo de nossa ULA contém um decodificador de 2 bits para gerar sinais de enable
(habilitação) para as quatro operações, com base nos sinais de controle F0 e F1. Dependendo dos valores de F0 e
F1, exatamente uma das quatro linhas de habilitação é selecionada. Ativar essa linha permite que a saída para a
função selecionada passe por ela até a porta OR final, para saída.
O canto superior esquerdo contém a lógica para calcular A and B, A or, B e B, mas no máximo um desses
resultados é passado para a porta or final, dependendo das linhas de habilitação que saem do decodificador. Como
exatamente uma das saídas do decodificador será 1, exatamente uma das quatro portas and que comandam a porta
or será habilitada; as outras três resultarão em 0, independente de A e B.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 131
Figura 3.18 ULA de 1 bit.
Vai-um
A
INVA
ENA
B
AB
B
F0
F1
A + B
ENB
Unidade lógica Vem-um
Saída
Soma
Linhas de
enable
Somador
completo
Decodificador
Além de poder usar A e B como entradas para operações lógicas ou aritméticas, também é possível for-
çar quaisquer delas para 0 negando ena ou enb, respectivamente. Também é possível obter A ativando inva.
eremos utilizações para inva, ena e enb no Capítulo 4. Em condições normais, ena e enb são ambas 1 para
habilitar ambas as entradas e inva é 0. Nesse caso, A e B são apenas alimentados na unidade lógica, sem
modificação.
O canto direito inferior da ULA contém um somador completo para calcular a soma de A e B, incluindo
manipulação de transportes (vai-um e vem-um), porque é provável que, em seu devido tempo, vários desses
circuitos serão ligados juntos para efetuar operações de palavra inteira. Na verdade, existem circuitos como o da
Figura 3.18 que são conhecidos como segmentos de bits (bit slices). Eles permitem que o projetista do computa-
dor monte uma ULA da largura que quiser. A Figura 3.19 mostra uma ULA de 8 bits montada com 8 segmentos
(slices) de ULA de 1 bit. O sinal inc só é útil para operações de adição. Quando presente, aumenta o resultado
(isto é, soma 1 a ele), possibilitando o cálculo de somas como A + 1 e A + B + 1.
Anos atrás, um segmento de bit era na verdade um chip que você podia comprar. Hoje, é mais como uma
biblioteca que um projetista de chip pode replicar quantas vezes quiser em um programa projeto-auxiliado-por-
-computador produzindo um arquivo de saída que direciona as máquinas de produção de chips. Mas a ideia, na
essência, é a mesma.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
132
Figura 3.19 Oito segmentos (slices) de ULA de 1 bit conectados para formar uma ULA de 8 bits. Os sinais de habilitac
a
o e inversa
o na
o
sa
o mostrados por simplicidade.
F0
F1
A7 B7
O7
A6 B6
O6
A5 B5
O5
A4 B4
O4
A3 B3
O3
A2 B2
O2
A1 B1
O1
INC
A0 B0
O0
ULA de
1 bit
ULA de
1 bit
ULA de
1 bit
ULA de
1 bit
ULA de
1 bit
ULA de
1 bit
ULA de
1 bit
ULA de
1 bit
Vem-um Vai-um
3.2.4 Clocks
Em muitos circuitos digitais, a ordem em que os eventos ocorrem é crítica. Às vezes um evento deve preceder
outro, às vezes dois eventos devem ocorrer simultaneamente. Para permitir que os projetistas consigam as rela-
ções de temporização requeridas, muitos circuitos digitais usam clocks para prover sincronização. Nesse contexto,
um clock é um circuito que emite uma série de pulsos com uma largura de pulso precisa e intervalos precisos
entre pulsos consecutivos. O intervalo de tempo entre as arestas correspondentes de dois pulsos consecutivos é
denominado tempo de ciclo de clock. Em geral, as frequências de pulso estão entre 100 MHz e 4 GHz, corres-
pondendo a ciclos de clock de 10 nanossegundos a 250 picossegundos. Para conseguir alta precisão, a frequência
de clock normalmente é controlada por um oscilador de cristal.
Muitos eventos podem ocorrer dentro de um computador durante um único ciclo de clock. Se eles devem
ocorrer em uma ordem específica, o ciclo de clock deve ser dividido em subciclos. Uma maneira comum de prover
resolução superior à do clock básico é aproveitar a linha de clock primária e inserir um circuito com um atraso
conhecido, gerando assim um sinal de clock secundário deslocado em certa fase em relação ao primeiro, confor-
me mostra a Figura 3.20(a). O diagrama de temporização da Figura 3.20(b) dá quatro referências de tempo para
eventos discretos:
1. Fase ascendente de C1.
2. Fase descendente de C1.
3. Fase ascendente de C2.
4. Fase descendente de C2.
inculando diferentes eventos às várias fases, pode-se conseguir a sequência requerida. Se forem necessárias
mais do que quatro referências de tempo dentro de um ciclo de clock, podem-se puxar mais linhas da linha pri-
mária, com diferentes atrasos, se for preciso.
Em alguns circuitos, estamos interessados em intervalos de tempo em vez de instantes discretos de tempo.
Por exemplo, pode-se permitir que algum evento aconteça toda vez que C1 estiver alto, em vez de exatamente
na fase ascendente. Outro evento só poderá acontecer quando C2 estiver alto. Se forem necessários mais de
dois intervalos diferentes, podem ser instaladas mais linhas de clock ou pode-se fazer com que os estados
altos dos dois clocks se sobreponham parcialmente no tempo. No último caso, podem-se distinguir quatro
intervalos distintos: C1 and C2, C1 and C2, C1 and C2 e C1 and C2.
A propósito, clocks são simétricos, com o tempo gasto no estado alto igual ao tempo gasto no estado
baixo, como mostra a Figura 3.20(b). Para gerar um trem de pulsos assimétrico, o clock básico é deslocado
usando um circuito de atraso e efetuando uma operação AND com o sinal original, como mostra a Figura
3.20(c) como C.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 133
Figura 3.20 (a) Um clock. (b) Diagrama de temporizac
a
o para o clock. (c) Gerac
a
o de um clock assime
trico.
C1
C2
(a) (b)
A
B
C
(c)
Atraso
3.3 Memo
ria
Um componente essencial de todo computador é sua memória. Sem ela não poderiam existir os computa-
dores que conhecemos. A memória é usada para armazenar instruções a serem executadas e dados. Nas seções
seguintes examinaremos os componentes básicos de um sistema de memória começando no nível da porta para
ver como eles funcionam e como são combinados para produzir memórias de grande porte.
3.3.1 Memo
rias de 1 bit
Para criar uma memória de 1 bit (“latch”), precisamos de um circuito que “se lembre”, de algum modo, de
valores de entrada anteriores. Tal circuito pode ser construído com base em duas portas nor, como ilustrado na
Figura 3.21(a). Circuitos análogos podem ser construídos com portas nand, porém, não vamos mais mencioná-los
porque são conceitualmente idênticos às versões nor.
O circuito da Figura 3.21(a) é denominado latch SR. Ele tem duas entradas, S, para ativar (setting) o latch,
e R, para restaurá-lo (resetting), isto é, liberá-lo. O circuito também tem duas saídas, Q e Q, que são complemen-
tares, como veremos em breve. Ao contrário de um circuito combinacional, as saídas do latch não são exclusiva-
mente determinadas pelas entradas atuais.
Figura 3.21 (a) Latch nor no estado 0. (b) Latch nor no estado 1. (c) Tabela verdade para nor.
A B NOR
0 0 1
0 1 0
1 0 0
1 1 0
R
Q
S
0
0
1
0
0
1
Q
R
Q
S
0
1
0
0
1
0
Q
(a) (b) (c)
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
134
Para ver como isso ocorre, vamos supor que ambos, S e R, sejam 0, o que é verdade na maior parte do tempo.
Apenas para polemizar, vamos supor que Q = 0. Como Q é realimentado para a porta nor superior, ambas as suas
entradas são 0, portanto, sua saída, Q, é 1. O 1 é realimentado para a porta inferior que, então, tem entradas 1 e
0, resultando em Q = 0. Esse estado é no mínimo coerente e está retratado na Figura 3.21(a).
Agora, vamos imaginar que Q não seja 0, mas 1, com R e S ainda 0. A porta superior tem entradas de 0 e 1,
e uma saída, Q, de 0, que é realimentada para a porta inferior. Esse estado, mostrado na Figura 3.21(b), também
é coerente. Um estado com as duas saídas iguais a 0 é incoerente, porque força ambas as portas a ter dois 0 como
entrada, o que, se fosse verdade, produziria 1, não 0, como saída. De modo semelhante, é impossível ter ambas
as saídas iguais a 1, porque isso forçaria as entradas a 0 e 1, o que resultaria 0, não 1. Nossa conclusão é simples:
para R = S = 0, o latch tem dois estados estáveis, que denominaremos 0 e 1, dependendo de Q.
Agora, vamos examinar o efeito das entradas sobre o estado do latch. Suponha que S se torna 1 enquanto Q = 0.
Então, as entradas para a porta superior são 1 e 0, forçando a saída Q a 0. Essa mudança faz ambas as entradas
para a porta inferior serem 0, forçando a saída para 1. Portanto, ativar S (isto é, fazer com que seja 1) muda o
estado de 0 para 1. Definir R em 1 quando o latch está no estado 0 não tem efeito algum porque a saída da porta
NOR inferior é 0 para entradas de 10 e entradas de 11.
Usando raciocínio semelhante, é fácil ver que definir S em 1 quando em estado Q = 1 não tem efeito algum,
mas definir R leva o latch ao estado Q = 0. Resumindo, quando S é definido em 1 momentaneamente, o latch acaba
no estado Q = 1, pouco importando seu estado anterior. Da mesma maneira, definir R em 1 momentaneamente
força o latch ao estado Q = 0. O circuito “se lembra” se foi S ou R definido por último. Usando essa propriedade
podemos construir memórias de computadores.
Latches SR com clock
Muitas vezes é conveniente impedir que o latch mude de estado, a não ser em certos momentos especificados.
Para atingir esse objetivo, fazemos uma ligeira modificação no circuito básico, conforme mostra a Figura 3.22,
para obter um latch SR com clock.
Figura 3.22 Latch SR com clock.
Clock
S
Q
Q
R
Esse circuito tem uma entrada adicional, o clock, que em geral é 0. Com o clock em 0, ambas as portas and
geram saída 0, independentemente de ser S e R, e o latch não muda de estado. Quando o clock é 1, o efeito das
portas and desaparece e o latch se torna sensível a S e R. Apesar de seu nome, o sinal do clock não precisa ser
gerado por um clock. Os termos enable e strobe também são muito usados para indicar que a entrada do clock é
1; isto é, o circuito é sensível ao estado de S e R.
Até aqui evitamos falar no que acontece quando ambos, S e R, são 1, por uma boa razão: o circuito se torna
não determinístico quando ambos, R e S, finalmente retornam a 0. O único estado coerente para S = R = 1 é Q =
Q = 0; porém, assim que ambas as entradas voltam para 0, o latch deve saltar para um de seus dois estados está-
veis. Se quaisquer das entradas cair para 0 antes da outra, a que permanecer em 1 por mais tempo vence, porque,
quando apenas uma entrada for 1, ela força o estado. Se ambas as entradas voltarem a 0 ao mesmo tempo (o que
é muito improvável), o latch salta aleatoriamente para um de seus estados estáveis.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 135
Latches D com clock
Uma boa maneira de resolver a instabilidade do latch SR (causada quando S = R = 1) é evitar que ela ocorra.
A Figura 3.23 apresenta um circuito de latch com somente uma entrada, D. Como a entrada para a porta and
inferior é sempre o complemento da entrada para a superior, nunca ocorre o problema de ambas as entradas serem 1.
Quando D = 1 e o clock for 1, o latch é levado ao estado Q = 1. Quando D = 0 e o clock for 1, ele é levado ao
estado Q = 0. Em outras palavras, quando o clock for 1, o valor corrente de D é lido e armazenado no latch. Esse
circuito, denominado latch  com clock, é uma verdadeira memória de 1 bit. O valor armazenado sempre estará
disponível em Q. Para carregar o valor atual de D na memória, um pulso positivo é colocado na linha do clock.
Figura 3.23 Latch D com clock.
D
Q
Q
Esse circuito requer 11 transistores. Circuitos mais sofisticados (porém, menos óbvios) podem armazenar
1 bit com até seis transistores. Esses projetos costumam ser usados na prática. Esse circuito pode permanecer
estável indefinidamente, desde que seja aplicada energia (não mostrado). Mais adiante, veremos os circuitos de
memória que se esquecem rápido do estado em que estão, a menos que, de alguma forma, sejam “relembrados”
constantemente.
3.3.2 Flip-flops
Em muitos circuitos é necessário ler o valor em determinada linha em dado instante, e armazená-lo. Nessa
variante, denominada flip-flop, a transição de estado não ocorre quando o clock é 1, mas durante a transição de
0 para 1 (borda ascendente), ou de 1 para 0 (borda descendente). Assim, o comprimento do pulso do clock não
é importante, contanto que as transições ocorram rapidamente.
Para dar ênfase, vamos repetir qual é a diferença entre um flip-flop e um latch. Um flip-flop é disparado pela
borda, enquanto um latch é disparado pelo nível. Contudo, fique atento, porque esses termos são muito confun-
didos na literatura. Muitos autores usam “flip-flop” quando estão se referindo a um latch, e vice-versa.
Há várias formas de projetar um flip-flop. Por exemplo, se houvesse alguma maneira de gerar um pulso muito
curto na borda ascendente do sinal de clock, esse pulso poderia ser alimentado para um latch D. Na verdade, essa
maneira existe, e o circuito para ela é mostrado na Figura 3.24(a).
À primeira vista, poderia parecer que a saída da porta and seria sempre zero, uma vez que a operação and de
qualquer sinal com seu inverso é zero, mas a situação é um pouco diferente disso. O inversor tem um atraso de propa-
gação pequeno, mas não zero, e é esse atraso que faz o circuito funcionar. Suponha que meçamos a tensão nos quatro
pontos de medição a, b, c e d. O sinal de entrada, medido em a, é um pulso de clock longo, como mostrado na parte
inferior da Figura 3.24(b). O sinal em b é mostrado acima dele. Observe que ele está invertido e também ligeiramente
atrasado, quase sempre de alguns nanossegundos, dependendo do tipo de inversor utilizado.
O sinal em c também está atrasado, mas apenas pelo tempo correspondente à propagação (à velocidade da
luz) do sinal. Se a distância física entre a e c for, por exemplo, 20 micra, então o atraso de propagação é 0,0001
ns, que decerto é desprezível em comparação com o tempo que o sinal leva para se propagar pelo inversor. Assim,
para todos os efeitos e propósitos, o sinal em c é praticamente idêntico ao sinal em a.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
136
Quando se efetua uma operação and com as entradas para a porta and, b e c, o resultado é um pulso
curto, como mostra a Figura 3.24(b), onde a largura do pulso, Δ, é igual ao atraso da porta do inversor, em
geral 5 ns ou menos. A saída da porta and é exatamente esse pulso deslocado pelo atraso da porta and, como
mostrado na parte superior da Figura 3.24(b). Esse deslocamento de tempo significa apenas que o latch D
será ativado com um atraso fixo após a fase ascendente do clock, mas não tem efeito sobre a largura do pulso.
Em uma memória com tempo de ciclo de 10 ns, um pulso de 1 ns para informar quando ler a linha D pode
ser curto o bastante, caso em que o circuito completo pode ser o da Figura 3.25. ale a pena observar que
esse projeto de flip-flop é atraente porque é fácil de entender, embora, na prática, sejam usados flip-flops
mais sofisticados.
Figura 3.24 (a) Gerador de pulso. (b) Temporizac
a
o em quatro pontos do circuito.
Tempo
a b
c
d
d
b AND c
c
b
a
(a)
(b)
∆
Figura 3.25 Flip-flop D.
Q
D
Q
Os símbolos padronizados para latches e flip-flops são mostrados na Figura 3.26. A Figura 3.26(a) é um latch
cujo estado é carregado quando o clock, CK, é 1, ao contrário da Figura 3.26(b), que é um latch cujo clock costuma
ser 1, mas cai para 0 momentaneamente para carregar o estado a partir de D. As figuras 3.26(c) e (d) são flip-flops
em vez de latches, o que é indicado pelo símbolo em ângulo nas entradas do clock. A Figura 3.26(c) muda de estado
na borda ascendente do pulso do clock (transição de 0 para 1), enquanto a Figura 3.26(d) muda de estado na borda
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 137
descendente (transição de 1 para 0). Muitos latches e flip-flops (mas não todos) também têm Q como uma saída, e
alguns têm duas entradas adicionais Set ou Preset (que forçam o estado para Q = 1) e Reset ou Clear (que forçam
o estado para Q = 0).
Figura 3.26 Latches e flip-flops D.
D Q
CK
(a)
D Q
CK
(b)
D Q
CK
(c)
D Q
(d)
CK
3.3.3 Registradores
Flip-flops podem ser combinados em grupos para criar registradores, que mantêm tipos de dados com
comprimentos maiores do que 1 bit. O registrador na Figura 3.27 mostra como oito flip-flops podem ser
ligados para formar um registrador armazenador de 8 bits. O registrador aceita um valor de entrada de 8
bits (I0 a I7) quando o clock CK fizer uma transição. Para implementar um registrador, todas as linhas de
clock são conectadas ao mesmo sinal de entrada CK, de modo que, quando o clock fizer uma transição,
cada registrador aceitará o novo valor de dados de 8 bits no barramento de entrada. Os próprios flip-flops
são do tipo da Figura 3.26(d), mas as bolhas de inversão nos flip-flops são canceladas pelo inversor ligado
ao sinal de clock CK, de modo que os flip-flops são carregados na transição ascendente do clock. Todos
os oito sinais clear também são ligados, de modo que, quando o sinal clear CLR passar para 0, todos os
flip-flops serão forçados a passar para o seu estado 0. Caso você queira saber por que o sinal de clock CK
é invertido na entrada e depois invertido novamente em cada flip-flop, um sinal de entrada pode não ter
corrente suficiente para alimentar todos os oito flip-flops; o inversor da entrada, na realidade, está sendo
usado como um amplificador.
Figura 3.27 Um registrador de 8 bits constru
do a partir de flip-flops de u
nico bit.
Q
CK
CLR
D Q
CK
CLR
D Q
CK
CLR
D Q
CK
CK
CLR
CLR
D
Q D
CK
CLR
Q D
CK
CLR
Q D
CK
CLR
CLR O4 O5 O6 O7
I4
O0 O1
I0 O2
I1 O3
I2 O3 CK
I5 I6 I7
Q D
Quando tivermos projetado um registrador de 8 bits, poderemos usá-lo como um bloco de montagem para
criar registradores maiores. Por exemplo, um registrador de 32 bits poderia ser criado pela combinação de dois
registradores de 16 bits, unindo seus sinais de clock CK e sinais de clear CLR. eremos os registradores e seus
usos com mais detalhes no Capítulo 4.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
138
3.3.4 Organizac
a
o da memo
ria
Embora agora tenhamos progredido de uma simples memória de 1 bit da Figura 3.23 para a de 8 bits
da Figura 3.27, para construir memórias grandes é preciso uma organização diferente, na qual palavras
individuais podem ser endereçadas. Uma organização de memória muito utilizada e que obedece a esse
critério é mostrada na Figura 3.28. Esse exemplo ilustra uma memória com quatro palavras de 3 bits. Cada
operação lê ou escreve uma palavra completa de 3 bits. Embora uma capacidade total de memória de 12
bits seja pouco mais do que nosso flip-flop octal, ela requer um número menor de pinos e, mais importante,
o projeto pode ser estendido com facilidade para memórias grandes. Observe que o número de palavras é
sempre uma potência de 2.
Figura 3.28 Diagrama lo
gico para uma memo
ria 4 x 3. Cada linha e
 uma das quatro palavras de 3 bits. Uma operac
a
o de leitura ou
escrita sempre le
 ou escreve uma palavra completa.
HABILITAR SAÍDA = CS · RD · OE
I0
I1
I2
Q
D
CK
O2
O1
O0
CS
RD
OE
CS • RD
A0
A1
Q
D
CK
Q
D
CK
Q
D
CK
Q
D
CK
Q
D
CK
Q
D
CK
Q
D
CK
Q
D
CK
Q
D
CK
Q
D
CK
Q
D
CK
Entrada de dados
Porta de
escrita
Linha de
seleção de
palavra 0
Linha de
seleção de
palavra 1
Linha de
seleção de
palavra 2
Palavra 0
Palavra 1
Palavra 2
Palavra 3
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 139
Embora à primeira vista talvez pareça complicada, a memória da Figura 3.28 na verdade é bastante
simples devido à sua estrutura regular. Ela tem oito linhas de entrada e três de saída. Três entradas são de
dados: I0, I1 e I2; duas são para o endereço: A0 e A1; e três são para controle: cs para chip select (selecionar
chip), rd para distinguir entre ler e escrever e oe para output enable (habilitar saída). As três saídas são para
dados: O0, O1 e O2. É interessante notar que essa memória de 12 bits requer menos sinais que o registra-
dor de 8 bits anterior. Este requer 20 sinais, incluindo alimentação e terra, enquanto a memória de 12 bits
requer apenas 13 sinais. O bloco de memória requer menos sinais porque, diferente do registrador, os
bits de memória compartilham um sinal de saída. Nessa memória, cada um dos 4 bits de memória compar-
tilha um sinal de saída. O valor das linhas de endereço determina quais dos 4 bits de memória pode receber
ou enviar um valor.
Para selecionar esse bloco de memória, a lógica externa deve estabelecer cs alto e também rd alto (1 lógico)
para leitura e baixo (0 lógico) para escrita. As duas linhas de endereço devem ser ajustadas para indicar qual das
quatro palavras de 3 bits deve ser lida ou escrita. Para uma operação de leitura, as linhas de entrada de dados
não são usadas, mas a palavra selecionada é colocada nas linhas de saída de dados. Para uma operação de escrita,
os bits presentes nas linhas de entrada de dados são carregados na palavra de memória selecionada; as linhas de
saída de dados não são usadas.
Agora, vamos examinar atentamente a Figura 3.28 para ver como isso funciona. As quatro portas and de
seleção de palavras à esquerda da memória formam um decodificador. Os inversores de entrada foram instalados
de modo que cada porta é habilitada (saída é alta) por um endereço diferente. Cada porta comanda uma linha
de seleção de palavra, de cima para baixo, para as palavras 0, 1, 2 e 3. Quando o chip é selecionado para uma
escrita, a linha vertical rotulada cs · rd estará alta, habilitando uma das quatro portas de escrita, dependendo de
qual linha de seleção de palavra esteja alta. A saída da porta de escrita comanda todos os sinais ck para a palavra
selecionada, carregando os dados de entrada nos flip-flops para aquela palavra. Uma escrita é efetuada apenas se
cs estiver alto e rd estiver baixo, e, ainda assim, somente a palavra selecionada por A0 e A1 é escrita; as outras
palavras não são alteradas.
Ler é semelhante a escrever. A decodificação de endereço é idêntica à da escrita. Mas agora a linha cs · rd está
baixa, portanto, todas as portas de escrita estão desabilitadas e nenhum dos flip-flops é modificado. Em vez
disso, a linha de seleção de palavra que for escolhida habilita as portas and vinculadas aos Q bits da palavra
selecionada. Portanto, a palavra selecionada entrega seus dados às portas or de quatro entradas na parte inferior
da figura, enquanto as outras três palavras produzem 0s. Em consequência, a saída das portas or é idêntica ao
valor armazenado na palavra selecionada. As três palavras não selecionadas não dão nenhuma contribuição à
saída.
Embora pudéssemos ter projetado um circuito no qual as três portas or fossem diretamente ligadas às três
linhas de saída de dados, essa operação às vezes causa problemas. Em particular, mostramos que as linhas de
entrada de dados e as linhas de saída de dados são diferentes, porém, nas memórias em si, as mesmas linhas são
usadas. Se tivéssemos vinculado as portas or às linhas de saída de dados, o chip tentaria produzir dados, isto é,
forçar cada linha a um valor específico, mesmo nas escritas, interferindo desse modo com os dados de entrada.
Por essa razão, é desejável ter um meio de conectar as portas or às linhas de saída de dados em leituras, mas
desconectá-las completamente nas escritas. O que precisamos é de um comutador eletrônico que possa estabele-
cer ou interromper uma conexão em poucos nanossegundos.
Felizmente, esses comutadores existem. A Figura 3.29(a) mostra o símbolo para o que denominamos buffer
não inversor, que tem uma entrada e uma saída de dados e uma entrada de controle. Quando a entrada de con-
trole estiver alta, o buffer age como um fio, como mostra a Figura 3.29(b). Quando a entrada de controle esti-
ver baixa, ele age como um circuito aberto, como mostra a Figura 3.29(c); é como se alguém desconectasse a
saída de dados do resto do circuito com um alicate de corte. Contudo, ao contrário do que aconteceria no caso
do alicate de corte, a conexão pode ser restaurada logo em seguida, dentro de alguns nanossegundos, apenas
fazendo o sinal de controle ficar alto novamente.
A Figura 3.29(d) mostra um buffer inversor, que funciona como um inversor normal quando o controle
estiver alto, e desconecta a saída do circuito quando o controle estiver baixo. Ambos os tipos de buffers são
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
140
dispositivos de três estados, porque podem produzir 0, 1, ou nenhum dos dois (circuito aberto). Buffers também
amplificam sinais, portanto, podem comandar muitas entradas simultaneamente. Às vezes, eles são usados em
circuitos por essa razão, mesmo quando suas propriedades de comutação não são necessárias.
oltando ao circuito de memória, agora já deve estar claro para que servem os três buffers não inversores
nas linhas de saída de dados. Quando cs, rd e oe estiverem todos altos, o sinal output enable também está alto,
habilitando os buffers e colocando uma palavra nas linhas de saída. Quando qualquer um dos cs, rd ou oe estiver
baixo, as saídas de dados são desconectadas do resto do circuito.
3.3.5 Chips de memo
ria
O bom da memória da Figura 3.28 é que ela pode ser ampliada com facilidade para tamanhos maiores. Em
nosso desenho, a memória é 4 × 3, isto é, quatro palavras de 3 bits cada. Para ampliá-la para 4 × 8, basta adicionar
cinco colunas de quatro flip-flops cada, bem como cinco linhas de entrada e cinco linhas de saída. Para passar de
4 × 3 para 8 × 3, devemos acrescentar quatro linhas de três flip-flops cada, bem como uma linha de endereço A2.
Com esse tipo de estrutura, o número de palavras na memória deve ser uma potência de 2 para que haja o máximo
de eficiência, mas o número de bits em uma palavra pode ser qualquer um.
Como a tecnologia de circuitos integrados se ajusta bem à fabricação de chips cuja estrutura interna é um
padrão bidimensional repetitivo, chips de memória são uma aplicação ideal para ela. À medida que a tecnologia
melhora, o número de bits que podem ser colocados em um chip continua crescendo, normalmente por um fator
de dois a cada 18 meses (lei de Moore). Os chips maiores nem sempre tornam os menores obsoletos devido aos
diferentes compromissos entre capacidade, velocidade, energia, preço e conveniência da interface. Em geral, os
chips maiores disponíveis no momento são vendidos por preços mais elevados, portanto, são mais caros por bit
do que os antigos, menores.
Há vários modos de organizar o chip para qualquer tamanho de memória dado. A Figura 3.30 mostra duas
organizações possíveis para um chip de memória mais antigo de 4 Mbits de tamanho: 512 K × 8 e 4.096 K × 1. (A
propósito, os tamanhos de chips de memória costumam ser citados em bits em vez de bytes, e por isso adotaremos
essa convenção.) Na Figura 3.30(a), são necessárias 19 linhas de endereço para endereçar um dos 219
bytes e oito
linhas de dados para carregar e armazenar o byte selecionado.
Cabe aqui uma observação sobre tecnologia. Em alguns pinos, a alta tensão provoca uma ação. Em outros, é
a baixa tensão que causa uma ação. Para evitar confusão, preferimos manter a coerência e dizer sempre que o sinal
é afirmado (em vez de dizer que fica alto ou baixo), o que significa que foi disparado para provocar alguma ação.
Assim, para alguns pinos, afirmá-lo significa estabelecê-lo alto. Para outros, significa estabelecer o pino baixo. Os
nomes de sinais de pinos afirmados baixos são distinguidos por uma barra superior. Assim, um sinal com rótulo
cs é ativado alto, mas um sinal com rótulo cs é ativado baixo. O oposto de afirmado é negado. Quando nada de
especial estiver acontecendo, os pinos são negados.
Figura 3.29 (a) Buffer na
o inversor. (b) Efeito de (a) quando o controle esta
 alto. (c) Efeito de (a) quando o controle esta
 baixo. (d)
Buffer inversor.
Controle
(b)
(a) (d)
(c)
Entrada
de dados
Saída de
dados
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 141
Agora, vamos voltar ao nosso chip de memória. Uma vez que um computador costuma ter muitos chips
de memória, é preciso um sinal para selecionar o chip necessário no momento em questão, de modo que ele
responda e todos os outros não. O sinal cs (chip select – seleção de chip) existe para essa finalidade e é ativado
para habilitar o chip. Além disso, é preciso uma maneira de distinguir entre leituras e escritas. O sinal we (write
enable – habilitar escrita) é usado para indicar que os dados estão sendo escritos, e não lidos. Por fim, o sinal oe
(output enable – habilitar saída) é afirmado para comandar os sinais de saída. Quando ele não é afirmado, a saída
do chip é desconectada do circuito.
Na Figura 3.30(b), é usado um esquema de endereçamento diferente. Esse chip é organizado internamente
como uma matriz 2.048 × 2.048 de células de 1 bit, o que dá 4 Mbits. Para endereçar o chip, em primeiro lugar
uma linha é selecionada ao se colocar seu número de 11 bits nos pinos de endereço. Então o ras (row address
strobe – strobe de endereço de linha) é afirmado. Em seguida, um número de coluna é colocado nos pinos de
endereço e o cas (column address strobe – strobe de endereço de coluna) é afirmado. O chip responde aceitando
ou entregando um bit de dados.
Chips de memória de grande porte costumam ser construídos como matrizes n × n endereçadas por linha
e coluna. Essa organização reduz o número de pinos requerido, mas também torna mais lento o endereçamento
do chip, já que são necessários dois ciclos, um para a linha e outro para a coluna. Para recuperar um pouco da
velocidade perdida por esse projeto, alguns chips de memória podem receber um endereço de linha acompanhado
por uma sequência de endereços de coluna para acessar bits consecutivos em uma linha.
Anos atrás, os maiores chips de memória costumavam ser organizados como os da Figura 3.30(b). À medida
que as palavras de memória cresciam de 8 bits até 32 bits e mais, os chips de 1 bit começaram a ser inconvenien-
tes. Construir uma memória com uma palavra de 32 bits usando chips de 4.096 K × 1 requer 32 chips em paralelo.
Esses 32 chips têm capacidade total de no mínimo 16 MB, ao passo que usar chips de 512 K × 8 requer somente
quatro chips em paralelo e permite memórias pequenas, de até 2 MB. Para evitar ter 32 chips para memória,
grande parte dos fabricantes lançou famílias com 4, 8 e 16 bits de largura. A situação com as palavras de 64 bits
é pior ainda, é claro.
Dois exemplos de chips modernos de 512 Mbits são dados na Figura 3.31. Esses chips têm quatro bancos de
memória internos de 128 Mbits cada, o que requer duas linhas de seleção de banco para escolher um banco. O
projeto da Figura 3.31(a) é de um chip de 32 M × 16 com 13 linhas para o sinal ras, 10 linhas para o sinal cas e
2 linhas para a seleção de banco. Juntos, esses 25 sinais permitem o endereçamento de cada uma das 225
células
Figura 3.30 Dois modos de organizar um chip de memo
ria de 4 Mbits.
Chip de
memória de
4.096 K x 1
(4 Mbits)
D0
A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
A11
A12
A13
A14
A15
A16
A17
A18
D1
D2
D3
D4
D5
D6
D7
WE
(a)
CS OE
A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
RAS
CAS
D
WE
(b)
CS OE
Chip de
memória de
512 K x 8
(4 Mbits)
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
142
internas de 16 bits. Em comparação, a Figura 3.31(b) apresenta um projeto de 128 M × 4 com 13 linhas para o
sinal ras, 12 linhas para o sinal cas e 2 linhas para a seleção de banco. Nesse caso, 27 sinais podem selecionar
quaisquer das 227
células internas de 4 bits a serem endereçadas. A decisão sobre o número de linhas e de colunas
que um chip tem é tomada por razões de engenharia. A matriz não precisa ser quadrada.
Figura 3.31 Dois modos de organizar um chip de memo
ria de 512 Mbits.
A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
A11
A12
D0
D1
D2
D3
D4
D5
D6
D7
WE
(a)
CS OE
A0
A1
A2
A3
A4
A5
A6
A7
A8
A9
A10
RAS
CAS
WE
(b)
CS OE
RAS
CAS
D8
D9
D10
D11
D12
D13
D14
D15
A11
A12
D0
D1
D2
D3
Chip de
memória de
32 M × 16
(512 Mbits)
Banco 0
Banco 1
Chip de
memória de
128 M × 4
(512 Mbits)
Banco 0
Banco 1
Esses exemplos demonstram duas questões separadas e independentes para o projeto do chip de memória.
A primeira é a largura da saída (em bits): o chip entrega 1, 4, 8, 16 ou algum outro número de bits de uma vez
só? A segunda é se todos os bits de endereço são apresentados em pinos separados de uma vez só ou se as linhas
e colunas são apresentadas em sequência, como nos exemplos da Figura 3.31. Um projetista de chips de memória
tem de responder a ambas as perguntas antes de iniciar o projeto do chip.
3.3.6 RAMs e ROMs
Todas as memórias que estudamos até aqui podem ser escritas e lidas. Elas são denominadas memórias RM
(Random Access Memory – memória de acesso aleatório), um nome suspeito porque todos os chips de memória
têm acesso aleatório. No entanto, o termo já é muito utilizado para que o mudemos agora. RAMs podem ser de
duas variedades, estáticas e dinâmicas. Nas estáticas (Static RMs  SRMs), a construção interna usa circuitos
similares ao nosso flip-flop D básico. Uma das propriedades dessas memórias é que seus conteúdos são conser-
vados enquanto houver fornecimento de energia: segundos, minutos, horas e até mesmo dias. As RAMs estáticas
são muito rápidas. Um tempo de acesso típico é da ordem de um nanossegundo ou menos. Por essa razão, elas são
muito usadas como memória cache.
RMS dinâmicas (ynamic RMs  RMs), ao contrário, não usam flip-flops. Em vez disso, uma RAM
dinâmica é um arranjo de células, cada uma contendo um transistor e um pequenino capacitor. Os capacitores
podem ser carregados ou descarregados, permitindo que 0s e 1s sejam armazenados. Como a carga elétrica tende
a vazar, cada bit em uma RAM dinâmica deve ser renovado (recarregado) com alguns milissegundos de intervalo
para evitar que os dados desapareçam. Como a lógica externa é que tem de cuidar da renovação, as RAMs dinâmi-
cas precisam de uma interface mais complexa do que as estáticas, embora em muitas aplicações essa desvantagem
seja compensada por suas maiores capacidades.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 143
isto que as RAMs dinâmicas precisam de apenas um transistor e um capacitor por bit, em comparação com
os seis transistores por bit para a melhor RAM estática, elas têm densidade muito alta (muitos bits por chip). Por
essa razão, as memórias principais quase sempre são construídas com RAMs dinâmicas. Contudo, essa grande
capacidade tem um preço: são lentas (dezenas de nanossegundos). Dessa maneira, a combinação de uma cache
de RAM estática e uma memória principal de RAM dinâmica tenta combinar as boas propriedades de cada uma.
Existem diversos tipos de RAMs dinâmicas. A mais antiga ainda existente (em computadores antigos) é a
DRAM FPM (Fast Page Mode  modo de página rápida). Ela é organizada internamente como uma matriz
de bits e funciona da seguinte maneira: o hardware escolhe um endereço de linha e então seleciona endereços de
coluna um a um, como descrevemos para o ras e o cas no contexto da Figura 3.30. Sinais explícitos informam
à memória quando é hora de responder, de modo que ela funciona de forma assíncrona com o clock do sistema
principal.
A DRAM FPM foi substituída pela EO (Extended ata Output  saída de dados ampliada), que permite
iniciar uma segunda referência à memória antes de ser concluída a referência à memória precedente. Esse parale-
lismo simples não acelerava uma referência individual à memória, mas melhorava a largura de banda da memória,
resultando em mais palavras por segundo.
FPM e EDO funcionavam bastante bem quando os tempos de ciclo de chips de memória eram de 12 nanos-
segundos ou mais lentos. Quando os processadores ficaram tão rápidos que era mesmo preciso ter memórias mais
rápidas, a FPM e a EDO foram substituídas pela SRM (Synchronous RM  RM síncrona), que é uma
híbrida de RAM estática e dinâmica, comandada pelo clock do sistema principal. A grande vantagem da SDRAM é
que o clock elimina a necessidade de sinais de controle para informar ao chip de memória quando responder. Em
vez disso, a CPU informa à memória por quantos ciclos ela deve funcionar e então a inicia. Em cada ciclo subse-
quente, a memória entrega 4, 8 ou 16 bits, dependendo de quantas linhas de saída ela tem. Eliminar a necessidade
de sinais de controle aumenta a taxa de dados entre CPU e memória.
A melhoria seguinte em relação à SDRAM foi a SDRAM R (ouble ata Rate  dupla taxa de dados).
Com esse tipo de memória, o chip de memória produz saída na borda ascendente do clock e também na borda
descendente, dobrando a taxa de dados. Portanto, um chip DDR de 8 bits de largura funcionando a 200 MHz
entrega dois valores de 8 bits 200 milhões de vezes por segundo (por um curto intervalo, é claro), o que dá uma
taxa de saída (burst) teórica de 3,2 Gbps. As interfaces de memória DDR2 e DDR3 oferecem desempenho adi-
cional em relação à DDR, aumentando as velocidades do barramento de memória para 533 MHz e 1.067 MHz,
respectivamente. No momento em que este livro era impresso, os chips DDR3 mais velozes poderiam enviar
dados a 17,067 GB/s.
Chips de memo
ria na
o vola
til
RAMs não são o único tipo de chip de memória. Em muitas aplicações, como brinquedos, eletrodomésti-
cos e carros, o programa e alguns dos dados devem permanecer armazenados mesmo quando o fornecimento
de energia for interrompido. Além do mais, uma vez instalados, nem o programa nem os dados são alterados.
Esses requisitos levaram ao desenvolvimento de ROMs (Read-Only Memories  memórias somente de leitura),
que não podem ser alteradas nem apagadas, seja intencionalmente ou não. Os dados de uma ROM são inseridos
durante sua fabricação por um processo que expõe um material fotossensível por meio de uma máscara que con-
tém o padrão de bits desejado e então grava o padrão sobre a superfície exposta (ou não exposta). A única maneira
de mudar o programa em uma ROM é substituir o chip inteiro.
ROMs são muito mais baratas que RAMs quando fabricadas em volumes grandes o bastante para cobrir o
custo da fabricação da máscara. Todavia, são inflexíveis porque não podem ser alteradas após a manufatura, e
o tempo decorrido entre fazer o pedido e receber as ROMs pode chegar a semanas. Para facilitar o desenvol-
vimento pelas empresas de novos produtos com ROM, foi inventada a PROM (Programmable ROM – ROM
programável). Uma PROM é como uma ROM, exceto que ela pode ser programada (uma vez) em campo, elimi-
nando o tempo de espera entre produção e entrega. Muitas PROMs contêm um arranjo de minúsculos fusíveis
em seu interior. Um fusível específico pode ser queimado selecionando sua linha e coluna e então aplicando
alta tensão a um pino especial no chip.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
144
O desenvolvimento seguinte nessa linha foi a EPROM (Erasable PROM – PROM apagável), que não só pode
ser programada, mas também apagada em campo. Quando a janela de quartzo de uma EPROM é exposta a uma
forte luz ultravioleta durante 15 minutos, todos os bits são definidos em 1. Se a expectativa é ter muitas alterações
durante o ciclo de projeto, as EPROMs são muito mais econômicas do que as PROMs, porque podem ser reuti-
lizadas. As EPROMS costumam ter a mesma organização que as RAMs estáticas. A EPROM 27C040 de 4 Mbits,
por exemplo, usa a organização da Figura 3.31(a), que é típica de uma RAM estática. O interessante é que chips
antigos como este não desaparecem. Eles apenas se tornam mais baratos e são usados em produtos inferiores,
que são altamente sensíveis ao custo. Um 27C040 agora pode ser comprado no varejo por menos de US$ 3, e por
muito menos em grandes volumes.
Ainda melhor do que a EPROM é a EEPROM, que pode ser apagada aplicando-se pulsos em vez de ser
exposta à luz ultravioleta dentro de uma câmara especial. Além disso, uma EEPROM pode ser reprogramada no
local, enquanto uma EPROM tem de ser inserida em um dispositivo especial de programação de EPROM para ser
programada. Uma desvantagem é que a capacidade das maiores EEPROMs é em geral somente 1/64 da capacidade
das EPROMs comuns, e sua velocidade é a metade. EEPROMs não podem competir com DRAMs ou SRAMs por-
que são 10 vezes mais lentas, sua capacidade é 100 vezes menor e são muito mais caras. Elas são usadas somente
em situações em que sua não volatilidade for crucial.
Um tipo mais recente de EEPROM é a memória flash. Diferente da EPROM, que é apagada pela exposição à
luz ultravioleta, e da EEPROM, cujos bytes podem ser apagados, os blocos da memória flash podem ser apagados
e reescritos. Como a EEPROM, a memória flash pode ser apagada sem ser removida do circuito. ários fabricantes
produzem pequenas placas de circuito impresso com até 64 GB de memória flash que são utilizadas como um
“filme” para armazenar fotos em câmeras digitais e muitas outras finalidades. Como já vimos no Capítulo 2, a
memória flash agora está começando a substituir os discos mecânicos. Assim como um disco, a memória flash
oferece tempos de acesso menores com menor consumo de energia, mas com um custo por bit muito mais alto.
Um resumo dos diversos tipos de memória pode ser visto na Figura 3.32.
Figura 3.32 Comparac
a
o entre va
rios tipos de memo
rias (Arranjo de portas programa
vel em campo).
Tipo Categoria Modo de apagar Byte alterável Volátil Utilização típica
SRAM Leitura/escrita Elétrico Sim Sim Cache de nível 2
DRAM Leitura/escrita Elétrico Sim Sim Memória principal (antiga)
SDRAM Leitura/escrita Elétrico Sim Sim Memória principal (nova)
ROM Somente de leitura Não é possível Não Não Equipamentos de grande volume
PROM Somente de leitura Não é possível Não Não Equipamentos de pequeno volume
EPROM Principalmente leitura Luz UV Não Não Prototipagem de dispositivos
EEPROM Principalmente leitura Elétrico Sim Não Prototipagem de dispositivos
Flash Leitura/escrita Elétrico Não Não Filme para câmera digital
Field-programmable gate arrays
Como vimos no Capítulo 1, Field-Programmable Gate rrays (FPGs) são chips que contêm lógica pro-
gramável, de modo que podem formar um circuito lógico qualquer simplesmente carregando o FPGA com dados
de configuração apropriados. A principal vantagem dos FPGAs é que novos circuitos de hardware podem ser
construídos em horas, em vez dos meses necessários para fabricar Cs. Porém, os circuitos integrados não serão
extintos, pois ainda possuem uma vantagem de custo significativa em relação aos FPGAs para aplicações de alto
volume, e também são mais rápidos e usam muito menos energia. Contudo, com suas vantagens de tempo de
projeto, os FPGAs são usados constantemente para protótipo de projeto e aplicações com baixo volume.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 145
Agora, vejamos o interior de um FPGA para entender como ele pode ser usado para executar uma grande gama
de circuitos lógicos. O chip FPGA contém dois componentes principais que são replicados muitas vezes: LUs
(LookUp ables  tabelas de pesquisa) e interconexões programáveis. ejamos agora como estes são utilizados.
Uma LUT, mostrada na Figura 3.33(a), é uma pequena memória programável que produz um sinal de saída
opcionalmente para um registrador, que é então enviada para a interconexão programável. A memória progra-
mável é usada para criar uma função lógica qualquer. A LUT na figura tem uma memória de 16 × 4, que pode
simular qualquer circuito lógico com 4 bits de entrada e 4 bits de saída. A programação da LUT requer a carga
da memória com as respostas apropriadas da lógica combinatória sendo simulada. Em outras palavras, se a lógica
combinatória produz o valor Y quando recebe a entrada X, o valor Y é escrito na LUT no índice X.
O projeto de exemplo na Figura 3.33(b) mostra como uma única LUT de 4 entradas poderia executar um
contador de 3 bits com reset. O exemplo de contador conta de modo contínuo somando um (módulo 4) ao valor
atual, a menos que um sinal de reset CLR seja afirmado, que nesse caso retorna o valor do contador a zero.
Para pôr em prática o contador do exemplo, as quatro entradas superiores da LUT são todas zero. Essas
entradas enviam o valor zero quando o contador é reiniciado. Assim, o bit mais significativo da entrada da LUT
(I3) representa a entrada de reset (CLR) que é ativada com uma lógica 1. Para as entradas restantes da LUT, o
valor no índice I0..3 da LUT contém o valor (I + 1) módulo 4. Para concluir o projeto, o sinal de saída O0..3 deve
ser conectado, usando a interconexão programável para o sinal de entrada interno I0..3.
Para entender melhor o contador baseado em FPGA com reset, vamos considerar sua operação. Se, por exem-
plo, o estado atual do contador for 2 e o sinal de reset (CLR) não for afirmado, o endereço de entrada da LUT será
2, que produzirá uma saída de 3 nos flip-flops. Se o sinal de reset (CLR) fosse afirmado para o mesmo estado, a
entrada na LUT seria 6, que produziria o próximo estado de 0.
Apesar de tudo, esse pode parecer um modo arcaico de se construir um contador com reset e, de fato, um
projeto totalmente personalizado, com um circuito incrementador e sinais de reset para os flip-flops, seria menor,
mais rápido e usaria menos energia. A principal vantagem do projeto baseado em FPGA é que você pode ajustá-lo
em uma hora em casa, enquanto o projeto totalmente personalizado, mais eficiente, deve ser fabricado com base
no silício, o que poderia levar pelo menos um mês.
Figura 3.33 (a) Uma tabela de pesquisa (LUT) de um FPGA. (b) A configurac
a
o da LUT para criar um contador de apagamento de 3 bits.
CK
0 1
1 2
2 3
3 0
O2..0 O2..0
O0..3
I0..3
CK CK
I CLR
4 0
5 0
6 0
7 0
D Q
3
FPGA Contador
Endereço Dados Endereço Dados
Da
interconexão
programável
Endereço
Dados
Memória
de 16 × 4
Flip-flop
×4
À
interconexão
programável
Designação de sinal
Para usar um FPGA, o projeto precisa ser descrito usando uma descrição de circuito ou uma linguagem de
descrição de hardware (ou seja, uma linguagem de programação usada para descrever estruturas de hardware).
O projeto é então processado por um sintetizador, que mapeia o circuito para uma arquitetura FPGA específica.
(a)
(b)
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
146
Um desafio do uso de FPGAs é que o projeto que você quer mapear nunca parece ser o suficiente. Os FPGAs são
fabricados com uma quantidade variável de LUTs, com quantidades maiores custando mais. Em geral, se o seu
projeto não for suficiente, você terá que simplificar ou abrir mão de alguma funcionalidade, ou então comprar
um FPGA maior (e mais caro). Projetos muito grandes podem não caber nos maiores FPGAs, exigindo que o
projetista mapeie o projeto em vários FPGAs; essa tarefa é definitivamente mais difícil, porém, ainda muito mais
fácil do que projetar um circuito integrado personalizado completo.
3.4 Chips de CPU e barramentos
Agora que já temos todas essas informações sobre circuitos integrados, clocks e chips de memória, pode-
mos começar a juntar todas as peças, examinando sistemas completos. Nesta seção, estudaremos primeiro
alguns aspectos gerais das CPUs do ponto de vista do nível lógico digital, incluindo a pinagem (pinout) (isto é,
o que significam os sinais dos vários pinos). Como as CPUs estão tão entrelaçadas com o projeto dos barramen-
tos que utilizam, também faremos uma introdução ao projeto de barramentos nesta seção. Nas seções seguintes,
daremos exemplos detalhados de CPUs e seus barramentos e de como é a interface entre eles.
3.4.1 Chips de CPU
Todas as CPUs modernas são contidas em um único chip, o que faz sua interação com o resto do sistema
ser bem definida. Cada chip de CPU tem um conjunto de pinos por meio dos quais deve ocorrer toda sua comu-
nicação com o mundo exterior. Alguns pinos produzem sinais da CPU para o mundo exterior; outros aceitam
sinais do mundo exterior; alguns podem fazer as duas coisas. Entendendo a função de todos esses pinos, podemos
aprender como a CPU interage com a memória e os dispositivos de E/S no nível lógico digital.
Os pinos de um chip de CPU podem ser divididos em três tipos: de endereço, de dados e de controle. Eles são
conectados a pinos similares na memória e a chips de E/S por meio de um conjunto de fios paralelos, denominado
barramento. Para buscar uma instrução, primeiro a CPU coloca o endereço de memória daquela instrução em seus
pinos de endereço. Então, ela ativa uma ou mais linhas de controle para informar à memória que ela quer ler uma
palavra, por exemplo. A memória responde colocando a palavra requisitada nos pinos de dados da CPU e ativando
um sinal que informa o que acabou de fazer. Quando percebe esse sinal, a CPU aceita a palavra e executa a instrução.
A instrução pode requisitar leitura ou escrita de palavras de dados, caso em que todo o processo é repetido
para cada palavra adicional. Mais adiante, vamos entrar nos detalhes do modo de funcionamento da leitura e da
escrita. Por enquanto, o importante é entender que a CPU se comunica com a memória e com dispositivos de
E/S apresentando sinais em seus pinos e aceitando sinais em seus pinos. Nenhuma outra comunicação é possível.
Dois dos parâmetros fundamentais que determinam o desempenho de uma CPU são o número de pinos de
endereço e o número de pinos de dados. Um chip com m pinos de endereço pode endereçar até 2m
localizações
de memória. alores comuns de m são 16, 32 e 64. De modo semelhante, um chip com n pinos de dados pode ler
ou escrever uma palavra de n bits em uma única operação. alores comuns de n são 8, 32 e 64. Uma CPU com 8
pinos de dados efetuará quatro operações para ler uma palavra de 32 bits, enquanto uma CPU com 32 pinos de
dados pode executar a mesma tarefa em uma única operação. Assim, o chip com 32 pinos de dados é muito mais
rápido; porém, invariavelmente, também é mais caro.
Além dos pinos de endereço e de dados, cada CPU tem alguns pinos de controle. Os pinos de controle regulam
o fluxo e a temporização de dados que vêm da CPU e vão para ela, além de ter outras utilizações diversas. Todas as
CPUs têm pinos para energia elétrica (geralmente +1,2 volt a +1,5 volt), para terra e para um sinal de clock (uma
onda quadrada com uma frequência bem definida), mas os outros pinos variam muito de um chip para outro. Não
obstante, os pinos de controle podem ser agrupados aproximadamente nas seguintes categorias principais:
1. Controle de barramento.
2. nterrupções.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 147
3. Arbitragem de barramento.
4. Sinalização de coprocessador.
5. Estado.
6. Diversos.
Logo faremos uma breve descrição de cada uma dessas categorias. Quando examinarmos os chips ntel Core
i7, T OMAP4430 e Atmel ATmega168, mais adiante, daremos mais detalhes. Um chip de CPU genérico que usa
esses grupos de sinais pode ser visto na Figura 3.34.
Figura 3.34 Pinagem lo
gica de uma CPU gene
rica. As setas indicam sinais de entrada e sinais de sa
da. Os segmentos de reta diagonais
indicam que sa
o utilizados va
rios pinos. Ha
 um nu
mero que indica quantos sa
o os pinos para uma CPU espec
fica.
Símbolo para
aterramento elétrico
Φ
Endereçamento
Dados
Controle de
barramento
Interrupções
Micropro-
cessador
típico
Arbitragem de
barramento
Coprocessador
Estado
Diversos
Símbolo para sinal
de clock
Alimentação
A maioria dos pinos de controle do barramento são saídas da CPU para o barramento (e, portanto, entradas
para a memória e chips de E/S) que informam se a CPU quer ler ou escrever na memória ou fazer outra coisa
qualquer. A CPU usa esses pinos para controlar o resto do sistema e informar o que ela quer fazer.
Os pinos de interrupção são entradas que vêm de dispositivos de E/S para a CPU. Em grande parte dos sis-
temas, a CPU pode dizer a um dispositivo de E/S que inicie uma operação e então continuar e fazer outra coisa
qualquer enquanto o dispositivo de E/S está realizando seu trabalho. Quando a E/S estiver concluída, o chip
controlador de E/S ativa um sinal em um desses pinos para interromper a CPU e fazê-la prestar algum serviço ao
dispositivo de E/S, por exemplo, verificar se ocorreram erros de E/S. Algumas CPUs têm um pino de saída para
confirmar o sinal de interrupção.
Os pinos de arbitragem de barramento são necessários para disciplinar o tráfego no barramento de modo
a impedir que dois dispositivos tentem usá-lo ao mesmo tempo. Do ponto de vista da arbitragem, a CPU é um
dispositivo e tem de requisitar o barramento como qualquer outro.
Alguns chips de CPUs são projetados para funcionar com coprocessadores, como chips de ponto flutuante,
mas às vezes também com chips gráficos ou outros chips. Para facilitar a comunicação entre CPU e coprocessador,
há pinos especiais dedicados a fazer e aceitar requisições.
Além desses sinais, há outros pinos diversos presentes em algumas CPUs. Alguns deles fornecem ou aceitam
informações de estado, outros são úteis para depuração ou para reiniciar o computador, e outros mais estão pre-
sentes para garantir a compatibilidade com chips de E/S mais antigos.
3.4.2 Barramentos de computador
Um barramento é um caminho elétrico comum entre vários dispositivos. Os barramentos podem ser cate-
gorizados por sua função. Podem ser usados no interior da CPU para transportar dados de e para a ULA ou ser
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
148
externos à CPU, para conectá-la à memória ou a dispositivos de E/S. Cada tipo tem seus próprios requisitos e
propriedades. Nesta seção e nas seguintes, focalizaremos barramentos que conectam a CPU à memória e a dispo-
sitivos de E/S. No capítulo seguinte, examinaremos mais de perto os barramentos internos à CPU.
Os primeiros computadores pessoais tinham somente um barramento externo, ou barramento do sistema,
que consistia em 50 a 100 fios de cobre paralelos gravados na placa-mãe, com conectores a intervalos regulares
para ligação com a memória e placas de E/S. Os computadores pessoais modernos em geral têm um barramento de
uso especial entre a CPU e a memória e (pelo menos) outro barramento para os dispositivos de E/S. Um sistema
mínimo, com um barramento de memória e um barramento de E/S, é ilustrado na Figura 3.35.
Figura 3.35 Sistema de computador com va
rios barramentos.
Chip de CPU
Registradores
Barramentos
ULA
Barramento no chip
Controlador
de
barramento
Barramento de
memória
Memória
Barramento de E/S
Disco Rede
Impres-
sora
Na literatura, às vezes os barramentos são representados por setas largas e sombreadas, como nesta
figura. A distinção entre essas setas e uma linha reta cortada por um pequeno segmento de reta inclinado
acompanhado de um número de bits é sutil. Quando todos os bits são do mesmo tipo, por exemplo, todos
são bits de endereço ou todos são bits de dados, então costuma ser usada a representação pelo segmento de
reta diagonal. Quando estão envolvidas linhas de endereço, de dados e de controle, a seta larga sombreada
é a mais comum.
Embora os projetistas de CPUs tenham liberdade para usar qualquer tipo de barramento que quiserem dentro
do chip, para possibilitar a ligação de placas projetadas por terceiros ao barramento de sistema é preciso haver
regras bem definidas sobre o modo de funcionamento do barramento, às quais todos os dispositivos a ele ligados
têm de obedecer. Essas regras são denominadas protocolo de barramento. Além disso, são necessárias especifi-
cações mecânicas e elétricas, de modo que placas de terceiros caibam no suporte da placa e tenham conectores
compatíveis com os da placa-mãe, tanto em termos mecânicos quanto em termos de tensões, temporizações etc.
Ainda assim, outros barramentos não possuem especificações mecânicas, pois são projetados para serem usados
dentro de um circuito integrado, por exemplo, para unir componentes dentro de um sistema-em-um-chip (SoC –
System-on-a-Chip).
Há inúmeros barramentos em uso no mundo dos computadores. Alguns dos mais conhecidos, no passado
e atualmente (com exemplos), são: Omnibus (PDP-8), Unibus (PDP-11), Multibus (8086), barramento ME
(equipamento para laboratório de física), barramento do BM PC (PC/T), barramento SA (PC/AT), barramento
ESA (80386), Microchannel (PS/2), Nubus (Macintosh), barramento PC (muitos PCs), barramento SCS (mui-
tos PCs e estações de trabalho), Universal Serial Bus (PCs modernos) e FireWire (equipamentos eletrônicos de
consumo). O mundo provavelmente seria um lugar melhor se todos os barramentos, menos um, desaparecessem
repentinamente da face da Terra (tudo bem, menos dois, então). nfelizmente, a padronização nessa área parece
muito improvável porque muito dinheiro já foi investido em todos esses sistemas incompatíveis.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 149
A propósito, existe outra interconexão, PC Express, que geralmente é chamada de barramento, mas na ver-
dade não é barramento algum. amos estudá-la mais adiante neste capítulo.
Agora, vamos iniciar nosso estudo do funcionamento dos barramentos. Alguns dispositivos ligados a um
barramento são ativos e podem iniciar transferências no barramento, ao passo que outros são passivos e esperam
requisições. Os ativos são denominados mestres; os passivos são denominados escravos. Quando a CPU ordena a
um controlador que leia ou escreva um bloco, ela está agindo como mestre e o controlador de disco, como escra-
vo. Todavia, mais tarde, o controlador de disco pode agir como um mestre quando manda a memória aceitar as
palavras que são lidas do drive de disco. árias combinações típicas mestre e escravo estão relacionadas na Figura
3.36. Em nenhuma circunstância a memória pode ser mestre.
Figura 3.36 Exemplos de mestres e escravos de barramentos.
Mestre Escravo Exemplo
CPU Memória Buscar instruções e dados
CPU Dispositivo de E/S Iniciar transferência de dados
CPU Coprocessador CPU que passa instruções para o coprocessador
Dispositivo de E/S Memória DMA (acesso direto à memória)
Coprocessador CPU Coprocessador que busca operandos na CPU
Os sinais binários emitidos por dispositivos de computador muitas vezes são fracos demais para energizar um
barramento, em especial se ele for relativamente longo ou tiver muitos dispositivos ligados a ele. Por esse motivo, a
maioria dos mestres de barramento está conectada a ele por um chip denominado controlador de barramento, que é
nada mais que um amplificador digital. De modo semelhante, grande parte dos escravos está conectada ao barramento
por um receptor de barramento. Quando dispositivos podem agir como mestres e também como escravos, é usado um
chip combinado denominado transceptor de barramento. Essas interfaces de barramento são com frequência disposi-
tivos de três estados, o que permite que flutuem (se desconectem) quando não são necessários ou então se conectem
de modo um tanto diferente, denominado coletor aberto, que consegue um efeito semelhante. Quando dois ou mais
dispositivos em uma linha de coletor aberto ativam a linha ao mesmo tempo, o resultado é o OR booleano de todos os
sinais. Esse arranjo costuma ser denominado OR cabeado (wired-OR). Na maioria dos barramentos, algumas das linhas
são de três estados, e outras, que precisam da propriedade OR cabeado, são de coletor aberto.
Assim como uma CPU, um barramento também tem linhas de endereço, de dados e de controle. Contudo,
nem sempre há um mapeamento um-para-um entre os pinos da CPU e os sinais do barramento. Por exemplo,
algumas CPUs têm três pinos que codificam se ela está fazendo uma leitura de memória, uma escrita na memória,
uma leitura de E/S, uma escrita de E/S ou alguma outra operação. Um barramento típico poderia ter uma linha
para leitura de memória, uma segunda para escrita na memória, uma terceira para leitura de E/S, uma quarta para
escrita de E/S e assim por diante. Nesse caso, seria necessário um chip decodificador entre a CPU e o barramento
para compatibilizar os dois lados, isto é, converter o sinal de 3 bits codificado em sinais separados que podem
comandar as linhas do barramento.
Projeto e operação de barramento são questões de tamanha complexidade que há inúmeros livros escritos
apenas sobre isso (Anderson et al., 2004; Solari e Willse, 2004). Os principais tópicos do projeto de barramento
são largura, clock, arbitragem e operações. Cada um desses tópicos tem impacto substancial sobre a velocidade e
a largura de banda do barramento. Agora, examinaremos cada um nas quatro seções seguintes.
3.4.3 Largura do barramento
A largura do barramento é o parâmetro de projeto mais óbvio. Quanto mais linhas de endereço tiver um bar-
ramento, mais memória a CPU pode endereçar diretamente. Se um barramento tiver n linhas de endereço, então
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
150
uma CPU pode usá-las para endereçar 2n
localizações de memória diferentes. Para memórias de grande porte, os
barramentos precisam de muitas linhas de endereço, o que parece algo bem simples.
O problema é que barramentos largos precisam de mais fios do que os estreitos, e também ocupam mais
espaço físico (por exemplo, na placa-mãe), além de precisar de conectores maiores. Todos esses fatores encare-
cem o barramento e, por isso, há um compromisso entre tamanho máximo de memória e custo do sistema. Um
sistema com barramento de endereços de 64 linhas e 232
bytes de memória custará mais que um com 32 linhas e
os mesmos 232
bytes de memória. A possibilidade de expansão posterior não é gratuita.
O resultado dessa observação é que muitos projetistas de sistemas tendem a ser imediatistas, o que provoca
consequências desastrosas mais tarde. O BM PC original continha uma CPU 8088 e um barramento de endereços
de 20 bits, conforme mostra a Figura 3.37(a). Os 20 bits permitiam ao PC endereçar 1 MB de memória.
Figura 3.37 Crescimento de um barramento de enderec
os ao longo do tempo.
8088
(a)
80286
(b)
80386
(c)
Endereço de 20 bits
Controle
Endereço de 20 bits
Controle
Endereço de 4 bits
Controle
Endereço de 20 bits
Controle
Endereço de 4 bits
Controle
Endereço de 8 bits
Controle
Quando lançou seu próximo chip de CPU (o 80286), a ntel decidiu aumentar o espaço de endereços para 16
MB, por isso precisou adicionar quatro linhas de barramento (sem mexer nas 20 originais, por razões de compa-
tibilidade), como ilustrado na Figura 3.37(b). nfelizmente, mais linhas de controle tiveram de ser acrescentadas
para lidar com as novas linhas de endereço. Quando o 80386 foi lançado, oito linhas de endereço foram adiciona-
das, junto com ainda mais linhas de controle, como mostra a Figura 3.37(c). O projeto resultante (o barramento
ESA) é muito mais confuso do que seria se o barramento tivesse 32 linhas desde o início.
Não é apenas o número de linhas de endereço que tende a crescer com o tempo, mas também o número de
linhas de dados, porém, por uma razão diferente. Há dois modos de aumentar a largura de banda de dados de um
barramento: reduzir o tempo deste (mais transferências por segundo) ou aumentar sua largura de dados (mais
bits por transferência). Acelerar o barramento é possível, mas difícil, porque os sinais trafegam em linhas dife-
rentes com velocidades ligeiramente diferentes, um problema conhecido como atraso diferencial do barramento.
Quanto mais rápido o barramento, mais sério se torna o atraso diferencial.
Outro problema com a aceleração é que isso não será compatível. Placas antigas, projetadas para os barra-
mentos mais lentos, não funcionarão com o novo. nvalidar as placas antigas descontentará não somente seus
proprietários, mas também os fabricantes. Por conseguinte, a técnica que costuma ser adotada para melhorar
o desempenho é adicionar linhas de dados, de forma análoga à Figura 3.37. Todavia, como era de esperar, no
fim das contas esse crescimento incremental não leva a um projeto limpo. O BM PC e seus sucessores, por
exemplo, passaram de oito linhas de dados para 16 e em seguida para 32, conservando praticamente o mesmo
barramento.
Para contornar o problema de barramentos muito largos, às vezes os projetistas optam por um barramento
multiplexado. Nesse projeto, em vez de as linhas de endereços e dados serem separadas, há, por exemplo, 32 linhas
para endereços e dados juntos. No início de uma operação de barramento, as linhas são usadas para o endereço.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 151
Mais tarde, são usadas para dados. Para uma escrita na memória, por exemplo, isso significa que as linhas de
endereço devem ser estabelecidas e propagadas para a memória antes que os dados possam ser colocados no
barramento. Com linhas separadas, endereços e dados podem ser colocados juntos. Multiplexar as linhas reduz
a largura (e o custo) do barramento, mas resulta em um sistema mais lento. Quando tomam suas decisões, os
projetistas de barramento têm de pesar cuidadosamente todas essas opções.
3.4.4 Clock do barramento
Barramentos podem ser divididos em duas categorias distintas, dependendo de seu clock. Um barramento
síncrono tem uma linha comandada por um oscilador de cristal. O sinal nessa linha consiste em uma onda qua-
drada com uma frequência em geral entre 5 e 133 MHz. Todas as atividades do barramento tomam um número
inteiro desses ciclos denominados ciclos de barramento. O outro tipo de barramento, o barramento assíncrono,
não tem um clock mestre. Ciclos de barramento podem ter qualquer largura requerida e não são os mesmos entre
todos os pares de dispositivos. A seguir, estudaremos cada tipo de barramento.
Barramentos s
ncronos
Como exemplo do funcionamento de um barramento síncrono, considere o diagrama temporal da Figura
3.38(a). Nesse exemplo, usaremos um clock de 100 MHz, que dá um ciclo de barramento de 10 nanossegundos.
Embora isso possa parecer um tanto lento em comparação a velocidades de CPU de 3 GHz ou mais, poucos bar-
ramentos de PCs são muito mais rápidos. Por exemplo, o popular barramento PC normalmente funciona a 33 ou
66 MHz e o barramento PC- atualizado (porém agora extinto) funcionava a uma velocidade de até 133 MHz.
As razões por que os barramentos atuais são lentos já foram dadas: problemas técnicos de projeto, como atraso
diferencial de barramento e necessidade de compatibilidade.
Em nosso exemplo, admitiremos ainda que ler da memória leva 15 ns a partir do instante em que o endereço
está estável. Como veremos em breve, com esses parâmetros, ler uma palavra levará três ciclos de barramento. O
primeiro ciclo começa na borda ascendente de T1 e o terceiro termina na borda ascendente de T4, como mostra
a figura. Observe que nenhuma das bordas ascendentes ou descendentes foi desenhada na linha vertical porque
nenhum sinal elétrico pode trocar seu valor em tempo zero. Nesse exemplo, admitiremos que leva 1 ns para o
sinal mudar. As linhas de clock, address, data, mreq, rd e wait, estão todas representadas na mesma escala de
tempo.
O início de T1 é definido pela borda ascendente do clock. A meio caminho de T1 a CPU coloca o endereço da
palavra que ela quer nas linhas de endereço. Como o endereço não é um valor único, como o clock, não podemos
mostrá-lo como uma linha única na figura; em vez disso, ele é mostrado como duas linhas que se cruzam no ins-
tante em que o endereço muda. Além disso, a área sombreada antes do cruzamento indica que o valor nessa área
não é importante. Usando essa mesma convenção, vemos que o conteúdo das linhas de dados não é significativo
até uma boa porção de T3.
Depois que as linhas de endereço tiverem uma chance de se acomodar a seus novos valores, mreq e rd são
ativados. O primeiro indica que é a memória (e não um dispositivo de E/S) que está sendo acessada e o segun-
do é ativado (valor 0) para leituras e negado (valor 1) para escritas. Uma vez que a memória leva 15 ns após o
endereço estar estável (a meio caminho no primeiro ciclo de clock), ela não pode entregar os dados requisitados
durante T2. Para dizer à CPU que não os espere, a memória ativa a linha wait no início de T2. Essa ação irá inserir
estados de espera (ciclos extras de barramento) até que a memória conclua e desative wait. Em nosso exemplo,
foi inserido um estado de espera (T2) porque a memória é muito lenta. No início de T3, quando está certa de que
terá os dados durante o ciclo corrente, a memória nega wait.
Durante a primeira metade de T3, a memória coloca os dados nas linhas de dados. Na borda descendente de
T3, a CPU mostra a linha de dados, isto é, lê a linha, armazenando (latching) o valor em um registrador interno.
Após ter lido os dados, a CPU nega mreq e rd. Se for preciso, outro ciclo de memória pode começar na próxima
borda ascendente do clock. Essa sequência pode ser repetida indefinidamente.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
152
Na especificação temporal da Figura 3.38(b), esclarecemos melhor oito símbolos que aparecem no diagrama.
TAD, por exemplo, é o intervalo de tempo entre a borda ascendente do clock T1 e o estabelecimento das linhas de
endereço. Conforme a especificação de temporização, TAD ≤ 4 ns. sso significa que o fabricante da CPU garante
que durante qualquer ciclo de leitura a CPU entregará o endereço a ser lido dentro de 4 ns a partir do ponto
médio da borda ascendente de T1.
Figura 3.38 (a) Temporizac
a
o de leitura em um barramento s
ncrono. (b) Especificac
a
o de alguns tempos cr
ticos.
Tempo
(a)
TAD
TM
TDS
TMH
TRH
TDH
TRL
Φ
T1 T2 T3
MREQ
RD
WAIT
TML
ADDRESS
DATA
Ciclo de leitura
com 1 estado de espera
Endereço de memória a ser lido
Dados
Símbolo Parâmetro Mín. Máx. Unidade
TAD Atraso de saída do endereço 4 ns
TML Endereço estável antes de MREQ 2 ns
TM Atraso de MREQ desde a borda descendente de Φ em T1 3 ns
TRL Atraso de RD desde a borda descendente de Φ em T1 3 ns
TDS Tempo de ajuste dos dados antes da borda descendente de Φ 2 ns
TMH Atraso de MREQ desde a borda descendente de Φ em T3 3 ns
TRH Atraso de RD desde a borda descendente de Φ em T3 3 ns
TDH Tempo de sustentação dos dados desde a negação de RD 0 ns
(b)
As especificações de temporização também requerem que os dados estejam disponíveis nas linhas de dados
no mínimo TDS (2 nanossegundos) antes da borda descendente de T3 para lhes dar tempo para se acomodarem
antes que a CPU os leia. A combinação de restrições impostas a Tad e TDS significa que, na pior das hipóteses, a
memória terá somente 25 – 4 – 2 = 19 ns desde o instante em que o endereço aparece até o instante em que ela
deve produzir os dados. Como 10 ns é suficiente, até mesmo no pior caso, uma memória de 10 ns sempre pode
responder durante T3. Uma memória de 20 ns, entretanto, perderia o momento por pouco e teria de inserir um
segundo estado de espera e responder durante T4.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 153
A especificação de temporização garante ainda mais que o endereço será estabelecido pelo menos 2 nanos-
segundos antes de mreq ser ativado. Esse tempo pode ser importante se mreq comandar a seleção de chip no chip
de memória, porque algumas memórias requerem um tempo de estabelecimento de endereço antes da seleção
do chip. Claro que o projetista do sistema não deve escolher um chip de memória que necessite de um tempo de
estabelecimento de 3 ns.
As limitações impostas a TM e TRL significam que ambos, mreq e rd, serão ativados dentro de 3 ns a partir
da borda descendente T1 do clock. No pior caso, o chip de memória terá somente 10 + 10 – 3 – 2 = 15 ns após a
ativação de mreq e rd para levar seus dados até o barramento. Essa restrição é adicional ao (e independente do)
intervalo de 15 ns necessário após o endereço estar estável.
TMH e TRH informam quanto tempo leva para mreq e rd serem negados após a leitura dos dados. Por fim, TDH
informa por quanto tempo a memória deve sustentar os dados no barramento após a negação de rd. No que diz
respeito a nosso exemplo de CPU, a memória pode remover os dados do barramento tão logo rd tenha sido negado;
porém, em algumas CPUs modernas, os dados devem ser conservados estáveis durante um pouco mais de tempo.
Gostaríamos de destacar que a Figura 3.38 é uma versão muito simplificada das restrições reais de tempo. Na
realidade, sempre são especificados muitos mais tempos críticos. Ainda assim, ela nos dá uma boa ideia do modo
de funcionamento de um barramento síncrono.
Uma última coisa que vale a pena mencionar é que sinais de controle podem ser ativados baixos ou altos.
Cabe aos projetistas do barramento determinar o que é mais conveniente, mas a escolha é, em essência, arbitrária.
Podemos entendê-la como equivalente em hardware à decisão que o programador toma de representar blocos de
discos livres em um mapa de bits como 0s ou 1s.
Barramentos ass
ncronos
Embora seja fácil trabalhar com barramentos síncronos por causa de seus intervalos discretos de tempo, eles
também têm alguns problemas. Por exemplo, tudo funciona como múltiplos do clock do barramento. Ainda que
CPU e memória possam concluir uma transferência em 3,1 ciclos, elas terão de prolongar o ciclo até 4,0 porque
ciclos fracionários são proibidos.
Pior ainda, uma vez escolhido o ciclo do barramento e construídas placas de memória e E/S para ele, é difícil
aproveitar futuros avanços da tecnologia. Por exemplo, suponha que alguns anos após a construção do sistema da
Figura 3.38 sejam lançadas novas memórias com tempos de acesso de 8 ns em vez de 15 ns, que eliminam o estado
de espera e dão mais velocidade à máquina. Então, suponha que sejam lançadas memórias de 4 ns. Não haveria
nenhum ganho adicional de desempenho porque, com esse projeto, o tempo mínimo para uma leitura é dois ciclos.
Exprimindo esses fatos em termos um pouco diferentes, se um barramento síncrono tiver uma coleção hete-
rogênea de dispositivos, alguns rápidos, alguns lentos, ele tem de ser ajustado para o mais lento, e os mais rápidos
não podem usar todo o seu potencial.
Pode-se utilizar tecnologia mista passando para um barramento assíncrono, isto é, que não tenha um clock
mestre, como mostra a Figura 3.39. Em vez de vincular tudo ao clock, quando o mestre de barramento tiver ati-
vado o endereço, mreq, rd e tudo o mais que precisa, em seguida ele ativa um sinal especial que denominaremos
msyn (Master SYNchronization). Quando o escravo vê esse sinal, ele realiza o trabalho com a maior rapidez que
puder e, ao concluir essa fase, ativa ssyn (Slave SYNchronization).
Assim que o mestre perceber ssyn ativado, sabe que os dados estão disponíveis, portanto, ele os serializa e
então desativa as linhas de endereço, junto com mreq, rd e msyn. Quando o escravo percebe a negação de msyn,
sabe que o ciclo foi concluído, portanto, nega ssyn, e voltamos à situação original, com todos os sinais negados,
esperando pelo próximo mestre.
Diagramas temporais de barramentos assíncronos (e às vezes também os de barramentos síncronos) usam
setas para mostrar causa e efeito, como na Figura 3.39. A ativação de msyn faz com que as linhas de dados sejam
ativadas e também com que o escravo ative ssyn. A ativação de ssyn, por sua vez, causa a negação das linhas de
endereço, mreq, rd e msyn. Por fim, a negação de msyn causa a negação e ssyn, que conclui a leitura e retorna o
sistema a seu estado original.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
154
Figura 3.39 Operac
a
o de um barramento ass
ncrono.
ADDRESS
MREQ
RD
MSYN
DATA
SSYN
Dados
Endereço de memória a ser lido
Um conjunto de sinais que se interligam dessa maneira é denominado operação completa. A parte essencial
consiste em quatro eventos:
1. msyn é ativado.
2. ssyn é ativado em resposta a msyn.
3. msyn é negado em resposta a ssyn.
4. ssyn é negado em resposta à negação de msyn.
É preciso que fique claro que operações completas são independentes de temporização. Cada evento é causa-
do por um evento anterior e não por um pulso de clock. Se determinado par mestre-escravo for lento, não afetará,
de modo algum, um par mestre-escravo subsequente, que é muito mais rápido.
Agora, a vantagem de um barramento assíncrono já deve estar bem clara, mas a verdade é que a maioria
dos barramentos é síncrona. A razão é que é mais fácil construir um sistema síncrono. A CPU apenas ativa seus
sinais e a memória apenas reage. Não há realimentação (causa e efeito), mas, se os componentes foram escolhidos
adequadamente, tudo funcionará sem dependência. Além disso, há muito dinheiro investido na tecnologia do
barramento síncrono.
3.4.5 Arbitragem de barramento
Até aqui ficou subentendido que há somente um mestre de barramento, a CPU. Na realidade, chips de E/S
têm de se tornar mestres de barramento para ler e escrever na memória e também para causar interrupções.
Coprocessadores também podem precisar se tornar mestres de barramento. Então, surge a pergunta: “O que
acontece se dois ou mais dispositivos quiserem se tornar mestres de barramento ao mesmo tempo?” A resposta é
que é preciso algum mecanismo de arbitragem de barramento para evitar o caos.
Mecanismos de arbitragem podem ser centralizados ou descentralizados. Em primeiro lugar, vamos consi-
derar a arbitragem centralizada. Uma forma particularmente simples de arbitragem centralizada é mostrada na
Figura 3.40(a). Nesse esquema, um único árbitro de barramento determina quem entra em seguida. Muitas CPUs
contêm o árbitro no chip de CPU, mas às vezes é preciso um chip separado. O barramento contém uma única
linha de requisição OR cabeada que pode ser afirmada por um ou mais dispositivos a qualquer tempo. Não há
nenhum modo de o árbitro dizer quantos dispositivos requisitaram o barramento. As únicas categorias que ele
pode distinguir são algumas requisições e nenhuma requisição.
Quando o árbitro vê uma requisição de barramento, emite uma concessão que ativa a linha de concessão
de barramento. Essa linha está ligada a todos os dispositivos de E/S em série, como um cordão de lâmpadas de
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 155
árvore de Natal. Quando o dispositivo que está fisicamente mais próximo do árbitro vê a concessão, verifica para
confirmar se fez uma requisição. Caso positivo, toma o barramento, mas não passa a concessão adiante na linha.
Se não fez uma requisição, ele propaga a concessão até o próximo dispositivo na linha que se comporta da mesma
maneira, e assim por diante, até algum deles aceitar a concessão e tomar o barramento. Esse esquema é denomi-
nado encadeamento em série (daisy chaining). Ele tem a propriedade de designar prioridades aos dispositivos
dependendo da distância entre eles e o árbitro. O que estiver mais próximo vence.
Para contornar as prioridades implícitas baseadas na distância em relação ao árbitro, muitos barramentos têm
vários níveis de prioridade. Para cada nível de prioridade há uma linha de requisição e uma linha de concessão
de barramento. O barramento da Figura 3.40(b) tem dois níveis, 1 e 2 (barramentos reais costumam ter 4, 8 ou
16 níveis). Cada dispositivo está ligado a um dos níveis de requisição do barramento, sendo que os mais críticos
em relação ao tempo estão ligados aos níveis com prioridade mais alta. Na Figura 3.40(b), os dispositivos 1, 2 e
4 usam prioridade 1, enquanto os dispositivos 3 e 5 usam prioridade 2.
Se vários níveis de prioridade são requisitados ao mesmo tempo, o árbitro emite uma concessão somente ao
de prioridade mais alta. Entre os dispositivos da mesma prioridade, é usado o encadeamento em série. Na Figura
3.40(b), se ocorrer algum conflito, o dispositivo 2 vence o dispositivo 4, que vence o 3. O dispositivo 5 tem a
menor prioridade porque está no final da linha de encadeamento de menor prioridade.
Figura 3.40 (a) A
rbitro de barramento centralizado de um n
vel usando encadeamento em se
rie. (b) Mesmo a
rbitro, mas com dois n
veis.
Requisição de barramento nível 1
Requisição de barramento nível 2
Concessão de barramento nível 2
Concessão de barramento nível 1
(a)
(b)
1 2 3 4 5
1 2 3 4 5
Requisição de barramento
Árbitro
Concessão de
barramento
Concessão de
barramento pode ser
ou não propagada ao
longo da cadeia Dispositivos
de E/S
Árbitro
A propósito, tecnicamente não é necessário ligar a linha de concessão de barramento de nível 2 em série
passando pelos dispositivos 1 e 2, já que eles não podem fazer requisições nessa linha. Contudo, por conveniência
de execução, é mais fácil ligar todas as linhas de concessão passando por todos os dispositivos, em vez de fazer
ligações especiais que dependem da prioridade de dispositivo.
Alguns árbitros têm uma terceira linha que um dispositivo ativa quando aceita uma concessão e pega o barra-
mento. Tão logo tenha ativado essa linha de reconhecimento, as linhas de requisição e concessão podem ser nega-
das. O resultado é que outros dispositivos podem requisitar barramento enquanto o primeiro o estiver usando.
No instante em que a transferência for concluída, o próximo mestre de barramento já terá sido selecionado. Ele
pode começar logo que a linha de reconhecimento tenha sido negada, quando então pode ser iniciada a próxima
rodada de arbitragem. Esse esquema requer uma linha de barramento extra e mais lógica em cada dispositivo,
mas faz melhor uso de ciclos de barramento.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
156
Em sistemas em que a memória está no barramento principal, a CPU deve competir pelo barramento com
todos os dispositivos de E/S em praticamente todos os ciclos. Uma solução comum para essa situação é dar à
CPU a prioridade mais baixa, de modo que ela obtenha o barramento apenas quando ninguém mais o quiser.
Nesse caso, a ideia é que a CPU sempre pode esperar, mas os dispositivos de E/S muitas vezes precisam adqui-
rir logo o barramento ou então perdem os dados que chegam. Discos que giram a alta velocidade não podem
esperar. Em muitos sistemas modernos de computadores, esse problema é evitado ao se colocar a memória em
um barramento separado dos dispositivos de E/S de modo que estes não tenham de competir pelo acesso ao
barramento.
Também é possível haver arbitragem de barramento descentralizada. Por exemplo, um computador poderia
ter 16 linhas de requisição de barramento priorizadas. Quando um dispositivo quer usar o barramento, ele afirma
sua linha de requisição. Todos os dispositivos monitoram todas as linhas de requisição, de modo que, ao final
de cada ciclo de barramento, cada dispositivo sabe se foi o requisitante de prioridade mais alta e, portanto, se
tem permissão de usar o barramento durante o próximo ciclo. Comparado à arbitragem centralizada, o método
descentralizado requer mais linhas de barramento, mas evita o custo potencial do árbitro. Além disso, limita o
número de dispositivos ao número de linhas de requisição.
Outro tipo de arbitragem de barramento descentralizada, mostrado na Figura 3.41, usa apenas três linhas,
não importando quantos dispositivos estiverem presentes. A primeira é uma linha OR cabeada para requisitar
o barramento. A segunda é denominada busy e é ativada pelo mestre de barramento corrente. A terceira linha é
usada para arbitrar o barramento. Ela está ligada por encadeamento em série a todos os dispositivos. O início
dessa cadeia é ativado ligando-o a uma fonte de alimentação.
Figura 3.41 Arbitragem de barramento descentralizada.
V
1 2 3 4 5
CC
Requisição de barramento
Busy (ocupado)
Linha de
arbitragem Entrada Saída Entrada Saída Entrada Saída Entrada Saída Entrada Saída
Quando nenhum dispositivo quiser o barramento, a linha de arbitragem ativada é propagada por todos os
outros. Para adquirir o barramento, um dispositivo primeiro verifica para ver se o barramento está ocioso e se o
sinal de arbitragem que está recebendo, in (entrada), está ativado. Se in estiver negado, o dispositivo em ques-
tão não pode se tornar o mestre de barramento e o sinal out (saída) é negado. Entretanto, se in for ativado, o
dispositivo nega out, o que faz seu vizinho seguinte na cadeia ver in negado e negar seu próprio out. Daí, todos
os dispositivos depois dele na cadeia veem in negado e, por sua vez, negam out. Quando o processo terminar,
somente um dispositivo terá in ativado e out negado, e é ele que se torna o mestre de barramento, ativa busy e
out e inicia sua transferência.
Um pouco de raciocínio revelará que o dispositivo mais à esquerda que quiser o barramento o obtém. Assim,
esse esquema é similar à arbitragem original por encadeamento em série, com a exceção de não ter o árbitro. Por
isso é mais barato, mais rápido e não está sujeito a falhas do árbitro.
3.4.6 Operac
o
es de barramento
Até agora, discutimos apenas ciclos de barramento comuns, com um mestre (em geral, a CPU) lendo de um
escravo (em geral, a memória) ou escrevendo nele. Na verdade, existem vários outros tipos de ciclos de barra-
mento. Em seguida, vamos estudar alguns deles.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 157
Em geral, só uma palavra é transferida por vez. Contudo, quando é usado caching, é desejável buscar uma
linha inteira de cache (por exemplo, 8 palavras de 64 bits consecutivas) por vez. Transferências de blocos costu-
mam ser mais eficientes do que transferências individuais sucessivas. Quando uma leitura de bloco é iniciada, o
mestre de barramento informa ao escravo quantas palavras serão transferidas, por exemplo, colocando o núme-
ro de palavras nas linhas de dados durante T1. Em vez de retornar apenas uma palavra, o escravo entrega uma
durante cada ciclo até esgotar aquele número de palavras. A Figura 3.42 mostra uma versão modificada da Figura
3.38(a), mas agora com um sinal extra, block, que é ativado para indicar que foi requisitada uma transferência de
bloco. Nesse exemplo, uma leitura de bloco de 4 palavras demora 6 ciclos em vez de 12.
Figura 3.42 Transfere
ncia de bloco.
Φ
T1 T2 T3 T4 T5 T6 T7
ADDRESS
DATA
MREQ
RD
WAIT
BLOCK
Endereço de
memória a ser lido
Contador Dados Dados Dados Dados
Há também outros tipos de ciclos de barramento. Por exemplo, em um sistema multiprocessador com duas
ou mais CPUs no mesmo barramento, muitas vezes é necessário garantir que só uma CPU por vez use alguma
estrutura de dados crítica na memória. Um modo típico de organizar isso é ter uma variável na memória que é 0
quando nenhuma CPU estiver usando a estrutura de dados e 1 quando esta estiver em uso. Se uma CPU quiser
obter acesso à estrutura de dados, deve ler a variável e, se esta for 0, passá-la para 1. O problema é que, com um
pouco de má sorte, duas CPUs podem ler a variável em ciclos de barramento consecutivos. Se cada uma perceber
que a variável é 0, então cada uma passa a variável para 1 e acha que é a única CPU que está usando a estrutura
de dados. Essa sequência de eventos leva ao caos.
Para evitar essa situação, sistemas multiprocessadores costumam ter um ciclo de barramento especial ler-
-modificar-escrever que permite a qualquer CPU ler uma palavra da memória, inspecionar e modificar essa pala-
vra, e escrevê-la novamente na memória, tudo sem liberar o barramento. Esse tipo de ciclo evita que uma CPU
rival possa usar o barramento e assim interferir com a operação da primeira CPU.
Outro tipo importante de ciclo de barramento é o usado para manipular interrupções. Quando ordena que
um dispositivo de E/S faça algo, a CPU espera uma interrupção quando o trabalho for concluído. A sinalização
da interrupção requer o barramento.
Uma vez que vários dispositivos podem querer causar uma interrupção simultaneamente, os mesmos tipos
de problemas de arbitragem que tivemos nos ciclos de barramento comuns também estão presentes aqui. A
solução normal é atribuir prioridades a dispositivos e usar um árbitro centralizado para dar prioridade aos dis-
positivos mais críticos em relação ao tempo. Existem chips controladores de interrupção padronizados que são
muito usados. Em PCs baseados em processador ntel, o chipset incorpora um controlador de interrupção 8259A,
ilustrado na Figura 3.43.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
158
Figura 3.43 Utilizac
a
o do controlador de interrupc
a
o 8259A.
D0-D7
CS
A0
WR
INTA
RD
INT IR0
IR1
IR2
IR3
IR4
IR5
IR6
IR7
VCC
CPU
Controlador
de
interrupção
8259A
Clock
Teclado
Disco
Impressora
Até oito controladores de E/S 8259A podem ser conectados direto às oito entradas irx (nterrupt Request –
solicitação de interrupção) do 8259A. Quando qualquer um desses dispositivos quiser causar uma interrupção, ele
ativa sua linha de entrada. Quando uma ou mais entradas são acionadas, o 8259A ativa int (NTerrupt – interrup-
ção), que impulsiona diretamente o pino de interrupção na CPU. Quando a CPU puder manipular a interrupção,
ela devolve o pulso ao 8259A por inta (NTerrupt Acknowledge – reconhecimento de interrupção). Nesse ponto,
o 8259A deve especificar qual entrada causou interrupção passando o número daquela entrada para o barramento
de dados. Essa operação requer um ciclo de barramento especial. Então, o hardware da CPU usa esse número
para indexar em uma tabela de ponteiros, denominados vetores de interrupção, para achar o endereço do proce-
dimento a executar para atender à interrupção.
No interior do 8259A há diversos registradores que a CPU pode ler e escrever usando ciclos de barramento
comuns e os pinos rd (ReaD), wr (WRite), cs (Chip Select) e a0. Quando o software tiver tratado da interrupção e
estiver pronto para atender à seguinte, ele escreve um código especial em um dos registradores, que faz o 8259A
negar NT, a menos que haja outra interrupção pendente. Esses registradores também podem ser escritos para
colocar o 8259A em um de vários modos, mascarar um conjunto de interrupções e habilitar outras características.
Quando mais de oito dispositivos de E/S estiverem presentes, os 8259As podem funcionar em cascata. No
caso mais extremo, todas as oito entradas podem ser conectadas às saídas de mais oito 8259As, permitindo até 64
dispositivos de E/S em uma rede de interrupção de dois estágios. O hub controlador de E/S CH10 da ntel, um dos
chips no chipset Core i7, incorpora dois controladores de interrupção 8259A. sso dá ao CH10 15 interrupções
externas, uma a menos que as 16 interrupções nos dois controladores 8259A, pois uma das interrupções é usada
para a operação em cascata do segundo 8259A para o primeiro. O 8259A tem alguns pinos dedicados a essa ope-
ração em cascata, que omitimos por questão de simplicidade. Hoje, o “8259A” é, na realidade, parte de outro chip.
Embora não tenhamos nem de perto esgotado a questão do projeto de barramento, o material que apresenta-
mos até aqui deve oferecer fundamento suficiente para entender os aspectos essenciais do modo de funcionamen-
to de um barramento e da interação entre CPUs e barramentos. Agora, vamos passar do geral para o específico e
examinar alguns exemplos de CPUs reais e seus barramentos.
3.5 Exemplo de chips de CPUs
Nesta seção, vamos examinar com algum detalhe os chips ntel Core i7, T OMAP4430 e Atmel ATmega168
no nível de hardware.
3.5.1 O Intel Core i7
O Core i7 é um descendente direto da CPU 8088 usada no BM PC original. O primeiro Core i7 foi lançado
em novembro de 2008 como uma CPU de 731 milhões de transistores de quatro processadores que funcionava
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 159
em 3,2 GHz com uma largura de linha de 45 nanômetros. Largura da linha quer dizer a largura dos fios entre
transistores, assim como uma medida do tamanho dos próprios transistores. Quanto menor a largura da linha,
mais transistores podem caber no chip. No fundo, a lei de Moore se refere à capacidade de os engenheiros de
processo continuarem a reduzir as larguras das linhas. Para fins de comparação, os fios de cabelo humano ficam
na faixa de 20 mil a 100 mil nanômetros de diâmetro, sendo o cabelo loiro mais fino do que o preto.
A versão inicial da arquitetura Core i7 era baseada na arquitetura “Nahalem”; porém, as versões mais
novas são montadas sobre a arquitetura “Sandy Bridge” mais recente. A arquitetura nesse contexto representa
a organização interna da CPU, que costuma receber um codinome. Apesar de serem em geral pessoas sérias,
os arquitetos de computador às vezes aparecerão com codinomes muito inteligentes para seus projetos. Uma
arquitetura digna de nota foi a série K da AMD, projetada para quebrar a posição aparentemente invulnerável
da ntel no segmento de CPU para desktop. O codinome dos processadores da série K foi “Kryptonite”, uma
referência à única substância capaz de ferir o Super-homem, e um golpe inteligente na dominante ntel.
O novo Core i7 baseado na Sandy Bridge evoluiu para ter 1,16 bilhão de transistores e trabalha em veloci-
dades de até 3,5 GHz, com larguras de linha de 32 nanômetros. Embora o Core i7 esteja longe do 8088 com 29
mil transistores, ele é totalmente compatível com o 8088 e pode rodar sem modificação os programas binários do
8088 (sem falar também nos programas para todos os processadores intermediários).
Do ponto de vista de software, o Core i7 é uma máquina completa de 64 bits. Tem todas as mesmas carac-
terísticas SA de nível de usuário que os chips 80386, 80486, Pentium, Pentium , Pentium Pro, Pentium  e
Pentium 4, inclusive os mesmos registradores, as mesmas instruções e uma execução completa no chip do padrão
EEE 754 de ponto flutuante. Além disso, tem algumas novas instruções destinadas principalmente a operações
criptográficas.
O processador Core i7 é uma CPU multicore (de múltiplos núcleos), de modo que o substrato de silício
contém vários processadores. A CPU é vendida com um número variável de processadores, que vai de 2 a 6,
com outras configurações planejadas para o futuro próximo. Se os programadores escreverem um programa
paralelo, usando threads e locks, é possível obter ganhos significativos na velocidade do programa, explorando
o paralelismo nos múltiplos processadores. Além disso, as CPUs individuais são “hyperthreaded”, de modo que
várias threads de hardware podem estar ativas simultaneamente. O hyperthreading (normalmente denominado
“multithreading simultâneo” pelos arquitetos de computador) permite que latências muito curtas, como faltas
de cache, sejam toleradas com trocas de thread de hardware. O threading baseado no software só pode tolerar
latências muito longas, como faltas de página, devido às centenas de ciclos necessárias para executar as trocas de
threads baseadas em software.
Em sua parte interna, no nível da microarquitetura, o Core i7 é um projeto bastante capaz. Ele é baseado na
arquitetura de seus predecessores, o Core 2 e Core 2 Due. O processador Core i7 pode executar até quatro ins-
truções ao mesmo tempo, tornando-o uma máquina superescalar de largura 4. Examinaremos a microarquitetura
no Capítulo 4.
Todos os processadores Core i7 têm três níveis de cache. Cada processador em um processador Core i7 tem
uma cache de dados de nível 1 (L1) com 32 KB e uma de instruções de nível 1 com 32 KB. Cada núcleo também
tem sua própria cache de nível 2 (L2) com 256 KB. A cache de segundo nível é unificada, significando que pode
ter uma mistura de instruções e dados. Todos os núcleos compartilham uma só cache unificada de nível 3 (L3),
cujo tamanho varia de 4 a 15 MB, dependendo do modelo de processador. Ter três níveis de cache melhora sig-
nificativamente o desempenho do processador, mas com um grande custo na área de silício, pois as CPUs Core
i7 podem ter até 17 MB de cache total em um único substrato de silício.
isto que todos os chips Core i7 têm múltiplos processadores com caches de dados privadas, surge um pro-
blema quando uma CPU modifica uma palavra na cache privada que esteja contida na de outro processador. Se o
outro processador tentar ler aquela palavra da memória, obterá um valor ultrapassado, já que palavras de cache
modificadas não são escritas de imediato de volta na memória. Para manter a consistência da memória, cada CPU
em um sistema microprocessador escuta (snoops) o barramento de memória em busca de referências de palavras
que tenha em cache. Quando vê uma dessas referências, ela se apressa em fornecer os dados requisitados antes que
a memória tenha chance de fazê-lo. Estudaremos a escuta (snooping) no Capítulo 8.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
160
Dois barramentos externos principais são usados nos sistemas Core i7, ambos síncronos. Um barramento
de memória DDR3 é usado para acessar a DRAM de memória principal, e um barramento PC Express conecta o
processador a dispositivos de E/S. ersões avançadas do Core i7 incluem memória múltipla e barramentos PC
Express, e elas também incluem uma porta Quick Path nterconnect (QP). A porta QP conecta o processador
a uma interconexão multiprocessadora externa, permitindo a montagem de sistemas com mais de seis proces-
sadores. A porta QP envia e recebe requisições de coerência de cache, mais uma série de outras mensagens de
gerenciamento de multiprocessador, como interrupções interprocessador.
Um problema com o Core i7, bem como com a maioria das outras CPUs modernas do tipo desktop, é a energia
que consome e o calor que gera. Para impedir danos ao silício, o calor deve ser afastado do substrato do processador
logo após ser produzido. O Core i7 consome entre 17 e 150 watts, dependendo da frequência e do modelo. Por
consequência, a ntel está sempre buscando meios de controlar o calor produzido por seus chips de CPU. As
tecnologias de resfriamento e os dissipadores de calor são vitais para evitar que o silício se queime.
O Core i7 vem em um pacote LGA quadrado com 37,5 mm de borda. Ele contém 1.155 pinos na parte infe-
rior, dos quais 286 são para alimentação e 360 são aterramento, para reduzir o ruído. Os pinos são arrumados
mais ou menos como um quadrado de 40 × 40, com os 17 × 25 do meio faltando. Além disso, 20 outros pinos
estão faltando no perímetro em um padrão assimétrico, para impedir que o chip seja inserido incorretamente em
sua base. A disposição física dos pinos aparece na Figura 3.44.
Figura 3.44 Disposic
a
o f
sica dos pinos no Core i7.
O chip é equipado com uma placa de montagem para um dissipador distribuir o calor e um ventilador para
resfriá-lo. Para ter uma ideia do tamanho do problema da potência, ligue uma lâmpada incandescente de 150
watts, deixe-a aquecer e depois coloque suas mãos ao seu redor (mas não a toque). Essa quantidade de calor deve
ser dissipada continuamente por um processador Core i7 de última geração. Em consequência, quando o Core
i7 não tiver mais utilidade como uma CPU, ele sempre poderá ser usado como um fogareiro em acampamentos.
De acordo com as leis da física, qualquer coisa que emita muito calor deve absorver muita energia. Não é
interessante usar muita energia em um computador portátil com carga de bateria limitada porque a bateria se
esgota rapidamente. Para resolver essa questão, a ntel oferece um meio de pôr a CPU para dormir quando ela
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 161
estiver ociosa e de fazê-la cair em sono profundo quando é provável que fique adormecida durante algum tempo.
Há cinco estados oferecidos, que vão de totalmente ativa a sono profundo. Nos estados intermediários são habi-
litadas algumas funcionalidades (tal como escuta de cache e manipulação de interrupção), mas outras funções
são desativadas. Quando em estado de sono profundo, os valores de registradores são preservados, mas as caches são
esvaziadas e desligadas. Nesse estado, é preciso que haja um sinal de hardware para despertá-la. Ainda não sabe-
mos se um Core i7 pode sonhar quando está em sono profundo.
Pinagem lo
gica do Core i7
Os 1.155 pinos do Core i7 são usados para 447 sinais, 286 conexões de energia elétrica (em diversas volta-
gens diferentes), 360 terras e 62 reservados para uso futuro. Alguns dos sinais lógicos usam dois ou mais pinos
(tal como o endereço de memória requisitado), de modo que há somente 131 sinais diferentes. Uma pinagem
lógica um pouco simplificada é dada na Figura 3.45. No lado esquerdo da figura, há cinco grupos principais de
sinais de barramento; no lado direito, há diversos sinais variados.
Figura 3.45 Pinagem lo
gica do Core i7.
Diagnósticos
Monitoramento térmico
Gerenciamento de energia
Detecção de energia
Configuração
Diversos
18
124
124
80
16
21
286 360
4
10
7
24
12
Canal de memória
DDR #1
Canal de memória
DDR #2
Canal PCIe
Interface de mídia
direta
Interface de monitor
flexível
CPU do
Core i7
CK Energia Terra
amos examinar os sinais, começando com os do barramento. Os dois primeiros sinais são usados para a
interface com DRAM compatível com DDR3. Esse grupo oferece endereço, dados, controle e clock ao banco de
DRAMs. O Core i7 admite dois canais DRAM DDR3 independentes, rodando com um clock de barramento de 666
MHz que transfere nas duas bordas, para permitir 1.333 milhões de transações por segundo. A interface DDR3
tem 64 bits de largura, e assim, as duas interfaces DDR3 trabalham em sequência para dar aos programas com
muita utilização de memória até 20 gigabytes de dados a cada segundo.
O terceiro grupo do barramento é a interface PC Express, que é usada para conectar periféricos diretamente
à CPU Core i7. A interface PC Express é uma interface serial de alta velocidade, com cada enlace serial único
formando uma “via” de comunicação com os periféricos. O enlace do Core i7 é uma interface x16, significando
que pode utilizar 16 vias simultaneamente para uma largura de banda agregada de 16 GB/s. Apesar de ser um
canal serial, um rico conjunto de comandos trafega pelos enlaces PC Express, incluindo comandos de leituras
de dispositivo, escrita, interrupção e configuração.
O grupo seguinte é a Direct Media nterface (DM), que é usada para conectar a CPU do Core i7 ao seu chip-
set correspondente. A interface DM é semelhante à interface PC Express, embora trabalhe com cerca de metade
da velocidade, pois quatro vias podem fornecer apenas taxas de transferência de dados de até 2,5 GB por segundo.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
162
O chipset de uma CPU contém um rico conjunto de suporte para interface de periférico adicional, exigido para
sistemas de mais alto nível, com muitos dispositivos de E/S. O chipset do Core i7 é composto dos chips P67 e
CH10. O chip P67 é o canivete suíço dos chips, oferecendo interfaces SATA, USB, Audio, PCe e memória flash.
O chip CH10 oferece suporte para interface legada, incluindo uma interface PC e a funcionalidade de contro-
le de interrupção do 8259A. Além disso, o CH10 contém alguns outros circuitos, como clocks de tempo real,
temporizadores de eventos e controladores de acesso direto à memória (DMA). Ter chips como esses simplifica
bastante a construção de um PC completo.
O Core i7 pode ser configurado para usar interrupções do mesmo modo que o 8088 (para fins de compati-
bilidade) ou também pode usar um novo sistema de interrupção que utiliza um dispositivo denominado PIC
(dvanced Programmable Interrupt Controller  controlador de interrupção programável avançado).
O Core i7 pode funcionar em quaisquer de várias tensões predefinidas, mas tem de saber qual delas. Os sinais
de gerenciamento de energia são usados para seleção automática de tensão da fonte de alimentação, para informar
à CPU que a energia está estável e outros assuntos relacionados com a energia. O controle dos vários estados de
sono também é feito aqui, já que o sono acontece por razões de gerenciamento de energia.
A despeito de seu sofisticado gerenciamento de energia, o Core i7 pode ficar muito quente. Para proteger o
silício, cada processador Core i7 contém vários sensores de calor internos, que detectam quando o chip está para
superaquecer. O grupo de monitoramento térmico trata do gerenciamento térmico, permitindo que a CPU indi-
que a seu ambiente que está em risco de superaquecimento. Um dos pinos é ativado pela CPU caso a temperatura
atinja 130°C (266°F). Se uma CPU alguma vez atingir essa temperatura, provavelmente estará sonhando com sua
aposentadoria e posterior transformação em fogareiro de acampamento.
Até mesmo em temperaturas de fogareiro de acampamento você não precisa se preocupar com a segurança
do Core i7. Se os sensores internos detectarem que o processador está para superaquecer, ele iniciará o estrangu-
lamento térmico, uma técnica que logo reduz a geração de calor, usando o processador apenas a cada N-ésimo
ciclo de clock. Quanto maior o valor de N, mais o processador é estrangulado, e mais rápido ele se resfriará. É
claro que o custo desse estrangulamento é uma diminuição no desempenho do sistema. Antes da invenção do
estrangulamento térmico, as CPUs se queimavam se seu sistema de resfriamento falhasse. A evidência desses tem-
pos negros do gerenciamento térmico da CPU pode ser achada procurando-se por “exploding CPU” no YouTube.
O vídeo é falso, mas o problema não.
O sinal Clock fornece o clock do sistema ao processador, que internamente é usado para gerar uma variedade
de clocks com base em um múltiplo ou fração do clock do sistema. Sim, é possível gerar um múltiplo da frequência de
clock, usando um dispositivo muito inteligente, chamado de delay-locked loop, ou DLL.
O grupo Diagnósticos contém sinais para testar e depurar sistemas em conformidade com o padrão de testes
EEE 1149.1 JTAG (Joint Test Action Group). Finalmente, o grupo Diversos é uma miscelânea de outros sinais
que possuem diversas finalidades especiais.
Paralelismo no barramento de memo
ria do DDR3 do Core i7
CPUs modernas como o Core i7 colocam grandes demandas sobre as memórias DRAM. Os processadores
individuais podem criar requisições de acesso muito mais depressa do que uma DRAM lenta consegue produzir
valores, e esse problema é aumentado quando vários processadores estão fazendo requisições simultâneas. Para
evitar que as CPUs morram por falta de dados, é essencial conseguir o máximo de vazão possível da memória. Por
esse motivo, o barramento de memória DDR3 do Core i7 pode ser operado de uma forma paralela, com até quatro
transações de memória simultâneas ocorrendo ao mesmo tempo. imos o conceito de paralelismo (ou pipelining)
no Capítulo 2, no contexto de uma CPU em paralelo (ver Figura 2.4), mas as memórias também podem trabalhar
com paralelismo.
Para permitir o paralelismo, as requisições à memória do Core i7 têm três etapas:
1. A fase ACTATE da memória, que “abre” uma linha de memória DRAM, aprontando-a para acessos
subsequentes à memória.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 163
2. A fase READ ou WRTE da memória, na qual vários acessos podem ser feitos a palavras individuais
dentro da linha DRAM aberta ou a várias palavras sequenciais dentro da linha de DRAM atual, usando
um modo de rajada.
3. A fase PRECHARGE, que “fecha” a linha de memória DRAM atual e prepara a memória DRAM para o
próximo comando ACTATE.
O segredo do barramento de memória com paralelismo do Core i7 é que as DRAMs DDR3 são organizadas
com vários bancos dentro do chip de DRAM. Um banco é um bloco de memória DRAM, que pode ser acessa-
do em paralelo com outros bancos de memória DRAM, mesmo que estejam contidos no mesmo chip. Um chip
DRAM DDR3 típico terá até 8 bancos de DRAM. Porém, a especificação de interface DDR3 permite apenas até
quatro acessos simultâneos sobre um único canal DDR3. O diagrama de temporização da Figura 3.46 ilustra o
Core i7 fazendo 4 acessos à memória para três bancos de DRAM distintos. Os acessos são totalmente sobrepostos,
de modo que as leituras de DRAM ocorrem em paralelo dentro do chip de DRAM. Com setas no diagrama de
temporização, a figura mostra quais comandos levam a outras operações.
Figura 3.46 Requisic
o
es de memo
ria com paralelismo na interface DDR3 do Core i7.
0 1 2 3 4 5 6 7 8 9 10 11 12 13
Ciclo de barramento
CK
CMD
ADDR
DATA
ACT
banco 0
ACT
banco 1
READ
banco 0
READ
banco 1
ACT
banco 2
PCHRG
banco 0
READ
banco 2
ACT
banco 0
PCHRG
banco 1
READ
banco 0
PCHRG
banco 2
PCHRG
banco 0
linha
banco 0
linha
banco 1
col
banco 0
col
banco 1
linha
banco 2
col
banco 2
linha
banco 0
col
banco 0
dados
banco 0
dados
banco 1
dados
banco 0
dados
banco 2
Como vemos na Figura 3.46, a interface de memória DDR3 tem quatro caminhos de sinal principais: clock de
barramento (CK), comando de barramento (CMD), endereço (ADDR) e dados (DATA). O sinal CK de clock
de barramento orquestra toda a atividade deste. O comando de barramento CMD indica qual atividade é requi-
sitada da DRAM de conexão. O comando ACTATE especifica o endereço de linha de DRAM a ser aberta por
meio do sinal ADDR. Quando um READ é executado, o endereço de coluna da DRAM é dado por meio de sinais
ADDR, e a DRAM produz o valor de leitura após um tempo fixo sobre os sinais DATA. Por fim, o comando
PRECHARGE indica ao banco para pré-carregar por meio dos sinais ADDR. Para a finalidade do exemplo, o
comando ACTATE deverá preceder o primeiro READ para o mesmo banco por dois ciclos de barramento
DDR3, e os dados são produzidos um ciclo após o comando READ. Além disso, a operação PRECHARGE deverá
ocorrer pelo menos dois ciclos de barramento após a última operação READ para o mesmo banco de DRAM.
O paralelismo nas requisições de memória pode ser visto na sobreposição das requisições de READ para os
diferentes bancos de DRAM. Os dois primeiros acessos READ aos bancos 0 e 1 são completamente superpostos, pro-
duzindo resultados nos ciclos de barramento 3 e 4, respectivamente. O acesso ao banco 2 é em parte superposto ao
primeiro acesso do banco 1, e por fim a segunda leitura do banco 0 é parcialmente superposta ao acesso ao banco 2.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
164
ocê pode estar questionando como o Core i7 sabe quando os dados do comando READ retornarão e quando
ele pode fazer uma nova requisição à memória. A resposta é que ele sabe quando receber e iniciar requisições
porque modela totalmente as atividades internas de cada DRAM DDR3 conectada. Assim, ele antecipará o retorno
dos dados no ciclo correto e saberá evitar o início de uma operação de pré-carga antes que se passem dois ciclos
de sua última operação de leitura. O Core i7 pode antecipar todas essas atividades porque a interface de memória
DDR3 é uma interface de memória síncrona. Assim, todas as atividades usam um número bem conhecido de
ciclos de barramento DDR3. Mesmo com todo esse conhecimento, a criação de uma interface de memória DDR3
com paralelismo completo e com alto desempenho é uma tarefa longe de ser trivial, exigindo muitos temporiza-
dores internos e detectores de conflito para realizar o tratamento eficaz da requisição de DRAM.
3.5.2 O sistema-em-um-chip Texas Instruments OMAP4430
Como nosso segundo exemplo de um chip de CPU, examinaremos agora o sistema-em-um-chip Texas
nstruments (T) OMAP4430. O OMAP4430 realiza o conjunto de instruções ARM e é voltado para aplicações
móveis e embutidas, como smartphones, tablets e dispositivos da nternet. Com um nome apropriado, um
sistema-em-um-chip incorpora uma grande variedade de dispositivos, de modo que, combinado com periféricos
físicos (tela sensível ao toque, memória flash etc.), ele executa um dispositivo de computação completo.
O sistema OMAP4430 inclui dois núcleos ARM A9, aceleradores adicionais e uma grande gama de inter-
faces periféricas. A organização interna do OMAP4430 aparece na Figura 3.47. Os núcleos ARM A9 são micro-
arquiteturas superescalares de largura 2. Além disso, existem mais três processadores aceleradores no substrato
OMAP4430: o processador gráfico POWERR SG540, um processador de sinal de imagem (SP) e um processa-
dor de vídeo A3. O SG540 oferece uma renderização 3D programável eficaz, semelhante às GPUs encontradas
em PCs desktop, apesar de menores e mais lentas. O SP é um processador programável projetado para manipula-
ção eficiente da imagem, para o tipo de operações que seriam exigidas em uma câmera digital avançada. O A3
executa codificação e decodificação eficientes de vídeo, com desempenho suficiente para dar suporte a aplicações
3D, como as encontradas em consoles de jogos portáteis. Há também no sistema OMAP4430 uma gama de inter-
faces periféricas, incluindo uma tela sensível ao toque e controladores de teclado, DRAM e interfaces flash, USB
e HDM. A Texas nstruments detalhou um roteiro para a série OMAP de CPUs. Projetos futuros terão mais de
tudo – mais núcleos ARM, mais GPUs e mais periféricos diversos.
Figura 3.47 Organizac
a
o interna do sistema-em-um-chip OMAP4430.
SDRC
IVA-HD
1080P
256KB SL2
mini64
466MHz
32KB L1
128KB L2
back-end de áudio LP L3
C2C
EMIF1
LPDDR2
(400MHz)
EMIF0
LPDDR2
(400MHz)
L3 RAM
no chip
48KB
DAP
Debug
& trace
MMCSD
(w/DMA)
8-bit DDR
Crypto
DMA
AES/SHA
Periféricos
L4
Per / emu / core / ABE
Power
Reset
Clocks
Manager
GPMC
NAND/NOR
externo
IVA3
DMM
Segundo
canal
LPDDR2
LPDDR2
NAND/NOR
cJTAG
STP
ETM
8-bit
HS-MMC
(x)
4-bit
HS-MMC
(x)
12C
(x)
UART
(x)
SPI
(x)
McBS
(x)
Slimbus
GPIOs
(max)
RESET,
CLOCKS,
POWER
CTRLS
Modem ou
acelerador
externo
Falante
E/S
Mic
A
e
D
E/S
PMIC
E/S
IRQs
Ducati
200Mhz
Imagem
Câmera
E/S
Requisição
de
DMA
USB2.0
OTG
USB2.0
HDMI
TV
PAL/NTSC
Display
múltiplo
E/S
C2C
Acelerador de
segurança
ARMv7
MPU
32KB/32KB L1
1MB L2
64KB.RAM
128KB ROM
SGX540
2D/3D
C2C
200MHz
(DDR)
DSS
Display
(DSI/HDMI)
SDMA SIMCOP
3-port
USB-HS
Host
UNIPRO
Extensões
HSI
ISP5
HSI
USB-HS
Interconexão de alta largura de banda com suporte de memória multicanal
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 165
O sistema OMAP4430 foi lançado no início de 2011 com dois núcleos ARM A9 rodando a 1 GHz usando
uma implementação de silício de 45 nanômetros. Um aspecto chave do projeto do OMAP4430 é que ele realiza
quantidades significativas de cálculo com muito pouca potência, pois é visado para aplicações móveis, alimenta-
das por uma bateria. Em tais aplicações, quanto mais eficiente for a operação do projeto, mais tempo o usuário
poderá ficar sem carregar a bateria.
Os muitos processadores do OMAP4430 são incorporados para dar suporte à missão de operação com baixa
potência. O processador gráfico, SP, e o A3 são todos aceleradores programáveis que fornecem capacidades de
cálculo eficientes com significativamente menos energia em comparação com as mesmas tarefas sendo executadas
apenas nas CPUs ARM A9. Totalmente alimentado, o sistema MAP4430 consome apenas 600 mW de potência.
Em comparação com o Core i7 avançado, o OMAP4430 usa cerca de 1/250 de sua potência. O OMAP4430 tam-
bém executa um modo de sono muito eficaz; quando todos os componentes estão dormindo, o projeto consome
somente 100 µW. Modos de sono eficientes são fundamentais para aplicações móveis com longos períodos de
tempo de standby, como um telefone celular. Quanto menos energia usada no modo de sono, mais tempo o tele-
fone celular durará no modo standby.
Para reduzir ainda mais as demandas de potência do OMAP4430, o projeto incorpora uma série de facilida-
des de gerenciamento de energia, incluindo a escalada dinâmica de tensão e o chaveamento de energia. A escala-
da dinâmica de tensão permite que os componentes sejam executados mais devagar em uma tensão inferior, o que
reduz bastante os requisitos de potência. Se você não precisa da velocidade de computação mais ardente da CPU,
a tensão do projeto pode ser reduzida para que a CPU trabalhe em uma velocidade mais lenta e muita energia
será economizada. O chaveamento de energia é uma técnica de gerenciamento ainda mais agressiva, na qual um
componente é desligado por completo quando não estiver em uso, eliminando assim seu consumo de energia.
Por exemplo, em uma aplicação de tablet, se o usuário não estiver assistindo a um filme, o processador de vídeo
A3 é completamente desligado e não consome energia. Por outro lado, quando o usuário está assistindo a um
filme, o processador de vídeo A3 trabalha ao máximo em suas tarefas de decodificação de vídeo, enquanto as
duas CPUs ARM A9 estão dormindo.
Apesar de sua tendência para uma operação com economia de energia, os núcleos ARM A9 utilizam uma
microarquitetura bastante capaz. Eles podem decodificar e executar até duas instruções a cada ciclo. Conforme
aprenderemos no Capítulo 4, essa taxa de execução representa a vazão máxima da microarquitetura. Mas não
espere que ela execute suas muitas instruções a cada ciclo. Em vez disso, pense nessa taxa como o desempenho
máximo garantido pelo fabricante, um nível que o processador nunca excederá, não importa o que aconteça. Em
muitos ciclos, menos de duas instruções serão executadas devido aos milhares de “hazards” (acasos) que podem
adiar as instruções, levando a uma vazão de execução mais baixa. Para resolver muitos desses limitadores de
vazão, o ARM A9 incorpora um poderoso previsor de desvio, escalonamento de instruções fora de ordem e um
sistema de memória altamente otimizado.
O sistema de memória do OMAP4430 tem duas caches L1 internas principais para cada processador ARM
A9: uma de 32 KB para instruções e uma de 32 KB para dados. Assim como o Core i7, ele também usa uma
cache nível 2 (L2) no chip, mas, diferente do Core i7, ela é uma memória de 1 MB relativamente pequena em
tamanho, sendo compartilhada por ambos os núcleos ARM A9. As caches são alimentadas com canais de DRAM
duais LPDDR2 de baixa potência. LPDDR2 é derivada do padrão de interface de memória DDR2, porém alterada
para exigir menos fios e operar em tensões mais eficientes em termos de potência. Além disso, o controlador de
memória incorpora uma série de otimizações de acesso à memória, como a pré-busca de memória ladrilhada e o
suporte para rotação na memória.
amos discutir caching em detalhes no Capítulo 4, mas é bom dizer algumas palavras sobre ela aqui. Toda
memória principal é dividida em linhas (blocos) de cache de 32 bytes. As 1.024 linhas de instrução mais usadas
e as 1.024 linhas de dados mais usadas estão na cache de nível 1. Linhas de cache que são muito usadas mas
não cabem na de nível 1 são mantidas na de nível 2. Essa cache contém linhas de dados e linhas de instrução de
ambas as CPUs ARM A9 misturadas aleatoriamente. A cache de nível 2 contém as 32.768 linhas acessadas mais
recentemente na memória principal.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
166
Quando há uma ausência na cache de nível 1, a CPU envia o identificador da linha que está procurando
(endereço de tag) para a cache de nível 2. A resposta (dados de tag) informa à CPU se a linha está ou não na cache
de nível 2 e, se estiver, informa também o estado em que esta se encontra. Se a linha estiver na cache, a CPU vai
pegá-la. Para obter um valor da cache de nível 2, são necessários 19 ciclos. Esse é um longo tempo para esperar os
dados, de modo que programadores inteligentes otimizarão seus programas para usar menos dados, aumentando
a probabilidade de achar os dados na cache rápida de nível 1.
Se a linha de cache não estiver na cache de nível 2, ela deve ser buscada da memória principal por meio da
interface de memória LPDDR2. A interface LPDDR2 do OMAP4430 é executada no chip de modo que a DRAM
LPDDR2 possa ser conectada diretamente ao OMAP4430. Para acessar a memória, a CPU primeiro deve enviar
a parte superior do endereço da DRAM ao chip de DRAM, usando as 13 linhas de endereço. Essa operação, cha-
mada ACTIVATE, carrega uma linha inteira de memória da DRAM para um buffer de linha. Depois disso, a CPU
pode emitir vários comandos read ou write, enviando o restante do endereço nas mesmas 13 linhas de endereço
e enviando (ou recebendo) os dados para a operação nas 32 linhas de dados.
Enquanto espera os resultados, a CPU pode perfeitamente continuar executando outro trabalho. Por exem-
plo, uma ausência na cache durante a busca antecipada de uma instrução não inibe a execução de uma ou mais
instruções já buscadas, cada uma das quais pode se referir a dados que não estão em quaisquer das caches. Assim,
várias transações com as mesmas interfaces LPDDR2 podem estar pendentes ao mesmo tempo, até para o mesmo
processador. Cabe ao controlador de memória monitorar tudo isso e fazer requisições de memória propriamente
ditas na ordem mais eficiente.
Quando os dados por fim chegam da memória, podem vir em 4 bytes por vez. Uma operação de memória pode
utilizar uma leitura ou escrita no modo rajada, permitindo que vários endereços contíguos dentro da mesma linha
da DRAM sejam lidos ou escritos. Esse modo é particularmente eficaz para ler ou escrever blocos de cache. Apenas
por registro, a descrição do OMAP4430 dada aqui, como a do Core i7 antes dele, foi bastante simplificada, mas a
essência de sua operação foi descrita.
O OMAP4430 vem em uma matriz em grade de bola (PBGA) de 547 pinos, conforme mostra a Figura 3.48.
Uma matriz em grade de bola é semelhante a uma matriz de grade de terra, exceto que as conexões no chip são
pequenas bolas de metal, em vez de plataformas quadradas usadas na LGA. Os dois pacotes não são compatíveis,
oferecendo mais evidência de que você não pode encaixar uma ponta quadrada em um furo redondo. O pacote
do OMAP4430 consiste em uma matriz retangular de 28 × 26 bolas, com os dois anéis de bolas mais internos
faltando, e mais duas meias linhas e colunas assimétricas de bolas faltando, para impedir que o chip seja inserido
incorretamente no soquete BGA.
Figura 3.48 A pinagem sistema-em-um-chip OMAP4430.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 167
É difícil comparar um chip CSC (como o Core i7) e um chip RSC (como o OMAP4430) apenas com
base na velocidade do clock. Por exemplo, os dois núcleos ARM A9 no OMAP4430 têm uma velocidade
máxima de execução de quatro instruções por ciclo de clock, dando-lhe quase a mesma taxa de execução dos
processadores superescalares de largura 4 do Core i7. Entretanto, o Core i7 alcança execução de programa
mais rápida, pois tem até seis processadores rodando com uma velocidade de clock 3,5 vezes mais rápida
(3,5 GHz) que o OMAP4430. O OMAP4430 pode parecer uma tartaruga correndo ao lado da lebre do Core
i7, mas a tartaruga usa muito menos potência, e pode terminar primeiro, ainda mais se a bateria da lebre
não for muito grande.
3.5.3 O microcontrolador Atmel ATmega168
Tanto o Core i7 quanto a OMAP4430 são exemplos de CPUs de alto desempenho projetadas para construir
dispositivos de computação altamente eficazes, com o Core i7 voltado para aplicações de desktop enquanto o
OMAP4430 é voltado para aplicações móveis. Quando pensam em computadores, são esses os tipos de sistemas
que muitas pessoas têm em mente. Entretanto, existe todo outro universo de computadores que na verdade é
muito maior: sistemas embutidos. Nesta seção, vamos examinar brevemente esse outro universo.
Talvez não seja um grande exagero dizer que todo equipamento elétrico que custe mais de 100 dólares tem
um computador dentro dele. Hoje, é certo que televisores, telefones celulares, agendas eletrônicas, fornos de
micro-ondas, filmadoras, aparelhos de DD, impressoras a laser, alarmes antifurto, aparelhos de surdez, jogos
eletrônicos e outros incontáveis dispositivos são todos controlados por computador. Os computadores que estão
dentro desses aparelhos costumam ser otimizados para baixo preço e não para alto desempenho, o que provoca
compromissos diferentes dos feitos para CPUs de tecnologia avançada que estudamos até aqui.
Como mencionamos no Capítulo 1, o Atmel ATmega168 provavelmente é o microcontrolador mais popular
em uso hoje, em grande parte por causa de seu custo muito baixo (cerca de 1 dólar). Como veremos em breve, ele
também é um chip versátil, portanto, fazer interface com ele é algo simples e barato. Agora, vamos examinar esse
chip, cuja pinagem física é mostrada na Figura 3.49.
Figura 3.49 Pinagem f
sica do ATmega168.
PC5
PC4
PC3
PC2
PC1
PC0
GND
AREF
AVCC
PB4
PB3
PB2
PB1
PB5
28
27
26
25
24
23
22
21
20
19
18
17
16
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
PC6
PD0
PD1
PD2
PD3
PD4
VCC
GND
PB6
PB7
PD5
PD6
PD7
PB0
Como podemos ver na figura, o ATmega168 normalmente vem em um pacote padrão de 28 pinos, embo-
ra haja outros pacotes disponíveis. À primeira vista, você talvez tenha notado que a pinagem nesse chip é um
pouco estranha em comparação com os dois projetos anteriores que examinamos. Em particular, esse chip não
tem linhas de endereço e dados. sso porque não foi projetado para ser conectado à memória, só a dispositivos.
Toda a memória, SRAM e flash, está contida dentro do processador, evitando a necessidade de quaisquer pinos
de endereço e dados, como mostra a Figura 3.50.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
168
Figura 3.50 Arquitetura interna e pinagem lo
gica do ATmega168.
2
6
GND
VCC
BARRAMENTO
DE
DADOS Temporizador
watchdog
Oscilador
watchdog
Circuitos
osciladores/
geração de
clock
EEPROM
Supervisão
de energia
POR/BOD &
RESET
Flash
debugWIRE
Lógica de
programa
SRAM
CPU
T/C 0 de
8 bits
T/C 1 de
16 bits
Conv. A/D
T/C 2 de
8 bits
Comp.
analógico
Lacuna de
banda interna
PORTA D (8) PORTA B (8) PORTA C (7)
USART 0 SPI TWI
AVCC
AREF
GND
RESET
PD[0..7] PB[0..7] PC[0..6] ADC[6..7]
XTAL[1..2]
Em vez de pinos de endereço e dados, o ATmega168 tem 27 portas de E/S digitais, 8 linhas na porta B e D,
e 7 linhas na porta C. Essas linhas de E/S digitais são projetadas para serem conectadas aos periféricos de E/S, e
cada uma pode ser configurada internamente pelo software de partida para ser uma entrada ou uma saída. Por
exemplo, quando usada em um forno de micro-ondas, uma linha de E/S digital seria uma entrada do sensor de
“porta aberta”. Outra linha de E/S digital seria uma saída usada para ligar e desligar o gerador do micro-ondas. O
software no ATmega168 verificaria se a porta estava fechada antes de ligar o gerador do micro-ondas. Se a porta
de repente for aberta, o software deverá cortar a energia. Na prática, as interconexões de hardware também estão
sempre presentes.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 169
Como opção, seis das entradas da porta C podem ser configuradas para serem E/S analógica. Pinos de E/S
analógica podem ler o nível de tensão de uma entrada ou definir o nível de tensão de uma saída. Estendendo
nosso exemplo de forno de micro-ondas, alguns aparelhos têm um sensor que permite ao usuário aquecer
o alimento até determinada temperatura. O sensor de temperatura seria conectado a uma entrada de porta
C, e o software poderia ler a tensão do sensor e depois convertê-la em uma temperatura usando uma função de
tradução específica do sensor. Os pinos restantes no ATmega168 são a entrada de tensão (vcc), dois pinos de terra
(gnd) e dois pinos para configurar os circuitos de E/S analógica (aref, avcc).
A arquitetura interna do ATmega168, como a do OMAP4430, é um sistema-em-um-chip com uma rica
matriz de dispositivos internos e memória. O ATmega168 vem com até 16 KB de memória flash interna, para
armazenamento de informações não voláteis que mudam com pouca frequência, como instruções de programa.
Ele também inclui até 1 KB de EEPROM, a memória não volátil que pode ser gravada pelo software. A EEPROM
guarda dados de configuração do sistema. De novo, usando nosso exemplo de micro-ondas, a EEPROM armaze-
naria um bit indicando se o micro-ondas mostrará a hora em formato de 12 ou 24 horas. O ATmega168 também
incorpora até 1 KB de SRAM interna, onde o software pode armazenar variáveis temporárias.
O processador interno roda o conjunto de instruções AR, que é composto de 131 instruções, cada uma
com 16 bits de extensão. O processador tem 8 bits, o que significa que opera sobre valores de dados de 8
bits, e internamente seus registradores possuem um tamanho de 8 bits. O conjunto de instruções incorpora
instruções especiais que permitem ao processador de 8 bits operar de modo eficiente sobre tipos de dados
maiores. Por exemplo, para realizar adições de 16 bits ou maiores, o processador fornece a instrução “add-
-with-carry” (somar com vai-um), que soma dois valores e mais o “vai-um” da adição anterior. Os outros
componentes internos englobam o clock em tempo real e uma variedade de lógica de interface, incluindo
suporte para enlaces seriais, enlaces PWM (pulse-width-modulated – modulado por largura de pulso), enlaces
2C (barramento nter-C) e controladores analógico e digital.
3.6 Exemplos de barramentos
Barramentos são a cola que mantém a integridade dos sistemas de computadores. Nesta seção, examinaremos
minuciosamente alguns barramentos populares: o PC e o USB (Universal Serial Bus – barramento serial univer-
sal). O PC é o principal barramento de E/S usado hoje em dia nos PCs. Ele pode ter duas formas, o barramento
PC mais antigo, e o novo e muito mais rápido barramento PC Express (PCe). O Universal Serial Bus é um
barramento de E/S cada vez mais popular para periféricos de baixa velocidade, como mouses e teclados. Uma
segunda e terceira versões do barramento USB rodam com velocidades muito mais altas. Nas próximas seções,
veremos esses barramentos um por vez, para ver como eles funcionam.
3.6.1 O barramento PCI
No BM PC original, a maioria das aplicações era baseada em texto. De modo gradual, com a introdução do
Windows, pouco a pouco começaram a ser usadas as interfaces gráficas de usuário. Nenhuma dessas aplicações
exigia demais do barramento SA. Contudo, com o passar do tempo, quando muitas aplicações, em especial jogos
em multimídia, começaram a usar computadores para exibir vídeo em tela cheia e com movimento completo, a
situação mudou radicalmente.
amos fazer um cálculo simples. Considere um vídeo colorido de 1.024 × 768 com 3 bytes/pixel. Um
quadro contém 2,25 MB de dados. Para um movimento suave, são necessárias ao menos 30 telas por segundo
para uma taxa de dados de 67,5 MB por segundo. Na verdade, é pior do que isso, pois para apresentar um
vídeo a partir de um disco rígido, CD-ROM ou DD, os dados devem passar do drive de disco para o barra-
mento e ir até a memória. Então, para a apresentação, os dados devem novamente percorrer o barramento até
o adaptador gráfico. Portanto, precisamos de uma largura de banda de barramento de 135 MB por segundo
só para o vídeo, sem contar a largura de banda de que a CPU e outros dispositivos precisam.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
170
O predecessor do barramento PC, o SA, funcionava à taxa máxima de 8,33 MHz e podia transferir 2 bytes
por ciclo para uma largura de banda máxima de 16,7 MB/s. O barramento SA avançado, denominado ESA, podia
movimentar 4 bytes por ciclo, para alcançar 33,3 MB/s. Claro que nenhuma dessas taxas sequer chegava perto do
que era necessário para apresentação de vídeo completo em tela.
Com o vídeo de HD completo moderno, a situação é ainda pior. sso exige 1.920 × 1.080 quadros a 30 qua-
dros/segundo para uma taxa de dados de 155 MB/s (ou 310 MB/s se os dados tiverem que atravessar o barramento
duas vezes). É claro que o barramento ESA sequer chegar perto de tratar disso.
Em 1990, a ntel percebeu o que estava para acontecer e desenvolveu um novo barramento com uma
largura de banda muito mais alta do que a do próprio barramento ESA. Foi denominado barramento PCI
(Peripheral Component Interconnect Bus  barramento de interconexão de componente periférico).
Para incentivar sua utilização, a ntel patenteou o PC e então passou todas as patentes para domínio
público, de modo que qualquer empresa podia construir periféricos para esse barramento sem ter de pagar
royalties. Ela também organizou um consórcio de empresas, o PC Special nterest Group, para gerenciar
o futuro desse barramento. O resultado foi que o PC alcançou enorme popularidade. Praticamente todos
os computadores com chips ntel a partir do Pentium têm barramento PC, e muitos outros computadores
também. Esse barramento é apresentado com todos os detalhes tétricos em Shanley e Anderson (1999) e
Solari e Willse (2004).
O barramento PC original transferia 32 bits por ciclo e funcionava em 33 MHz (tempo de ciclo de 30
ns) para uma largura de banda total de 133 MB/s. Em 1993, foi lançado o PC 2.0 e em 1995 saiu o PC
2.1. O PC 2.2 tem características para computadores portáteis (principalmente para economizar energia da
bateria). O barramento PC funciona em até 66 MHz e pode manipular transferências de 64 bits para uma
largura de banda total de 528 MB/s. Com esse tipo de capacidade, o vídeo de tela inteira e movimento total
é viável (admitindo que o disco e o resto do sistema estejam à altura do serviço). Seja como for, o PC não
será o gargalo.
Mesmo que 528 MB/s pareça muito rápido, ainda há dois problemas. Primeiro, não era muito bom para um
barramento de memória. Segundo, não era compatível com todas aquelas antigas placas SA que havia por aí. A
solução imaginada pela ntel foi projetar computadores com três ou mais barramentos, conforme mostra a Figura
3.51. Nessa figura, vemos que a CPU pode se comunicar com a memória principal por um barramento de memó-
ria especial, e que um barramento SA pode ser conectado ao PC. Esse arranjo atendia a todos os requisitos e,
por consequência, foi amplamente usado na década de 1990.
Dois componentes fundamentais dessa arquitetura são os dois chips de pontes, fabricados pela ntel – daí
seu interesse em todo esse projeto. A ponte PC conecta a CPU, a memória e o barramento PC. A ponte SA
conecta o barramento PC ao SA e também suporta um ou dois discos DE. Quase todos os sistemas PC usando
essa arquitetura vêm com um ou mais encaixes PC livres para acrescentar novos periféricos de alta velocidade e
um ou mais encaixes SA para acrescentar periféricos de baixa velocidade.
A grande vantagem do arranjo da Figura 3.51 é que a CPU tem uma largura de banda extremamente alta para
a memória usando um barramento de memória proprietário; o PC oferece alta largura de banda para periféricos
rápidos, como discos SCS, adaptadores gráficos etc.; e as antigas placas SA ainda podem ser usadas. A caixa USB
na figura se refere ao Universal Serial Bus, que será discutido mais adiante neste capítulo.
Seria bom se houvesse apenas um tipo de placa PC. Porém, não é esse o caso. Há opções para tensão, lar-
gura e temporização. Computadores mais antigos usam em geral 5 volts e os mais novos tendem a usar 3,3 volts,
portanto, o barramento PC suporta ambos. Os conectores são os mesmos, exceto por dois pedacinhos de plástico
que estão lá para impedir que as pessoas insiram uma placa de 5 volts em um barramento PC de 3,3 volts ou
vice-versa. Felizmente, existem placas universais que suportam ambas as tensões e podem ser ligadas a quaisquer
dos tipos de encaixe. Além da opção de tensão, as placas também têm versões de 32 bits e 64 bits. As placas de 32
bits têm 120 pinos; as de 64 bits têm os mesmos 120 pinos mais 64 pinos adicionais. Um sistema de barramento
PC que suporta placas de 64 bits também pode aceitar placas de 32 bits, mas o inverso não é verdade. Por fim,
barramentos e placas PC podem funcionar em 33 MHz ou 66 MHz. A opção é feita ligando um pino à fonte de
energia ou ao fio terra. Os conectores são idênticos para ambas as velocidades.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 171
Figura 3.51 Arquitetura de um dos primeiros sistemas Pentium. Os barramentos representados por linhas mais largas te
m mais largura de
banda do que os representados por linhas mais finas, mas a figura na
o esta
 em escala.
Barramento de cache Barramento local Barramento de memória
Cache de
nível 2 CPU Ponte PCI
Memória
principal
Barramento PCI
SCSI USB
Mouse Teclado
Ponte ISA
Disco
IDE
Adaptador
gráfico
Mo-
nitor
Encaixe PCI
disponível
Barramento ISA
Modem
Placa
de som
Impres-
sora
Encaixe ISA
disponível
No final da década de 1990, quase todos concordavam que o barramento SA estava morto, portanto, os novos
projetos o excluíram. Contudo, nessa mesma época a resolução de monitores tinha aumentado, em alguns casos
para 1.600 × 1.200, e a demanda por vídeo de tela inteira e movimento total também cresceu, em especial no con-
texto de jogos de alto grau de interação, portanto, a ntel acrescentou mais um outro barramento só para comandar
a placa gráfica. Esse barramento foi denominado barramento GP (ccelerated Graphics Port bus  barramento
de porta gráfica acelerada). A versão inicial, AGP 1.0, funcionava a 264 MB/s, o que foi definido como 1x. Embora
mais lento que o barramento PC, foi dedicado a comandar a placa gráfica. Com o passar dos anos, saíram novas
versões, com AGP 3.0 funcionando a 2,1 GB/s (8x). Hoje, até mesmo o barramento AGP 3.0 de alto desempenho
foi substituído por outros ainda mais rápidos, em particular, o PC Express, que pode bombear incríveis 16 GB/s de
dados por enlaces de barramento serial de alta velocidade. Um sistema Core i7 moderno é ilustrado na Figura 3.52.
Em um sistema moderno baseado no Core i7, diversas interfaces foram integradas diretamente no chip
da CPU. Os dois canais de memória DDR3, rodando a 1.333 transações/s, conectam-se à memória principal e
oferecem uma largura de banda agregada de 10 GB/s por canal. Também integrado à CPU está um canal PC
Express de 16 vias, que idealmente pode ser configurado em um único barramento PC Express de 16 bits ou
barramentos PC Express independentes de 8 bits. As 16 vias juntas oferecem uma largura de banda de 16 GB/s
para dispositivos de E/S.
A CPU se conecta ao chip da ponte principal, o P67, por meio da interface de mídia direta (DM) serial de 20
Gb/s (2,5 GB/s). O P67 oferece interfaces para uma série de interfaces de E/S modernas de alto desempenho. Oito
vias PC Express adicionais são fornecidas, mais interfaces de disco SATA. O P67 também executa 14 interfaces
USB 2.0, Ethernet de 10G e uma de áudio.
O chip CH10 oferece suporte a interface legada para dispositivos antigos. Ele está conectado ao P67 por
meio de uma interface DM mais lenta. O CH10 implementa o barramento PC, Ethernet a 1G, portas USB e
as clássicas interfaces PC Express e SATA. Sistemas mais novos não podem incorporar o CH10; isso é exigido
apenas se o sistema precisa dar suporte a interfaces legadas.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
172
Figura 3.52 Estrutura do barramento de um Core i7 moderno.
Gráficos PCI
Express 2.0
ou
Gráficos PCI Express
2.0 (opcional)
Gráficos PCI Express
2.0 (opcional)
16 vias
16 GB/s
8 vias
8 GB/s
8 vias
8 GB/s
Intel
Core i7
DDR3 a 1.333 MHz
DDR3 a 1.333 MHz
DMI a
20 Gb/s
14 portas USB 2.0 de alta velocidade;
EHCI dual; porta USB desabilitada
MAC 100/1G/10G
integrado à Intel
Conexão de LAN
Gigabit da Intel
40
Mb/s
cada
Chipset
Intel P67
Express
5 Gb/s
cada x1
Até 6
Gb/s2
Áudio de alta
definição da Intel
8 PCI Express 2.0
6 portas seriais ATA; eSATA;
desativação de porta
Tecnologia de armazenamento
rápido da Intel (opcional)
12 portas USB 2.0 de
alta velocidade EHCI
6 PCI Express x1
MAC 10/100/1000
integrado à Intel
GLCI LCI
Conexão de LAN
Gigabit da Intel
480 Mb/s
cada
500
Mb/s
cada x1
LPC ou SPI
Suporte do BIOS
3
Gb/s
cada
Áudio de alta
definição da Intel
6 portas seriais ATA; eSATA;
desativação de porta
PCI
PCIe x1 Barramento SM
ICH10
ICH10R
2 GB/s DMI
Operac
a
o do barramento PCI
Como todos os barramentos do PC desde o BM PC original, o barramento PC é síncrono. Todas as suas
transações ocorrem entre um mestre, cujo nome oficial é iniciador, e um escravo, oficialmente denominado alvo.
Para manter baixo o número de pinos PC, as linhas de endereços e dados são multiplexadas. Desse modo, nas
placas PC são necessários somente 64 pinos para endereço mais sinais de dados, ainda que o PC suporte ende-
reços de 64 bits e dados de 64 bits.
Os pinos de endereço e de dados multiplexados funcionam da seguinte maneira. Em uma operação de leitu-
ra, durante o ciclo 1, o mestre coloca o endereço no barramento. No ciclo 2, ele remove o endereço e o barramento
muda de sentido, de modo que o escravo possa usá-lo. No ciclo 3, o escravo entrega os dados requisitados. Em
operações de escrita, o barramento não tem de virar porque o mestre coloca o endereço e também os dados. Não
obstante, a transação mínima ainda dura três ciclos. Se o escravo não conseguir responder em três ciclos, ele pode
inserir estados de espera. Também são permitidas transferências de blocos sem limite de tamanho, assim como
diversos outros tipos de ciclos de barramento.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 173
Arbitragem de barramento PCI
Para usar o barramento PC, um dispositivo deve antes adquiri-lo. A arbitragem de barramento PC usa um
árbitro de barramento centralizado, como mostra a Figura 3.53. Na maioria dos projetos, o árbitro de barramento
é inserido em um dos chips de ponte. Todo dispositivo PC tem duas linhas dedicadas que vão dele até o árbitro.
Uma linha, req#, é usada para requisitar o barramento. A outra linha, gnt#, é usada para receber concessões de
barramento. Nota: req# é a forma do PC indicar req.
Figura 3.53 O barramento PCI usa um a
rbitro de barramento centralizado.
REQ#
GNT#
REQ#
GNT#
REQ#
GNT#
REQ#
GNT#
Árbitro de PCI
Dispositivo
PCI
Dispositivo
PCI
Dispositivo
PCI
Dispositivo
PCI
Para requisitar o barramento, um dispositivo PC (incluindo a CPU) ativa req# e espera até ver sua linha
gnt# ativada pelo árbitro. Quando esse evento acontece, o dispositivo pode usar o barramento no próximo ciclo.
O algoritmo usado pelo árbitro não é definido pela especificação do PC. Arbitragem por varredura circular, arbi-
tragem por prioridade e outros esquemas são todos permitidos. Claro que um bom árbitro será justo, de modo a
não deixar alguns dispositivos esperando para sempre.
Uma concessão de barramento serve para uma transação apenas, embora em teoria o comprimento dessa
transação não tenha limite. Se um dispositivo quiser executar uma segunda transação e nenhum outro dispo-
sitivo estiver requisitando o barramento, ele pode entrar de novo, apesar de ser preciso inserir um ciclo ocioso
entre transações. Contudo, em circunstâncias especiais, na ausência de disputa pelo barramento, um dispositivo
pode fazer uma transação atrás da outra sem ter de inserir um ciclo ocioso. Se um mestre de barramento estiver
realizando uma transferência muito longa e algum outro dispositivo requisitar o barramento, o árbitro pode
negar a linha gnt#. O mestre de barramento em questão deve monitorar a linha gnt#; portanto, quando perce-
ber a negação, deve liberar o barramento no próximo ciclo. Esse esquema permite transferências muito longas
(que são eficientes) quando há só um mestre de barramento candidato, mas ainda assim dá resposta rápida a
dispositivos concorrentes.
Sinais de barramento PCI
O barramento PC tem vários sinais obrigatórios, mostrados na Figura 3.54(a), e vários sinais opcionais,
mostrados na Figura 3.54(b). O restante dos 120 ou 184 pinos são usados para energia, aterramento e diversas
funções relacionadas, e não aparecem nessa lista. As colunas Mestre (iniciador) e Escravo (alvo) informam quem
ativa o sinal em uma transação normal. Se o sinal for ativado por um dispositivo diferente (por exemplo, clk),
ambas as colunas são deixadas em branco.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
174
Figura 3.54 (a) Sinais obrigato
rios de barramento PCI. (b) Sinais opcionais de barramento PCI.
Sinal Linhas Mestre Escravo Descrição
CLK 1 Clock (33 MHz ou 66 MHz)
AD 32 × × Linhas de endereço e de dados multiplexadas
PAR 1 × Bit de paridade de endereço ou dados
C/BE 4 × Comando de barramento/mapa de bits para bytes habilitados
FRAME# 1 × Indica que AD e C/BE estão ativadas
IRDY# 1 × Leitura: mestre aceitará; escrita: dados presentes
IDSEL 1 × Seleciona espaço de configuração em vez de memória
DEVSEL# 1 × Escravo decodificou seu endereço e está na escuta
TRDY# 1 × Leitura: dados presentes; escrita: escravo aceitará
STOP# 1 × Escravo quer interromper transação imediatamente
PERR# 1 Erro de paridade de dados detectado pelo receptor
SERR# 1 Erro de paridade de endereço ou erro de sistema detectado
REQ# 1 Arbitragem de barramento: requisição de propriedade de barramento
GNT# 1 Arbitragem de barramento: concessão de propriedade de barramento
RST# 1 Restaura o sistema e todos os dispositivos
(a)
Sinal Linhas Mestre Escravo Descrição
REQ64# 1 × Requisição para realizar transação de 64 bits
ACK64# 1 × Permissão concedida para uma transação de 64 bits
AD 32 × 32 bits adicionais de endereço ou dados
PAR64 1 × Paridade para os 32 bits extras de endereço/dados
C/BE# 4 × 4 bits adicionais para habilitações de bytes
LOCK 1 × Trava o barramento para permitir múltiplas transações
SBO# 1 Presença de dados em uma cache remota (para um multiprocessador)
SDONE 1 Escuta realizada (para um multiprocessador)
INTx 4 Requisição de uma interrupção
JTAG 5 Sinais de testes IEEE 1149.1 JTAG
M66EN 1 Ligado à energia ou ao terra (66 MHz ou 33 MHz)
(b)
Agora, vamos examinar brevemente cada um dos sinais do barramento PC. Começaremos com os obrigató-
rios (32 bits) e em seguida passaremos para os opcionais (64 bits). O sinal clk comanda o barramento. A maioria
dos outros sinais é síncrona com ele. Ao contrário do SA, uma transação de barramento PC começa na borda
descendente do clk, que está no meio do ciclo, em vez de estar no início.
Os 32 sinais ad são para endereços e dados (para transações de 32 bits). Em geral, durante o ciclo 1 o ende-
reço é ativado e durante o ciclo 3 os dados são ativados. O sinal PAR é um bit de paridade para ad. O sinal c/be#
é usado para duas coisas diferentes. No ciclo 1, ele contém o comando de barramento (leia 1 palavra, leia bloco
etc.). No ciclo 2, contém um mapa de bits de 4 bits que informa quais bytes da palavra de 32 bits são válidos.
Usando c/be# é possível ler ou escrever 1, 2 ou 3 bytes quaisquer, bem como uma palavra inteira.
O sinal frame# é ativado pelo mestre para iniciar uma transação de barramento. nforma ao escravo que os
comandos de endereço e barramento agora são válidos. Em uma leitura, usualmente o irdy# é ativado ao mesmo
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 175
tempo em que o frame#. Ele informa que o mestre está pronto para aceitar dados que estão chegando. Em uma
escrita, o irdy# é ativado mais tarde, quando os dados estão no barramento.
O sinal idsel está relacionado ao fato de que todo dispositivo PC deve ter um espaço de configuração de
256 bytes que outros dispositivos possam ler (ativando idsel). Esse espaço de configuração contém propriedades
do dispositivo. A característica plug-and-play de alguns sistemas operacionais usa o espaço de configuração para
saber quais dispositivos estão no barramento.
Agora, chegamos aos sinais ativados pelo escravo. O primeiro deles, devsel#, anuncia que o escravo detectou
seu endereço nas linhas ad e está preparado para realizar a transação. Se devsel# não for ativado em certo limite
de tempo, o mestre esgota sua temporização e supõe que o dispositivo endereçado está ausente ou avariado.
O segundo sinal de escravo é trdy#, que ele ativa em leituras para anunciar que os dados estão nas linhas ad
e em escritas para anunciar que está preparado para aceitar dados.
Os três sinais seguintes são para notificar erros. O primeiro deles é stop#, que o escravo ativa se algo desas-
troso acontecer e ele quiser abortar a transação corrente. O seguinte, perr#, é usado para notificar um erro de
paridade no ciclo anterior. Para uma leitura, ele é ativado pelo mestre; para uma escrita, pelo escravo. Cabe ao
receptor executar a ação adequada. Por fim, serr# é para reportar erros de endereço e de sistema.
Os sinais req# e gnt# são para fazer arbitragem de barramento. Eles não são assegurados pelo mestre de
transferência de dados em questão, mas por um dispositivo que quer se tornar mestre de barramento. O último
sinal obrigatório é rst#, usado para reiniciar o sistema, seja porque o usuário apertou a tecla RESET seja porque
algum dispositivo do sistema notou um erro fatal. Ativar esse sinal restaura todos os dispositivos e reinicia o
computador.
Agora, chegamos aos sinais opcionais, cuja maioria está relacionada à expansão de 32 bits para 64 bits. Os
sinais req64# e ack64# permitem que o mestre peça permissão para conduzir uma transação de 64 bits e permite
que o escravo aceite, respectivamente. Os sinais ad, par64 e c/be# são apenas extensões dos sinais correspondentes
de 32 bits.
Os três sinais seguintes não estão relacionados aos 32 bits contra 64 bits, mas a sistemas multiprocessadores,
algo que as placas PC não são obrigadas a suportar. O sinal lock permite que o barramento seja travado para múl-
tiplas transações. Os dois seguintes estão relacionados à escuta do barramento para manter coerência de cache.
Os sinais intx são para requisitar interrupções. Uma placa PC pode conter até quatro dispositivos lógicos
separados e cada um pode ter sua própria linha e requisição de interrupção. Os sinais jtag são para procedimento
de teste EEE 1149.1 JTAG. Por fim, o sinal m66en é ligado alto ou é ligado baixo para estabelecer a velocidade de
clock. Não deve mudar durante a operação do sistema.
Transac
o
es de barramento PCI
Na realidade, o barramento PC é muito simples (no que diz respeito a barramentos). Para ter uma ideia
melhor dele, considere o diagrama temporal da Figura 3.55, onde podemos ver uma transação de leitura seguida
por um ciclo ocioso, seguida por uma transação de escrita pelo mesmo mestre de barramento.
Quando a borda descendente do clock acontece durante T1, o mestre põe o endereço de memória em ad e o
comando de barramento em c/be#. Então, ativa frame# para iniciar a transação de barramento.
Durante T2, o mestre libera o barramento de endereço para deixar que ele retorne em preparação para o
comando do escravo durante T3. O mestre também muda c/be# para indicar quais bytes na palavra endereçada ele
quer habilitar, isto é, quais quer que sejam lidos.
Em T3, o escravo ativa devsel# de modo que o mestre saiba que ele obteve o endereço e está planejando res-
ponder. Além disso, põe os dados nas linhas ad e ativa trdy# para informar ao mestre que fez isso. Se o escravo
não puder responder com tanta rapidez, ainda assim ele ativaria devsel# para anunciar sua presença, mas manteria
trdy# negado até que pudesse obter os dados que lá estão. Esse procedimento introduziria um ou mais estados
de espera.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
176
Figura 3.55 Exemplos de transac
o
es de barramento PCI de 32 bits. Os tre
s primeiros ciclos sa
o usados para uma operac
a
o de leitura, em
seguida um ciclo ocioso e depois tre
s ciclos para uma operac
a
o de escrita.
Φ
T1 T2 T3 T4 T5 T6 T7
AD
C/BE#
FRAME#
IRDY#
DEVSEL#
TRDY#
Ciclo de barramento
Escrita
Retorno
Leitura Ocioso
Endereço Endereço
Dados Dados
Cmd. de
leitura Habilitação
Cmd. de
leitura Habilitação
Nesse exemplo (e muitas vezes na realidade), o ciclo seguinte é ocioso. Começando em T5, vemos o mesmo
mestre iniciando uma escrita. Ele começa colocando o endereço e o comando no barramento, como sempre. Só
que agora, no segundo ciclo, ele ativa os dados. Uma vez que o mesmo dispositivo está comandando as linhas ad,
não há necessidade de um ciclo de retorno. Em T7, a memória aceita os dados.
3.6.2 PCI Express
Embora o funcionamento do barramento PC seja adequado para a maioria das aplicações, a necessidade de
maior largura de banda de E/S está causando uma confusão na antes limpa arquitetura interna do PC. A Figura
3.52 deixa claro que o barramento PC não é mais o elemento central que mantém unidas as partes do PC. O chip
ponte se apossou de parte desse papel.
A essência do problema é que há cada vez mais dispositivos de E/S muito rápidos para o barramento PC.
Elevar a frequência de clock do barramento não é uma boa solução porque então os problemas de atraso diferen-
cial no barramento, interferência na fiação e efeitos de capacitância só ficariam piores. Toda vez que um dispo-
sitivo de E/S fica muito rápido para o barramento PC (como as placas gráficas, disco rígido, redes etc.), a ntel
acrescenta uma porta especial para o chip ponte para permitir que o dispositivo contorne o barramento PC. Claro
que isso tampouco é uma solução de longo prazo.
Outro problema com o barramento PC é que as placas são muito grandes. Placas PC padrão costumam ter
17,5 cm por 10,7 cm e placas inferiores possuem 12,0 cm por 3,6 cm. Nenhuma delas cabe em laptops e, com
certeza, não em dispositivos móveis. Os fabricantes gostariam de produzir dispositivos menores ainda. Além
disso, alguns deles gostariam de repartir o espaço interno do PC, colocando a CPU e a memória dentro de uma
pequena caixa selada e o disco rígido dentro do monitor. Com as placas PC é impossível fazer isso.
Diversas soluções foram propostas, mas a que tem mais probabilidade de vencer (e em grande parte porque
a ntel está por trás dela) é denominada PCI Express. Ela tem pouco a ver com o barramento PC e, na verdade,
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 177
nem é um barramento, mas o pessoal do marketing não quer largar mão do famoso nome PC. PCs que contêm
essa solução já estão no mercado há algum tempo. amos ver como eles funcionam.
Arquitetura do PCI Express
O coração da solução PC Express (em geral, abreviado como PCe) é se livrar do barramento paralelo com
seus muitos mestres e escravos e passar para um projeto baseado em conexões seriais ponto a ponto de alta
velocidade. Essa solução representa uma ruptura radical com a tradição do barramento SA/ESA/PC e toma
emprestadas muitas ideias do mundo das redes locais, em especial a Ethernet comutada. A ideia básica se resume
no seguinte: no fundo, um PC é um conjunto de chips de CPU, memória, controladores de E/S que precisa ser
interconectado. O que o PC Express faz é fornecer um comutador de uso geral para conectar chips usando liga-
ções seriais. Uma configuração típica é ilustrada na Figura 3.56.
Figura 3.56 Sistema PCI Express t
pico.
Cache de
nível 2 CPU
Chip
ponte
Memória
Comutador
Ligações
seriais em
pares
Disco Rede USB 2 Outro
Gráficos
Como mostra a figura, a CPU, a memória e a cache estão conectadas ao chip ponte no modo tradicional. A
novidade aqui é um comutador conectado à ponte (talvez parte do próprio chip ponte ou integrado diretamente ao
processador). Cada um dos chips de E/S tem uma conexão ponto a ponto dedicada com o comutador. Cada conexão
consiste em um par de canais unidirecionais, um que vai para o comutador e outro que vem dele. Cada canal é com-
posto de dois fios, um para o sinal e outro para o terra, para dar imunidade contra ruído alto durante a transmissão
de alta velocidade. Essa arquitetura substituirá a atual por um modelo muito mais uniforme, no qual todos os dispo-
sitivos são tratados igualmente.
A arquitetura PC Express tem três pontos de diferença em relação ao antigo barramento PC. Já vimos dois
deles: um comutador centralizado contra um barramento multidrop e a utilização de conexões seriais ponto a
ponto estreitas contra um barramento paralelo largo. O terceiro é mais sutil. O modelo conceitual que fundamen-
ta o PC é o de um mestre de barramento que emite um comando a um escravo para ler uma palavra ou um bloco
de palavras. O modelo do PC Express é o de um dispositivo que envia um pacote de dados a outro dispositivo.
O conceito de um pacote, que consiste em um cabeçalho e em uma carga útil, é tirado do mundo das redes.
O cabeçalho contém informação de controle, o que elimina a necessidade dos muitos sinais de controle presen-
tes no barramento PC. A carga útil contém os dados a transferir. Na verdade, um PC com PC Express é uma
miniatura de rede de comutação de pacotes.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
178
Além dessas três importantes rupturas com o passado, também há diversas pequenas diferenças. A quarta é
que o código de detecção de erro é usado somente nos pacotes, o que dá um grau de confiabilidade mais alto do
que o barramento PC. A quinta é que a conexão entre um chip e o comutador é mais longa do que era, até 50 cm,
para permitir a repartição do sistema. A sexta é que o sistema pode ser expandido porque um dispositivo pode per-
feitamente ser outro comutador, o que permite uma árvore de comutadores. A sétima é que dispositivos podem ser
acrescentados ou removidos do sistema enquanto ele está em operação. Por fim, uma vez que conectores seriais
são muito menores do que os antigos conectores PC, podem-se fabricar dispositivos e computadores muito
menores. Em resumo, o PC Express é uma grande ruptura em relação ao barramento PC.
Pilha de protocolos do PCI Express
Condizente com o modelo de uma rede de comutação de pacotes, o sistema PC Express tem uma pilha de
protocolos em camadas. Um protocolo é um conjunto de regras que governam a conversa entre duas partes. Uma
pilha de protocolos é uma hierarquia de protocolos que tratam de questões diferentes em camadas diferentes. Por
exemplo, considere uma carta comercial. Ela obedece a certas convenções referentes à localização e ao conteúdo
do cabeçalho, ao endereço do destinatário, à data, aos cumprimentos, ao corpo, à assinatura e assim por dian-
te. Podemos dizer que tudo isso junto é um protocolo de carta. Além disso, há outro conjunto de convenções
referentes ao envelope, como tamanho, local e formato do endereço do remetente, local e formato do endereço
do destinatário, local do selo e assim por diante. Essas duas camadas e seus protocolos são independentes. Por
exemplo, é possível dar um formato completamente diferente à carta, mas usar o mesmo envelope, e vice-versa.
Protocolos em camadas são um projeto modular flexível e há décadas são muito usados no mundo dos softwares
de rede. A novidade, no caso, é montá-los no hardware do “barramento”.
A pilha de protocolos do PC Express é mostrada na Figura 3.57(a). Ela é discutida a seguir.
Figura 3.57 (a) Pilha de protocolos do PCI Express. (b) Formato de um pacote.
(a) (b)
Camada de
software
Camada de
transação
Camada de
enlace
Camada física
Cabeçalho
Cabeçalho
Cabeçalho
Seq #
Seq #
Quadro Quadro
CRC
CRC
Carga útil
Carga útil
Carga útil
amos examinar as camadas de baixo para cima. A camada mais baixa é a camada física. Ela trata da movi-
mentação de bits de um remetente para um destinatário por uma conexão ponto a ponto. Cada conexão ponto a
ponto consiste em um ou mais pares de enlaces simplex (isto é, unidirecionais). No caso mais simples, há um par
em cada direção, mas também é permitido ter 2, 4, 8, 16 ou 32 pares. Cada enlace é denominado via. O número
de vias em cada direção deve ser o mesmo. Produtos de primeira geração devem suportar uma taxa de dados de
no mínimo 2,5 Gbps, mas espera-se que logo a velocidade passe para 10 Gbps em cada direção.
Diferente dos barramentos SA/ESA/PC, o PC Express não tem um clock mestre. Os dispositivos têm
liberdade para começar a transmitir tão logo tenham dados a enviar. Essa liberdade deixa o sistema mais rápido,
mas também leva a um problema. Suponha que um bit 1 seja codificado como +3 volts e um bit 0, como 0 volt.
Se os primeiros bytes forem todos 0s, como o destinatário sabe que dados estão sendo transmitidos? Afinal, uma
sequência de 0 bits parece o mesmo que um enlace ocioso. O problema é resolvido usando o que denominamos
codificação 8b/10b. Nesse esquema, 10 bits são usados para codificar 1 byte de dados reais em um símbolo de 10
bits. Entre os 1.024 símbolos de 10 bits possíveis, foram escolhidos como legais os que têm suficientes transições
de clock para manter remetente e destinatário sincronizados nas fronteiras de bits, mesmo sem um clock mestre.
Uma consequência da codificação 8b/10b é que um enlace que tenha uma capacidade bruta de 2,5 Gbps só pode
transmitir 2 Gbps (líquidos) de dados de usuário.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 179
Enquanto a camada física lida com transmissão de bits, a camada de enlace trata de transmissão de pacotes.
Ela pega o cabeçalho e a carga útil passados para ela pela camada de transação e acrescenta a eles um número
de sequência e um código de correção de erro denominado CRC (Cyclic Redundancy Check  verificação por
redundância cíclica). O CRC é gerado pela execução de certo algoritmo no cabeçalho e nos dados da carga
útil. Quando um pacote é recebido, o destinatário efetua alguns cálculos no cabeçalho e nos dados e compara o
resultado com o CRC anexado ao pacote. Se forem compatíveis, ele devolve um curto pacote de reconhecimento
confirmando sua correta chegada. Se não forem, o destinatário solicita uma retransmissão. Desse modo, a integri-
dade dos dados melhora muito em relação ao sistema de barramento PC, que não tem nenhuma prescrição para
verificação e retransmissão de dados enviados pelo barramento.
Para evitar que um transmissor rápido soterre um receptor lento com pacotes que ele não pode manipu-
lar, é usado um mecanismo de controle de fluxo que funciona da seguinte maneira: o receptor concede ao
transmissor certo número de créditos que correspondem em essência à quantidade de espaço de buffer de que
ele dispõe para armazenar pacotes que chegam. Quando os créditos se esgotam, o transmissor tem de parar de
enviar pacotes até receber mais créditos. Esse esquema, que é muito usado em todas as redes, evita a perda
de dados em consequência da incompatibilidade entre as velocidades do transmissor e do receptor.
A camada de transação trata das ações do barramento. Ler uma palavra da memória requer duas transações:
uma iniciada pela CPU ou canal DMA que está requisitando alguns dados e outra iniciada pelo alvo que está for-
necendo os dados. Mas a camada de transação faz mais do que manipular leituras e escritas puras. Ela adiciona
valor à transmissão de pacotes bruta oferecida pela camada de enlace. Para começar, ela pode dividir cada via em
até oito circuitos virtuais, cada um manipulando uma classe de tráfego diferente. A camada de transação pode
rotular pacotes de acordo com sua classe de tráfego, o que pode incluir atributos como “alta prioridade”, “baixa
prioridade”, “não escute”, “pode ser entregue fora da ordem” e outros mais. O comutador pode usar esses rótulos
para decidir qual pacote manipulará em seguida.
Cada transação usa um dos quatro espaços de endereços:
1. Espaço da memória (para leituras e escritas comuns).
2. Espaço de E/S (para endereçar registradores de dispositivos).
3. Espaço de configuração (para inicialização do sistema etc.).
4. Espaço de mensagem (para sinalização, interrupções etc.).
Os espaços de memória e E/S são semelhantes aos dos sistemas existentes. O espaço de configuração pode
ser usado para executar características como plug-and-play. O espaço de mensagem assume o papel de muitos
dos sinais de controle existentes. É necessário ter algo parecido com esse espaço porque nenhuma das linhas de
controle do PC existe no PC Express.
A camada de software faz a interface entre sistema PC Express e sistema operacional. Ela pode emular o
barramento PC, possibilitando a execução de sistemas operacionais existentes não modificados em sistemas PC
Express. Claro que uma operação como essa não irá explorar todo poder do PC Express, mas a compatibilidade
é um mal necessário até que os sistemas operacionais sejam modificados para utilizar totalmente o PC Express.
A experiência mostra que isso pode levar algum tempo.
O fluxo de informações é ilustrado na Figura 3.57(b). Quando é dado um comando à camada de software,
esta o passa para a camada de transação, que o formula em termos de um cabeçalho e uma carga útil. Então, essas
duas partes são passadas para a camada de enlace, que acrescenta um número de sequência à sua parte anterior e
um CRC à posterior. Em seguida, esse pacote ampliado é passado à camada física, que acrescenta informações de
enquadramento de dados a cada extremidade para formar o pacote físico, que é, por fim, transmitido. Na extre-
midade receptora ocorre o processo inverso – cabeçalho de enlace e as informações que acompanham o bloco de
dados (trailer) são removidos e o resultado é passado para a camada de transação.
O conceito do acréscimo de informações adicionais aos dados à medida que ele desce pela pilha de protoco-
los já é usado há décadas no mundo das redes com grande sucesso. A grande diferença entre uma rede e o PC
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
180
Express é que, no mundo das redes, o código nas várias camadas quase sempre é um software que faz parte do
sistema operacional. No PC Express, ele faz parte do hardware do dispositivo.
O PC Express é um assunto complicado. Para mais informações, consulte Mayhew e Krishnan, 2003; e
Solari e Congdon, 2005. Ele ainda está evoluindo. Em 2007, o PCe 2.0 foi lançado. Ele admite 500 MB/s por
via em até 32 vias, para uma largura de banda total de 16 GB/s. Depois veio o PCe 3.0 em 2011, que mudou a
codificação de 8b/10b para 128b/130b e pode rodar a 8 bilhões de transações por segundo, o dobro do PCe 2.0.
3.6.3 Barramento serial universal (USB)
O barramento PC e o PC Express são bons para anexar periféricos de alta velocidade a um computador, mas
são muito caros para dispositivos de E/S de baixa velocidade, como teclados e mouses. Cada dispositivo padrão de
E/S era conectado ao computador de modo especial, com alguns encaixes SA e PC livres para adicionar novos
dispositivos. nfelizmente, esse esquema teve problemas desde o início.
Por exemplo, cada novo dispositivo de E/S costuma vir com sua própria placa SA ou PC. Muitas vezes, o usuá-
rio é responsável pelo ajuste de comutadores e pontes na placa e por assegurar que tais ajustes não entrem em con-
flito com as outras placas. Então, ele precisa abrir a torre, inserir cuidadosamente a placa, fechar a torre e reiniciar
o computador. Para muitos usuários, esse processo é difícil e sujeito a erros. Além disso, o número de encaixes SA
e PC é muito limitado (em geral, dois ou três). Placas plug-and-play eliminam o ajuste das pontes, mas ainda assim
o usuário tem de abrir o computador para inserir a placa e o número de encaixes do barramento continua limitado.
Para tratar desse problema, em 1993, representantes de sete empresas (Compaq, DEC, BM, ntel, Microsoft,
NEC e Northern Telecom) se reuniram para buscar a melhor maneira de anexar dispositivos de E/S a um computador.
Desde então, centenas de outras empresas se juntaram a elas. O padrão resultante, lançado oficialmente em 1998, é
denominado USB (Universal Serial Bus  barramento serial universal), e é amplamente executado em computadores
pessoais. Uma descrição mais detalhada desse barramento pode ser encontrada em Anderson (1997) e Tan (1997).
Alguns dos objetivos das empresas que conceberam o USB original e iniciaram o projeto eram os seguintes:
1. Usuários não terão de ajustar comutadores ou pontes em placas ou dispositivos.
2. Usuários não terão de abrir a torre para instalar novos dispositivos de E/S.
3. Haverá apenas um tipo de cabo, que servirá para conectar todos os dispositivos.
4. A energia para os dispositivos de E/S deve ser fornecida por esse cabo.
5. Até 127 dispositivos poderão ser ligados a um único computador.
6. O sistema deve suportar dispositivos de tempo real (por exemplo, som, telefone).
7. Os dispositivos poderão ser instalados com o computador em funcionamento.
8. Não será preciso reiniciar o computador após a instalação do dispositivo.
9. O custo de produção do novo barramento e de seus dispositivos de E/S não deve ser alto.
O USB cumpre todos esses objetivos. É projetado para dispositivos de baixa velocidade, como teclados, mou-
ses, câmeras fotográficas, scanners, telefones digitais e assim por diante. A versão 1.0 tem uma largura de banda
de 1,5 Mbps, que é suficiente para teclados e mouses. A versão 1.1 funciona em 12 Mbps, que é suficiente para
impressoras, câmeras digitais e muitos outros dispositivos. A versão 2.0 tem suporte para dispositivos com até
480 Mbps, que é suficiente para trabalhar com drives de disco externos, webcams de alta definição e interfaces de
rede. O USB versão 3.0, recentemente definido, empurra as velocidades para acima de 5 Gbps; só o tempo dirá
quais aplicações novas e ávidas por largura de banda aproveitarão essa interface com largura de banda ultra-alta.
Um sistema USB consiste em um hub-raiz (root hub) que é ligado ao barramento principal (veja a Figura
3.51). Esse hub tem soquetes para cabos que podem ser conectados a dispositivos de E/S ou a hubs de expansão,
para fornecer mais soquetes, de modo que a topologia de um sistema USB é uma árvore cuja raiz está no hub,
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 181
dentro do computador. Há diferentes conectores na extremidade dos cabos do hub-raiz e na extremidade do dis-
positivo para evitar que, por acidente, os usuários liguem dois soquetes entre si.
O cabo consiste em quatro fios: dois para dados, um para energia (+5 volts) e um para terra. O sistema de
sinalização transmite um 0 como uma transição de tensão e um 1 como ausência de uma transição da tensão,
portanto, longas carreiras de 0s geram um fluxo regular de pulsos.
Quando um novo dispositivo de E/S é ligado, o hub-raiz detecta esse evento e interrompe o sistema ope-
racional, que então pesquisa para descobrir que dispositivo é e de quanta largura de banda USB ele precisa.
Se o sistema operacional decidir que há suficiente largura de banda para o dispositivo, atribui um endereço
exclusivo para ele (1–127) e descarrega esse endereço e outras informações em registradores de configura-
ção dentro do dispositivo. Desse modo, novos dispositivos podem ser acrescentados com o computador em
funcionamento, sem exigir nenhuma configuração da parte do usuário e sem ter de instalar novas placas SA
ou PC. Placas não inicializadas começam com endereço 0, por isso, podem ser endereçadas. Para simplificar
o cabeamento, muitos dispositivos USB contêm conexões internas que aceitam dispositivos USB adicionais.
Por exemplo, um monitor poderia ter dois soquetes de conexão para acomodar os alto-falantes esquerdo e
direito.
Em termos lógicos, o sistema USB pode ser visto como um conjunto de ramificações que saem do hub-raiz
para os dispositivos de E/S. Cada dispositivo pode subdividir sua própria ramificação em até 16 ramos secundá-
rios para diferentes tipos de dados (por exemplo, áudio e vídeo). Dentro de cada ramo secundário, os dados fluem
do hub-raiz até o dispositivo, ou ao contrário. Não há tráfego entre dois dispositivos de E/S.
Exatamente a cada 1,00 ± 0,05 ms, o hub-raiz transmite um novo quadro para manter todos os dispositivos
sincronizados em relação ao tempo. Um quadro é associado a um caminho de bit e consiste em pacotes, o primei-
ro dos quais vem do hub-raiz até o dispositivo. Pacotes subsequentes no quadro também podem ir nessa direção
ou voltar do dispositivo até o hub-raiz. A Figura 3.58 mostra uma sequência de quatro quadros.
Na Figura 3.58, não há nenhum serviço a ser realizado nos quadros 0 e 2, portanto, basta um pacote SOF
(Start of Frame – início do quadro). Ele é sempre transmitido para todos os dispositivos. O quadro 1 é uma son-
dagem (poll), por exemplo, uma requisição para que um scanner devolva os bits que encontrou na imagem que
está digitalizando. O quadro 3 consiste em entregar dados a algum dispositivo, por exemplo, uma impressora.
O USB suporta quatro tipos de quadros: de controle, isócrono, de volume e de interrupção. Quadros de con-
trole são usados para configurar dispositivos, transmitir-lhes comandos e inquirir seu estado. Quadros isócronos
são para dispositivos de tempo real, como microfones, alto-falantes e telefones, que precisam enviar ou aceitar
dados a intervalos de tempo exatos. Eles têm um atraso muito previsível, mas não fazem retransmissões quando
Figura 3.58 Hub-raiz USB emite quadros a cada 1,00 ms.
0
SOF
2
SOF
1
SOF IN DATA ACK
SYN PID PAYLOAD CRC
3
SOF OUT DATA ACK
SYN PID PAYLOAD CRC
Tempo (ms)
Ocioso
Quadro 0 Quadro 1 Quadro 2 Quadro 3
Pacotes
da raiz
Pacotes
da raiz
A partir do
dispositivo
Pacote de dados
do dispositivo
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
182
ocorrem erros. Quadros de volume são para grandes transferências de e para dispositivos para os quais não há
requisitos de tempo real, como impressoras. Por fim, quadros de interrupção são necessários porque o USB não
aceita interrupções. Por exemplo, em vez de fazer com que o teclado cause uma interrupção sempre que uma tecla
é acionada, o sistema operacional pode fazer uma sondagem a cada 50 ms para coletar qualquer tecla acionada
que esteja pendente.
Um quadro consiste em um ou mais pacotes, alguns possivelmente na mesma direção. Existem quatro tipos
de pacotes: permissão (token), dados, apresentação (handshake) e especial. Pacotes de permissão vêm da raiz
até um dispositivo e servem para controle do sistema. Os pacotes SOF, N e OUT na Figura 3.58 são pacotes
de permissão. O pacote SOF é o primeiro de cada quadro e marca seu início. Se não houver nenhum trabalho a
realizar, o pacote SOF é o único no quadro. O pacote de permissão N é uma sondagem, que pede ao dispositivo
que retorne certos dados. Campos no pacote N informam qual caminho está sendo sondado de modo que o
dispositivo saiba quais dados retornar (se tiver múltiplos fluxos). O pacote de permissão OUT anuncia ao dispo-
sitivo que serão enviados dados a ele. Um quarto tipo de pacote de permissão, SETUP (não mostrado na figura),
é usado para configuração.
Além do pacote de permissão há três outros tipos de pacote: DATA (usado para transmitir até 64 bytes de
informação em qualquer direção), pacotes de apresentação e pacotes especiais. O formato de um pacote de dados
é mostrado na Figura 3.58. Consiste em um campo de sincronização de 8 bits, um tipo de pacote (PD) de 8 bits,
a carga útil (payload) e um CRC de 16 bits para detectar erros. São definidos três tipos de pacotes de apresentação:
ACK (o pacote de dados anterior foi recebido corretamente), NAK (foi detectado um erro CRC) e STALL (favor
esperar – agora estou ocupado).
Agora, vamos examinar a Figura 3.58 mais uma vez. A cada 1,00 ms um quadro deve ser enviado do
hub-raiz, mesmo que não haja trabalho a realizar. Os quadros 0 e 2 consistem em apenas um pacote SOF,
indicando que não há trabalho a executar. O quadro 1 é uma sondagem, portanto, começa com pacotes SOF
e N do computador ao dispositivo de E/S, seguidos por um pacote DATA do dispositivo para o computador.
O pacote ACK informa ao dispositivo que os dados foram recebidos corretamente. Caso ocorra um erro, um
NAK é devolvido ao dispositivo e o pacote é retransmitido quando for de volume, mas não quando os dados
forem isócronos. A estrutura do quadro 3 é semelhante à do quadro 1, exceto que agora o fluxo de dados é
do computador para o dispositivo.
Após a conclusão do padrão USB em 1998, o pessoal que o projetou não tinha nada para fazer, então, come-
çou a trabalhar em uma nova versão de alta velocidade do USB, denominada USB 2.0. Esse padrão é semelhante
ao antigo USB 1.1 e compatível com ele, exceto pela adição de uma terceira velocidade, 480 Mbps, às duas exis-
tentes. Além disso, há algumas pequenas diferenças, como interface entre hub-raiz e o controlador. O USB 1.1
tinha duas interfaces disponíveis. A primeira, UHCI (Universal Host Controller Interface  interface universal
de controlador de hospedeiro), foi projetada pela ntel e passava grande parte da carga para os projetistas de
software (leia-se: Microsoft). A segunda, OHCI (Open Host Controller Interface  interface aberta de controla-
dor de hospedeiro), foi projetada pela Microsoft e passava grande parte da carga para os projetistas de hardware
(leia-se: ntel). No USB 2.0, todos concordaram com uma nova interface única denominada EHCI (Enhanced
Host Controller Interface  interface melhorada de controlador de hospedeiro).
Agora que o USB funcionava a 480 Mbps, passou a competir com o barramento serial EEE 1394, mais conhe-
cido como FireWire, que funciona a 400 Mbps ou 800 Mbps. isto que praticamente todo novo PC baseado no
ntel agora vem com USB 2.0 ou USB 3.0 (ver a seguir), é provável que o 1394 desapareça no devido tempo. O
desaparecimento não é tanto pela obsolescência quanto à guerra por territórios. O USB é um produto da indústria
da computação, enquanto o 1394 vem do setor de eletrônica de consumo. Quando se trata de conectar câmeras a
computadores, cada indústria queria que todos usassem seu cabo. Parece que o pessoal do computador ganhou essa.
Oito anos depois da introdução do USB 2.0, o padrão de interface USB 3.0 foi anunciado. O USB 3.0 admite
incríveis 5 Gbps de largura de banda pelo cabo, embora a modulação do enlace seja adaptativa, e provavelmente
essa velocidade só poderá ser alcançada com cabeamento de qualidade profissional. Os dispositivos USB 3.0 são
estruturalmente idênticos aos dispositivos USB anteriores, e executam totalmente o padrão USB 2.0. Se conecta-
dos a um soquete USB 2.0, eles operarão corretamente.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 183
3.7 Interface
Um sistema de computador típico de pequeno a médio porte consiste em um chip de CPU, chipset, chips de
memória e alguns controladores de E/S, todos conectados por um barramento. Às vezes, todos esses dispositivos
estão integrados a um sistema-em-um-chip, como o T OMAP4430. Já estudamos memórias, CPUs e barramentos
com certo detalhe. Agora, chegou a hora de examinar a última parte do quebra-cabeça, as interfaces de E/S. É por
meio dessas portas de E/S que o computador se comunica com o mundo exterior.
3.7.1 Interfaces de E/S
Há inúmeras interfaces de E/S disponíveis no mercado e novas são lançadas o tempo todo. Entre as interfaces
comuns estão UARTs, USARTs, controladores de CRT, controladores de disco e POs. Uma UR (Universal
synchronous Receiver ransmitter  transmissor receptor assíncrono universal) é uma interface de E/S que
pode ler um byte do barramento de dados e entregá-lo um bit por vez a um terminal por meio de uma linha serial,
ou receber dados de um terminal. Em geral, as UARTs permitem várias velocidades de 50 a 19.200 bps; largura de
caracteres de 5 a 8 bits; 1, 1,5 ou 2 bits de fim; e fornecem paridade par, ímpar ou nenhuma paridade, tudo sob con-
trole de programa. USRs (Universal Synchronous synchronous Receiver ransmitters  transmissor receptor
assíncrono síncrono universal) podem manipular transmissão síncrona usando uma variedade de protocolos, bem
como executando todas as funções da UART. Como as UARTs se tornaram menos importantes com o desapareci-
mento dos modems de telefone, agora vamos estudar a interface paralela como exemplo de uma interface de E/S.
Interfaces PIO
Uma interface PIO (Parallel Input/Output  entrada e saída paralela) típica é o ntel 8255A, mostrado na
Figura 3.59. Ele tem uma série de linhas de E/S (por exemplo, 24 linhas de E/S no exemplo da figura) que podem
fazer ligação com qualquer interface de dispositivo lógico digital, por exemplo, teclados, comutadores, luzes ou
impressoras. Resumindo, o programa da CPU pode escrever um 0 ou 1, ou ler o estado de entrada de qualquer
linha, o que dá grande flexibilidade. Um pequeno sistema com CPU que use uma interface PO pode controlar
diversos dispositivos físicos, como um robô, torradeira ou microscópio eletrônico. As interfaces PO são encon-
tradas frequentemente em sistemas embutidos.
Figura 3.59 Uma interface PIO de 24 bits.
Porta A
Porta B
Porta C
CS
WR
RD
A0-A1
RESET
D0-D7
2
8
8
8
8
Interface de E/S
Paralela (PIO)
A interface PO é configurada com um registrador de configuração de 3 bits, que especifica se as três portas
independentes de 8 bits devem ser usadas para entrada (0) ou saída (1) do sinal digital. A definição do valor
apropriado no registrador de configuração permitirá qualquer combinação de entrada e saída para as três portas.
Associado com cada porta há um registrador com amostragem de 8 bits. Para estabelecer as linhas em uma porta
de saída, a CPU apenas escreve um número de 8 bits no registrador correspondente, e esse número aparece nas
linhas de saída e fica ali até que o registrador seja reescrito. Para usar uma porta para entrada, a CPU apenas lê o
registrador de 8 bits correspondente.
É possível montar interfaces PO mais sofisticadas. Por exemplo, um modo de operação popular fornece apre-
sentação com dispositivos externos. Assim, para enviar a um dispositivo que nem sempre está pronto para aceitar
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
184
dados, a interface PO pode apresentar dados em uma porta de saída e esperar que o dispositivo devolva um pulso
informando que aceitou os dados e quer mais. A lógica necessária para amostrar tais pulsos e torná-los disponíveis
para a CPU inclui um sinal de pronto e mais uma fila de registradores de 8 bits para cada porta de saída.
Pelo diagrama funcional da interface PO, podemos ver que, além dos 24 pinos para as três portas, ela tem oito
linhas que se conectam diretamente com o barramento de dados, uma linha de seleção de chip (chip select), linhas de
leitura e escrita, duas linhas de endereço e uma para reiniciar o chip. As duas linhas de endereço selecionam um dos
quatro registradores internos correspondentes às portas A, B, C e ao registrador de configuração de porta. Em geral, as
duas linhas de endereço estão conectadas aos bits de ordem baixa do barramento de endereço. A linha de seleção de
chip permite que a interface PO de 24 bits seja combinada para formar interfaces PO maiores, acrescentando outras
linhas de endereço e usando-as para selecionar a interface PO apropriada, ativando sua linha de seleção de chip.
3.7.2 Decodificac
a
o de enderec
o
Até agora fomos propositalmente superficiais sobre como a seleção do chip é ativada na memória e nos chips
de E/S que já vimos. Agora, é hora de examinar com mais cuidado como isso é feito. amos considerar um com-
putador embutido simples de 16 bits que consiste em uma CPU, uma EPROM de 2 KB × 8 bytes para o programa,
uma RAM de 2 KB × 8 bytes para os dados e uma interface PO. Esse pequeno sistema pode ser usado como
um protótipo para o cérebro de um brinquedo barato ou um eletrodoméstico simples. Uma vez em produção, a
EPROM poderia ser substituída por uma ROM.
A interface PO pode ser selecionada de um entre dois modos: como um verdadeiro dispositivo de E/S
ou como parte da memória. Se optarmos por usá-la como um dispositivo de E/S, então devemos selecioná-la
usando uma linha de barramento explícita que indica que um dispositivo de E/S está sendo referenciado, e não
a memória. Se usarmos a outra abordagem, E/S mapeada para a memória, então temos de lhe designar 4 bytes
do espaço de memória para as três portas e o registrador de controle. A escolha é, de certa forma, arbitrária.
Escolheremos E/S mapeada para a memória porque ela ilustra alguns aspectos interessantes da interface de E/S.
A EPROM necessita de 2 KB de espaço de endereço, a RAM também precisa de 2 K de espaço de endereço e
a PO precisa de 4 bytes. Como o espaço de endereço de nosso exemplo é 64 K, temos de escolher onde colocar
os três dispositivos. Uma opção possível é mostrada na Figura 3.60. A EPROM ocupa endereços até 2 K, a RAM
ocupa endereços de 32 KB a 34 KB e a PO ocupa os 4 bytes mais altos do espaço de endereço, 65.532 a 65.535.
Do ponto de vista do programador, não faz diferença quais endereços são usados; contudo, isso não acontece
quando se trata da interface. Se tivéssemos optado por endereçar a PO via espaço de E/S, ela não precisaria de
nenhum endereço de memória, mas precisaria de quatro espaços de endereço de E/S.
Com as designações de endereço da Figura 3.60, a EPROM deve ser selecionada por quaisquer endereços de
memória de 16 bits da forma 00000xxxxxxxxxxx (binário). Em outras palavras, qualquer endereço de memória
cujos 5 bits de ordem alta são todos 0s cai na parte inferior da memória de 2 KB, portanto, na EPROM. Por isso,
a seleção de chip da EPROM poderia ser ligada a um comparador de 5 bits, com uma de suas entradas perma-
nentemente ligada a 00000.
Uma maneira melhor de conseguir o mesmo efeito é usar uma porta OR de cinco entradas com as cinco
entradas ligadas às linhas de endereço A11 a A15. Se, e somente se, todas a cinco linhas forem 0, a saída será 0,
Figura 3.60 Localizac
a
o da EPROM, RAM e PIO em nosso espac
o de enderec
o de 64 KB.
0 4K 8K 12K 16K 20K 24K 28K 32K 36K 40K 44K 48K 52K 56K 60K 64K
EPROM no endereço 0 RAM no endereço 8000H PIO em FFFCH
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 185
o que ativa cs (que é ativado baixo). Esse método de endereçamento é ilustrado na Figura 3.61(a) e é chamado
decodificação de endereço completo.
O mesmo princípio pode ser usado para a RAM. Contudo, a RAM deve responder a endereços binários
da forma 10000xxxxxxxxxxx, portanto, é preciso um inversor adicional, como mostra a figura. A decodifica-
ção de endereços PO é um pouco mais complicada, porque é selecionada pelos quatro endereços da forma
11111111111111xx. Um possível circuito que assegure cs só quando o endereço correto aparecer no barramento
de endereço é mostrado na figura. Ele usa duas portas nand de oito entradas para alimentar uma porta or.
Contudo, se o computador de fato tiver apenas uma CPU, dois chips de memória e a PO, podemos usar
um truque para conseguir uma decodificação de endereço muito mais simples. Esse truque se baseia no fato de
que todos os endereços da EPROM, e somente endereços da EPROM, têm um 0 no bit de ordem alta, a15. Por
conseguinte, basta ligar cs a a15 diretamente, como mostra a Figura 3.61(b).
Figura 3.61 (a) Decodificac
a
o total de enderec
o. (b) Decodificac
a
o parcial de enderec
o.
A0
A15
A0
A15
CS CS CS
CS CS CS
EPROM
2K × 8
RAM
2K × 8
PIO
EPROM
2K × 8
RAM
2K × 8
PIO
(a)
(b)
Barramento
de endereço
Barramento
de endereço
Nesse ponto, a decisão de colocar a RAM em 8000H pode parecer muito menos arbitrária. A decodifi-
cação da RAM pode ser feita observando que somente endereços válidos da forma 10xxxxxxxxxxxxxx estão
na RAM, portanto, 2 bits de decodificação são suficientes. De modo semelhante, qualquer endereço que
comece com 11 deve ser um endereço PO. Agora, a lógica completa de decodificação são duas portas nand
e um inversor.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
186
A lógica de decodificação de endereço da Figura 3.61(b) é denominada decodificação parcial de ende-
reço, porque não são usados os endereços completos. Ela tem essa propriedade: uma leitura dos endereços
0001000000000000, 0001100000000000 ou 0010000000000000 dará o mesmo resultado. Na verdade, todo ende-
reço na metade inferior do espaço de endereço selecionará a EPROM. Como os endereços extras não são usados,
não há dano algum, mas se estivermos projetando um computador que poderá ser expandido no futuro (o que é
improvável no caso de um brinquedo), devemos evitar a decodificação parcial porque ela ocupa muito espaço de
endereço.
Outra técnica comum de decodificação de endereço é usar um decodificador como o mostrado na Figura
3.13. Conectando as três entradas às três linhas de endereço de ordem alta, obtemos oito saídas correspondentes
aos endereços nos primeiros 8 K, nos 8 K seguintes e assim por diante. Para um computador com oito RAMs, cada
uma com 8 K × 8, um chip como esse fornece decodificação completa. Para um computador com oito chips de
memória de 2 K × 8, um único decodificador também é suficiente, contanto que cada um dos chips de memória
esteja localizado em porções distintas de 8 KB do espaço de endereço. (Lembre-se de que observamos anterior-
mente que a posição dos chips de memória e E/S dentro do espaço de endereços tem importância.)
3.8 Resumo
Computadores são construídos com base em chips de circuito integrado que contêm minúsculos elementos
comutadores denominados portas. As portas mais comuns são and, or, nand, nor e not. Circuitos simples podem
ser montados ao se combinar diretamente portas individuais.
Circuitos mais complexos são multiplexadores, demultiplexadores, codificadores, decodificadores, deslo-
cadores e ULAs. Funções booleanas arbitrárias podem ser programadas usando um FPGA. Se forem necessárias
muitas funções booleanas, os FPGAs costumam ser mais eficientes. As leis da álgebra booleana podem ser usadas
para transformar circuitos de uma forma para outra. Em muitos casos, é possível produzir circuitos mais econô-
micos dessa maneira.
A aritmética de computadores é efetuada por somadores. Um somador completo de um só bit pode ser cons-
truído usando dois meios-somadores. Um somador para uma palavra multibit pode ser construído com a conexão
de vários somadores completos de tal modo que permita o vai-um para seu vizinho da esquerda.
Os componentes de memórias (estáticas) são latches e flip-flops, cada um dos quais pode armazenar um bit de
informação. Esses bits podem ser combinados linearmente formando latches octais e flip-flops, ou por logaritmos
formando memórias completas que usam palavras. Há memórias de vários tipos: RAM, ROM, PROM, EPROM,
EEPROM e flash. RAMs estáticas não precisam ser renovadas; elas mantêm seus valores armazenados enquanto
a energia estiver ligada. RAMs dinâmicas, por outro lado, devem ser renovadas periodicamente para compensar a
fuga de corrente dos pequenos capacitores do chip.
Os componentes de um sistema de computador são conectados por barramentos. Muitos pinos – não todos –
de um chip de CPU típico comandam diretamente uma linha de barramento. Tais linhas podem ser divididas
em linhas de endereço, de dados e de controle. Barramentos síncronos são comandados por um clock mestre.
Barramentos assíncronos usam trocas completas para sincronizar o escravo com o mestre.
O Core i7 é um exemplo de uma CPU moderna. Sistemas modernos que usam esse chip têm um barramento
de memória, um barramento PCe e um barramento USB. A interconexão PCe é o modo mais comum de conectar
as partes internas de um computador em altas velocidades. A ARM também é uma CPU moderna de alto nível,
mas é voltada para sistemas embutidos e dispositivos móveis, onde o baixo consumo de energia é importante. O
Atmel ATmega168 é um exemplo de um chip de baixo preço para aparelhos pequenos, baratos, e muitas outras
aplicações sensíveis ao preço.
Comutadores, luzes, impressoras e muitos outros dispositivos de E/S podem fazer interface com computadores
usando interfaces de E/S paralela. Esses chips podem ser configurados como parte do espaço de E/S ou do espaço de
memória, conforme a necessidade. Eles podem ser total ou parcialmente decodificados, dependendo da aplicação.
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 187
Problemas
1. Circuitos analógicos estão sujeitos a ruído que pode
distorcer sua saída. Os circuitos digitais são imunes
ao ruído? Discuta sua resposta.
2. Um especialista em lógica entra em uma lancho-
nete drive-in e diz: “Quero um hambúrguer ou um
cachorro-quente e batatas fritas”. nfelizmente, o
cozinheiro não sabe (ou não se importa) se “e” tem
precedência sobre “ou”. Para ele, tanto faz uma ou
outra interpretação. Quais dos seguintes casos são
interpretações válidas do pedido?
a. Apenas um hambúrguer.
b. Apenas um cachorro-quente.
c. Apenas batatas fritas.
d. Um cachorro-quente e batatas fritas.
e. Um hambúrguer e batatas fritas.
f. Um cachorro-quente e um hambúrguer.
g. Todo os três.
h. Nada – o especialista em lógica passa fome por ser
um espertinho.
3. Um missionário perdido no sul da Califórnia para
em um entroncamento da rodovia. Ele sabe que duas
gangues de motociclistas frequentam a área; uma
delas sempre diz a verdade e a outra sempre mente.
Ele quer saber qual estrada leva à Disneylândia. Que
pergunta deve fazer?
4. Use a tabela verdade para mostrar que X = (X and Y)
or (X and not Y).
5. Existem quatro funções booleanas de uma única
variável e 16 funções de duas variáveis. Quantas
funções de três variáveis existem? E de n variáveis?
6. Existem quatro funções booleanas de uma única
variável e 16 funções de duas variáveis. Quantas fun-
ções de quatro variáveis existem?
7. Mostre como a função and pode ser construída com
base em duas portas nand.
8. Usando o chip multiplexador de três variáveis da
Figura 3.12, execute uma função cuja saída é pari-
dade das entradas, isto é, a saída é 1 se, e somente se,
um número par de entradas for 1.
9. Ponha seu “capacete de raciocínio”. O chip mul-
tiplexador de três variáveis da Figura 3.12 pode
calcular uma função arbitrária de quatro variáveis
booleanas. Descreva como e, a título de exemplo,
desenhe o diagrama lógico para a função que é 0 se a
palavra inglesa para a fila da tabela verdade tiver um
número par de letras, é 1 se tiver um número ímpar
de letras (por exemplo, 0000 = zero = quatro letras
→ 0; 0111 = seven = cinco letras → 1; 1101 = thirteen
= oito letras → 0). Dica: se denominarmos a quarta
entrada variável D, as oito linhas de entrada podem
ser ligadas a Vcc, terra, D ou D.
10. Desenhe o diagrama lógico para um codificador de
2 bits, um circuito com quatro linhas de entrada,
exatamente uma das quais é alta em qualquer instan-
te dado, e duas linhas de saída cujo valor binário de
2 bits informa qual entrada é alta.
11. Desenhe o diagrama lógico para um demultiplexador
de 2 bits, um circuito cuja única linha de entrada
é direcionada para uma das quatro linhas de saída
dependendo do estado das duas linhas de controle.
12. O que esse circuito faz?
A
B
C
D
13. Um chip comum é um somador de 4 bits. Quatro
desses chips podem ser conectados para formar um
somador de 16 bits. Quantos pinos você espera que
tenha o chip do somador de 4 bits? Por quê?
14. Um somador de bits pode ser construído fazendo um
arranjo em cascata de n somadores completos em
série com o vem-um no estágio i, Ci, vindo da saída
o estágio i – 1. O vem-um para o estágio 0, C0, é 0.
Se cada estágio levar T nanossegundos para produzir
sua soma e vai-um, o vem-um para o estágio i não
será válido até iT nanossegundos após o início da
adição. Para n grande, o tempo requerido para o vai-
-um fazer o transporte (ripple) até o estágio de ordem
alta pode ser inaceitavelmente longo. Projete um
somador que funcione com mais rapidez. Dica: cada
Ci pode ser expresso em termos dos bits de operando
Ai – 1 e Bi – 1, bem como do vai-um Ci – 1. Usando essa
relação, é possível expressar Ci como uma função das
entradas para os estágios 0 a i – 1, de modo que todos
os vai-um possam ser gerados simultaneamente.
15. amos admitir que todas as portas da Figura 3.18
tenham um atraso de propagação de 1 ns e que
podemos ignorar todos os outros atrasos. Qual o
menor tempo para esse circuito ter certeza de que um
bit de saída é válido?
16. A ULA da Figura 3.19 é capaz de fazer adições de
complemento 2 de oito bits. Ela também pode fazer
subtrações de complemento 2? Se puder, explique
como. Caso contrário, modifique-a para que possa
efetuar subtrações.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
188
17. Uma ULA de 16 bits é composta de 16 ULAs de 1
bit, cada uma com um tempo de adição de 10 ns.
Se houver 1 ns adicional de atraso de propagação de
uma ULA para a seguinte, quanto tempo leva para
aparecer o resultado de uma soma de 16 bits?
18. Às vezes, é útil que uma ULA de 8 bits como a da
Figura 3.19 gere a constante –1 como saída. Proponha
dois modos para fazer isso. Especifique os valores dos
seis sinais de controle para cada um deles.
19. Qual é o estado quiescente das entradas S e R para
um latch SR composto de duas portas nand?
20. O circuito da Figura 3.25 é um flip-flop que é dis-
parado na borda ascendente do clock. Modifique esse
circuito para produzir um flip-flop que é disparado
na borda descendente.
21. A memória 4 × 3 da Figura 3.28 usa 22 portas and
e três portas or. Se o circuito tivesse de ser expan-
dido para 256 × 8, quantas portas de cada seriam
necessárias?
22. Para ajudar a pagar o novo computador pessoal que
comprou, você está prestando consultoria a novos
fabricantes de chips SS. Um de seus clientes está
pensando em produzir um chip que contém 4 flip-
-flops D, cada um contendo Q e também Q, a pedido
de um cliente potencialmente importante. O projeto
proposto agrupa todos os quatro sinais de clock, tam-
bém a pedido. Não há preset nem clear. Sua tarefa é
fazer uma avaliação profissional do projeto.
23. À medida que cada vez mais memória é espremida
em um único chip, o número de pinos necessários
para endereçá-la também aumenta. Muitas vezes,
é inconveniente ter grandes números de pinos
de endereço em um chip. Proponha um meio de
endereçar 2n
palavras de memória usando menos do
que n pinos.
24. Um computador com um barramento de dados de 32
bits de largura usa chips de memória RAM dinâmica
de 1 M × 1. Qual é a menor memória (em bytes) que
esse computador pode ter?
25. Referindo-nos ao diagrama temporal da Figura 3.38,
suponha que você desacelerou o relógio para um
período de 20 ns em vez de 10 ns, como mostra a
figura, mas que as restrições de temporização per-
maneceram inalteradas. Na pior das hipóteses, quanto
tempo a memória teria para colocar os dados no bar-
ramento durante T3 após mreq estar ativado?
26. Novamente com referência à Figura 3.38, suponha
que o clock permaneceu a 100 MHz, mas TDS foi
aumentado para 4 ns. Poderiam ser usados chips de
memória de 10 ns?
27. Na Figura 3.38(b), TML é especificado para ser no
mínimo 2 nanossegundos. ocê pode imaginar um
chip no qual ele seja negativo? Especificamente, a
CPU poderia ativar mreq antes de o endereço estar
estável? Por que ou por que não?
28. Considere que a transferência de bloco da Figura
3.42 foi realizada no barramento da Figura 3.38.
Quanto mais largura de banda obtemos usando uma
transferência de bloco em comparação com trans-
ferências individuais para blocos longos? Agora,
considere que a largura do barramento é 32 bits, e
não 8 bits. Responda à pergunta outra vez.
29. ndique os tempos de transição das linhas de
endereço da Figura 3.39 como TA1 e TA2, e os tempos
de transição de mreq como TMREQ1 e TMREQ2 e assim
por diante. Anote todas as desigualdades implicadas
pela troca completa.
30. Chips multicore, com várias CPUs no mesmo subs-
trato, estão se tornando populares. Que vantagens
elas têm em relação a um sistema consistindo de
vários PCs conectados por uma Ethernet?
31. Por que os chips multicore apareceram de repente?
Existem fatores tecnológicos que tenham preparado
o caminho para eles? A lei de Moore tem alguma
influência aqui?
32. Qual é a diferença entre o barramento de memória e
o barramento PC?
33. A maioria dos barramentos de 32 bits permite leitu-
ras e escritas de 16 bits. Há alguma ambiguidade
sobre onde colocar os dados? Discuta.
34. Muitas CPUs têm um tipo especial de ciclo de barra-
mento para reconhecimento de interrupção. Por quê?
35. Um computador de 32 bits com um barramento de
400 MHz requer quatro ciclos para ler uma palavra
de 32 bits. Que largura de banda do barramento a
CPU consome na pior das hipóteses, ou seja, con-
siderando leituras ou escritas de ponta a ponta o
tempo inteiro?
36. Um computador de 64 bits com um barramento de
400 MHz requer quatro ciclos para ler uma palavra
de 64 bits. Que largura de banda do barramento a
CPU consome na pior das hipóteses, ou seja, con-
siderando leituras ou escritas de ponta a ponta o
tempo inteiro?
37. Uma CPU de 32 bits com linhas de endereço A2–A31
requer que todas as referências à memória sejam alinha-
das. sto é, palavras têm de ser endereçadas em múltiplos
de 4 bytes, meias-palavras têm de ser endereçadas em
bytes pares. Os bytes podem estar em qualquer lugar.
Há quantas combinações legais para leituras de memória
e quantos pinos são necessários para expressá-las? Dê
duas respostas e justifique cada uma com um caso.
38. Chips de CPU modernos possuem um, dois ou até
mesmo três níveis de cache no chip. Por que são
necessários vários níveis de cache?
C a p 
t u l o 3 O n 
v e l l o
 g i c o d i g i t a l 189
39. Suponha que uma CPU tenha uma cache de nível 1
e uma de nível 2, com tempos de acesso de 1 ns e 2
ns, respectivamente. O tempo de acesso à memória
principal é 10 ns. Se 20% dos acessos resultarem
em presença na cache de nível 1 e 60% dos acessos
resultarem em presença na cache de nível 2, qual é o
tempo médio de acesso?
40. Calcule a largura de banda de barramento necessária
para apresentar um filme em cores (1.280 × 960) a
30 quadros por segundo. Considere que os dados
devam passar duas vezes pelo barramento, uma vez do
CD-ROM para a memória e uma vez da memória para
a tela.
41. Qual dos sinais da Figura 3.55 não é estritamente
necessário para o funcionamento do protocolo de
barramento?
42. Um sistema PC Express tem enlaces de 10 Mbps
(capacidade bruta). Quantos fios de sinal são
necessários em cada direção para operação 16x?
Qual é a capacidade bruta em cada direção? Qual é a
capacidade líquida em cada direção?
43. Um computador tem instruções que requerem dois
ciclos de barramento cada: um para buscar a instru-
ção e um para buscar os dados. Cada ciclo de bar-
ramento leva 10 ns e cada instrução leva 20 ns (isto
é, o tempo de processamento interno é desprezível).
O computador também tem um disco com 2.048
setores de 512 bytes por trilha. O tempo de rotação
do disco é 5 ms. A que porcentagem de sua veloci-
dade normal o computador é reduzido durante uma
transferência DMA se cada transferência DMA de 32
bits leva um ciclo de barramento?
44. A carga útil máxima de um pacote de dados isócrono
no barramento USB é 1.023 bytes. Supondo que um
dispositivo pode enviar só um pacote de dados por
quadro, qual é a máxima largura de banda para um
único dispositivo isócrono?
45. Que efeito causaria o acréscimo de uma terceira linha
de entrada sobre uma porta nand selecionando a PO
da Figura 3.61(b) se essa nova linha fosse conectada
a a13?
46. Escreva um programa para simular o comporta-
mento de uma matriz m × n de portas nand com
duas entradas. Esse circuito, contido em um chip,
tem j pinos de entrada e k pinos de saída. Os valores
de j, k, m e n são parâmetros da simulação em tempo
de compilação. O programa deve iniciar lendo em
uma “lista de fiação” onde cada fio especifica uma
entrada e uma saída. Uma entrada é um dos j pinos
de entrada ou a saída de alguma porta nand. Uma
saída ou é um dos k pinos de saída ou uma entrada
para alguma porta nand. Entradas não usadas são 1
lógico. Após ler a lista de fiação, o programa deve
imprimir a saída para cada uma das 2j
entradas pos-
síveis. Chips de porta vetorial como esse são muito
usados para colocar circuitos sob encomenda em
um chip porque a maior parte do trabalho (deposi-
tar o arranjo vetorial no chip) é independente do
circuito a ser executado. Somente a fiação é especí-
fica para cada projeto.
47. Escreva um programa, na sua linguagem de
programação favorita, para ler duas expressões
booleanas quaisquer e verificar se elas represen-
tam a mesma função. A linguagem de entrada deve
incluir letras únicas, como variáveis booleanas, ope-
randos and, or e not, e parênteses. Cada expressão
deve caber em uma linha de entrada. O programa
deve calcular tabelas verdade para ambas as funções
e compará-las.
O
nível acima do lógico digital é o nível de microarquitetura. Sua função é executar o nível SA (nstruction
Set Architecture – arquitetura do conjunto de instruções) acima dele, como ilustrado na Figura 1.2. O
projeto do nível de microarquitetura depende da SA que está sendo implementada, bem como das metas
de custo e desempenho do computador. Muitas SAs modernas, em particular projetos RSC, têm instruções simples
que normalmente podem ser executadas em um único ciclo de clock. SAs mais complexas, como a Core i7, podem
exigir muitos ciclos para executar uma única instrução. Executar uma instrução pode requerer localizar os operan-
dos na memória, ler esses operandos e armazenar resultados de volta na memória. A sequência de operações dentro
de uma única instrução muitas vezes leva a uma abordagem de controle diferente da adotada para SAs simples.
4.1 Um exemplo de microarquitetura
O ideal seria que nós apresentássemos este tópico explicando os princípios gerais do projeto de microar-
quitetura. nfelizmente, não há princípios gerais; cada microarquitetura é um caso especial. Por conseguinte,
resolvemos discutir um exemplo detalhado. Para nossa SA que servirá de exemplo, escolhemos um subconjunto
da Java irtual Machine, como prometemos no Capítulo 1. Esse subconjunto contém somente instruções com
inteiros, portanto, nós o denominamos IJVM para enfatizar que ele trata somente de inteiros.
Começaremos pela descrição da microarquitetura sobre a qual realizaremos a JM, arquitetura que tem
algumas instruções complexas. Muitas dessas arquiteturas costumam ser executadas ao se recorrer à microprogra-
mação, como discutimos no Capítulo 1. Embora a JM seja pequena, é um bom ponto de partida para descrever
o controle e a sequência de instruções.
O n
vel de microarquitetura
4
Cap
tulo
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 191
Nossa microarquitetura conterá um microprograma (em ROM) cuja tarefa é buscar, decodificar e executar instruções
JM. Não podemos usar o interpretador Oracle JM para o microprograma porque precisamos de um microprograma
diminuto, que comande com eficiência portas individuais no hardware propriamente dito. Por comparação, o interpreta-
dor Oracle JM foi escrito em C por questão de portabilidade, e não pode controlar o hardware de forma alguma.
Como o hardware utilizado consiste apenas nos componentes básicos descritos no Capítulo 3, em teoria, se
o leitor entender completamente esse capítulo, deverá estar habilitado a sair e comprar uma sacola de transistores
e montar esse subconjunto da máquina JM. Os estudantes que conseguirem executar essa tarefa com sucesso
ganharão créditos extras (e um exame psiquiátrico completo).
Um modelo conveniente para o projeto de microarquitetura é pensar no projeto como um problema de
programação no qual cada instrução no nível SA é uma função a ser chamada por um programa mestre. Nesse
modelo, o programa mestre é um laço simples, sem fim, que determina uma função a ser invocada, chama a fun-
ção e então começa de novo, algo muito parecido com a Figura 2.3.
O microprograma tem um conjunto de variáveis denominado estado do computador, que pode ser acessado
por todas as funções. Cada função altera ao menos algumas das variáveis que compõem o estado. Por exemplo,
o contador de programa (Program Counter – PC) é parte do estado. Ele indica a localização da memória que
contém a próxima função (isto é, instrução SA) a ser executada. Durante a execução de cada instrução, o PC é
incrementado para indicar a próxima instrução a ser executada.
nstruções JM são curtas e fáceis. Cada instrução tem alguns campos, em geral um ou dois, e cada um
deles tem alguma finalidade específica. O primeiro campo de toda instrução é o opcode (abreviatura de operation
code – código de operação), que identifica a instrução, informando se ela é um ADD ou um BRANCH, ou qualquer
outra coisa. Muitas instruções têm um campo adicional que especifica o operando. Por exemplo, instruções que
acessam uma variável local precisam de um campo que identifique qual variável.
Esse modelo de execução, às vezes denominado ciclo buscar-decodificar-executar, é útil em termos abstratos
e também pode ser a base para execução de SAs como a JM, isto é, que tenham instruções complexas. Logo
adiante, descreveremos como ela funciona, qual é o aspecto da microarquitetura e como ela é controlada pelas
microinstruções; cada uma delas controla o caminho de dados durante um ciclo. A lista de microinstruções forma
o microprograma, que apresentaremos e discutiremos detalhadamente.
4.1.1 O caminho de dados
O caminho de dados é a parte da CPU que contém a ULA, suas entradas e suas saídas. O caminho de dados
de nossa microarquitetura de exemplo é mostrado na Figura 4.1. Embora tenha sido cuidadosamente otimizado
para interpretar programas JM, ele guarda uma razoável semelhança com o caminho de dados usado na maioria
das máquinas. Contém vários registradores de 32 bits, aos quais atribuímos nomes simbólicos como PC, SP e
MDR. Embora alguns desses nomes sejam familiares, é importante entender que esses registradores são acessíveis
apenas no nível de microarquitetura (pelo microprograma). Eles recebem esses nomes porque em geral contêm
um valor correspondente à variável do mesmo nome na arquitetura do nível de SA. A maior parte dos regis-
tradores pode dirigir seu conteúdo para o barramento B. A saída da ULA comanda o deslocador e em seguida o
barramento C, cujo valor pode ser escrito em um ou mais registradores ao mesmo tempo. Por enquanto, não há
nenhum barramento A; incluiremos um mais adiante.
A ULA é idêntica à mostrada nas figuras 3.18 e 3.19. Sua função é determinada por seis linhas de controle. O
segmento de reta diagonal com rótulo “6” na Figura 4.1 indica que há seis linhas de controle de ULA, a saber: F0
e
F1
para determinar a operação da ULA; ENA e ENB para habilitar as entradas individualmente; INVA para inverter
a entrada esquerda e INC para forçar um vai-um para o bit de ordem baixa, somando 1 ao resultado. Contudo,
nem todas as 64 combinações de linhas de controle de ULA fazem algo de útil.
Algumas das combinações mais interessantes são mostradas na Figura 4.2. Nem todas essas funções são
necessárias para a JM, mas, para a JM completa, muitas delas viriam a calhar. Em muitos casos, há várias
possibilidades de conseguir o mesmo resultado. Nessa tabela, + significa “mais” aritmético e – significa “menos”
aritmético; assim, por exemplo, –A significa o complemento de dois de A.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
192
Figura 4.1 Caminho de dados da microarquitetura de exemplo usada neste cap
tulo.
H
Controle do deslocador
Deslocador
ULA
2
N
A B
Barramento B
Barramento C
6
Controle da ULA
Sinais de controle
Registradores
de controle
da memória
Habilitar para barramento B
Escrever barramento C para registrador
De e
para a
memória
principal
Z
SP
LV
CPP
TOS
OPC
PC
MDR
MAR
MBR
A ULA da Figura 4.1 precisa de duas entradas de dados: uma entrada esquerda (A) e uma entrada direita (B). Ligado
à entrada esquerda está um registrador de retenção, H. Ligado à entrada direita está o barramento B, que pode ser carre-
gado por cada uma de nove fontes, indicadas pelas nove setas cinza que chegam até ele. Um projeto alternativo, com dois
barramentos completos, tem um conjunto diferente de opções de projeto e será discutido mais adiante neste capítulo.
H pode ser carregado com a escolha de uma função da ULA que passe diretamente da entrada direita (vinda do
barramento B) para a saída da ULA. Uma função desse tipo seria somar as entradas da ULA, porém, com ENA nega-
do, de modo que a entrada esquerda é forçada a zero. Adicionar zero ao valor no barramento B resulta somente no
valor no barramento B. Então, esse resultado pode ser passado pelo deslocador sem modificação e armazenado em H.
Além das funções citadas, duas outras linhas de controle podem ser usadas independentemente para con-
trolar a saída da ULA. SLL8 (Shift Left Logical) desloca o conteúdo para a esquerda por 1 byte, preenchendo os
8 bits menos significativos com zeros. SRA1 (Shift Right Arithmetic) desloca o conteúdo para a direita por 1 bit,
deixando inalterado o bit mais significativo.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 193
Figura 4.2 Combinac
o
es u
teis de sinais de ULA e a func
a
o executada.
F0
F1
ENA ENB INVA INC Função
0 1 1 0 0 0 A
0 1 0 1 0 0 B
0 1 1 0 1 0 A
1 0 1 1 0 0 B
1 1 1 1 0 0 A + B
1 1 1 1 0 1 A + B + 1
1 1 1 0 0 1 A + 1
1 1 0 1 0 1 B + 1
1 1 1 1 1 1 B – A
1 1 0 1 1 0 B – 1
1 1 1 0 1 1 –A
0 0 1 1 0 0 A AND B
0 1 1 1 0 0 A OR B
0 1 0 0 0 0 0
1 1 0 0 0 1 1
1 1 0 0 1 0 –1
É explicitamente possível ler e escrever o mesmo registrador em um único ciclo. Por exemplo, é permitido
colocar SP no barramento B, desativar a entrada esquerda da ULA, habilitar o sinal INC e armazenar o resultado
em SP, desse modo incrementando SP em 1 (veja a oitava linha na Figura 4.2). Como um registrador pode ser
lido e escrito no mesmo ciclo sem produzir lixo? A solução é que leitura e escrita na verdade são executadas em
instantes diferentes dentro do ciclo. Quando um registrador é selecionado como a entrada direita da ULA, seu
valor é colocado no barramento B no início do ciclo e ali é mantido durante todo o ciclo. Depois, a ULA realiza
seu trabalho, produzindo um resultado que passa pelo deslocador e entra no barramento C. Próximo ao final do
ciclo, quando se sabe que as saídas da ULA e deslocador são estáveis, um sinal de clock ativa o armazenamento do
conteúdo do barramento C e o passa para um ou mais dos registradores. Um deles pode perfeitamente ser aquele
que forneceu sua saída ao barramento B. A temporização exata do caminho de dados possibilita ler e escrever o
mesmo registrador em um único ciclo, como descreveremos a seguir.
Temporizac
a
o do caminho de dados
A temporização desses eventos é mostrada na Figura 4.3. Um pulso curto é produzido no início de cada
ciclo de clock. Ele pode ser derivado do clock principal, como ilustra a Figura 3.20(c). Na borda descendente do
pulso, os bits que comandarão todas as portas são ajustados, o que leva um tempo finito e conhecido, ∆w. Depois,
o registrador necessário no barramento B é selecionado e conduzido até este. Demora ∆x para o valor ficar está-
vel. Então, a ULA e o deslocador começam a operar com dados válidos. Após outro ∆y, as saídas da ULA e do
deslocador estão estáveis. Após um ∆z adicional, os resultados se propagaram ao longo do barramento C até os
registradores, onde podem ser carregados na borda ascendente do próximo pulso. A carga deve ser acionada pela
borda ascendente do próximo pulso e de forma rápida, de modo que, se alguns dos registradores de entrada forem
alterados, o efeito não será sentido no barramento C até muito tempo após os registradores terem sido carregados.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
194
Também na borda ascendente do pulso, o registrador que comanda o barramento B para de fazê-lo preparando-
-se para o próximo ciclo. MPC, MIR e a memória são mencionados na figura; em breve, discutiremos seus papéis.
É importante perceber que, ainda que não haja nenhum elemento de armazenamento no caminho de dados,
há um tempo de propagação finito por ele. Uma alteração de valor no barramento B só provocará uma alteração
no barramento C após um tempo finito (por causa dos atrasos finitos de cada etapa). Por conseguinte, mesmo que
um armazenamento altere um dos registradores de entrada, o valor estará guardado em segurança no registrador
muito antes que o valor (agora incorreto) que está sendo colocado no barramento B (ou H) possa alcançar a ULA.
Fazer esse esquema funcionar requer rígida temporização, um ciclo de clock longo, um tempo mínimo de
propagação pela ULA conhecido e uma carga rápida dos registradores pelo barramento C. Contudo, com cuida-
dosa engenharia, o caminho de dados pode ser projetado de modo que funcione corretamente o tempo todo. Na
verdade, as máquinas reais funcionam desse modo.
Um modo um pouco diferente de ver o ciclo de caminho de dados é imaginá-lo fragmentado em subciclos
implícitos. O início do subciclo 1 é acionado pela borda descendente do clock. As atividades que ocorrem durante
os subciclos são mostradas a seguir, junto com as extensões dos subciclos (entre parênteses).
1. Os sinais de controle são ajustados (∆w).
2. Os registradores são carregados no barramento B (∆x).
3. Operação da ULA e deslocador (∆y).
4. Os resultados se propagam ao longo do barramento C de volta aos registradores (∆z).
O intervalo de tempo após ∆z oferece alguma tolerância, pois os tempos não são exatos. Na borda ascendente
do próximo ciclo de clock, os resultados são armazenados nos registradores.
Dissemos que é melhor imaginar os subciclos como implícitos. Com isso, queremos dizer que não há nenhum
pulso de clock ou outros sinais explícitos que indiquem à ULA quando operar ou que digam aos resultados que
entrem no barramento C. Na verdade, a ULA e o deslocador funcionam o tempo todo. Contudo, suas entradas
são lixo até um tempo ∆w + ∆x após a borda descendente do clock. Do mesmo modo, suas saídas são lixo até que
∆w + ∆x + ∆y tenha transcorrido após a borda descendente do clock. Os únicos sinais explícitos que comandam
Figura 4.3 Diagrama de temporizac
a
o de um ciclo de caminho de dados.
Ciclo 1
começa
aqui
Saída do
deslocador
estável
Registradores carregados
instantaneamente do
barramento C e da memória
na borda ascendente do clock
Prepara
sinais para
comandar
o caminho
de dados
ULA e
deslocador
Drive H e
barramento B
Propagação
do deslocador
aos registradores
∆w ∆x ∆y ∆z
Ciclo de clock 1 Ciclo de clock 2
MPC
disponível
aqui
Novo MPC usado para
carregar MIR com a próxima
microinstrução aqui
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 195
o caminho de dados são a borda descendente do clock, que inicia o ciclo do caminho de dados, e a borda ascen-
dente, que carrega os registradores a partir do barramento C. As outras fronteiras de subciclos são determinadas
implicitamente pelos tempos de propagação inerentes dos circuitos envolvidos. Cabe aos engenheiros de projeto
garantir que o tempo ∆w + ∆x + ∆y + ∆z venha suficientemente antes da borda ascendente do clock para fazer as
cargas de registrador funcionarem de modo confiável o tempo todo.
Operac
a
o de memo
ria
Nossa máquina tem dois modos diferentes de se comunicar com a memória: uma porta de memória de 32
bits, endereçável por palavra, e outra de 8 bits, endereçável por byte. A porta de 32 bits é controlada por dois
registradores, MAR (Memory ddress Register  registrador de endereço de memória) e MDR (Memory ata
Register  registrador de dados de memória), como mostra a Figura 4.1. A porta de 8 bits é controlada por um
registrador, PC, que lê 1 byte para os 8 bits de ordem baixa do MBR. Essa porta só pode ler dados da memória;
ela não pode escrever dados na memória.
Cada um desses registradores (e todos os outros na Figura 4.1) é comandado por um ou dois sinais de con-
trole. Uma seta clara sob um registrador indica um sinal de controle que habilita a saída do registrador para o
barramento B. isto que MAR não tem conexão com o barramento B, não tem sinal de habilitação. H também não
tem esse sinal porque está sempre habilitado, por ser a única entrada esquerda possível da ULA.
Uma seta negra sob um registrador indica um sinal de controle que escreve (isto é, carrega) o registrador a
partir do barramento C. Uma vez que MBR não pode ser carregado a partir do barramento C, não tem um sinal
de escrita (embora tenha dois outros sinais de habilitação, descritos mais adiante). Para iniciar uma leitura ou
escrita da memória, os registradores de memória adequados devem ser carregados e em seguida deve ser emitido
um sinal de leitura ou escrita para a memória (não mostrado na Figura 4.1).
MAR contém endereços de palavras, de modo que os valores 0, 1, 2 etc. se referem a palavras consecutivas. PC
contém endereços de bytes, portanto, os valores 0, 1, 2 etc. se referem a bytes consecutivos. Assim, colocar um 2 em
PC e iniciar uma leitura de memória lerá o byte 2 da memória e o colocará nos 8 bits de ordem baixa do MBR. Colocar
2 em MAR e iniciar uma leitura de memória lerá os bytes 8–11 (isto é, palavra 2) da memória e os colocará em MDR.
Essa diferença de funcionalidade é necessária porque MAR e PC serão usados para referenciar duas partes
diferentes da memória. A necessidade dessa distinção ficará mais clara adiante. Por enquanto, basta dizer que
a combinação MAR/MDR é usada para ler e escrever palavras de dados de nível SA e a combinação PC/MBR é
empregada para ler o programa executável de nível SA, que consiste em uma sequência de bytes. Todos os outros
registradores que contêm endereços usam endereço de palavras, como o MAR.
Na implementação física propriamente dita, há apenas uma memória real que funciona com bytes. Permitir que
MAR conte palavras (isso é necessário por causa do modo como a JM é definida) enquanto a memória física conta bytes
depende de um truque simples. Quando o MAR é colocado no barramento de endereço, seus 32 bits não são mapeados
diretamente para as 32 linhas de endereço, 0–31. Em vez disso, o bit 0 do MAR é ligado à linha 2 do barramento de
endereço, o bit 1 do MAR é ligado à linha 3 do barramento de endereço e assim por diante. Os 2 bits superiores do MAR
são descartados, visto que só são necessários para endereços de palavra acima de 232
, nenhum dos quais é válido para
nossa máquina de 4 GB. Usando esse mapeamento, quando MAR é 1, o endereço 4 é colocado no barramento; quando
MAR é 2, o endereço 8 é colocado no barramento e assim por diante. Esse estratagema está ilustrado na Figura 4.4.
Como já mencionamos, dados lidos da memória por uma porta de memória de 8 bits são devolvidos em MBR,
um registrador de 8 bits. MBR pode ser copiado (gated) para o barramento B por um entre dois modos: com ou sem
sinal. Quando é preciso o valor sem sinal, a palavra de 32 bits colocada no barramento B contém o valor MBR nos 8
bits de ordem baixa e zeros nos 24 bits superiores. alores sem sinal são úteis para indexar em uma tabela ou quando
um inteiro de 16 bits tem de ser montado a partir de 2 bytes consecutivos (sem sinal) na sequência de instrução.
A outra opção para converter o MBR de 8 bits em uma palavra de 32 bits é tratá-lo como um valor com
sinal entre –128 e +127 e usar esse valor para gerar uma palavra de 32 bits com o mesmo valor numérico. Essa
conversão é feita duplicando o bit de sinal do MBR (o bit mais à esquerda) nas 24 posições superiores de bits do
barramento B, um processo denominado extensão de sinal. Quando essa opção é escolhida, os 24 bits superiores
serão todos 0s ou todos 1s, dependendo do bit mais à esquerda do MBR de 8 bits ser um 0 ou um 1.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
196
Figura 4.4 Mapeamento dos bits em MAR para o barramento de enderec
o.
Descartados
MAR de 32 bits (contagem em palavras)
Barramento de endereço de 32 bits (contagem em bytes)
0 0
A opção de converter o MBR de 8 bits em um valor de 32 bits com sinal ou sem sinal no barramento B é
determinada por qual dos dois sinais de controle (setas claras sob MBR na Figura 4.1) for ativado. A necessidade
dessas duas opções é a razão de haver duas setas presentes. A capacidade de fazer o MBR de 8 bits agir como uma
fonte de 32 bits para o barramento B é indicada pelo retângulo tracejado na figura.
4.1.2 Microinstruc
o
es
Para controlar o caminho de dados da Figura 4.1 precisamos de 29 sinais, que podem ser divididos em cinco
grupos funcionais, como descreveremos a seguir:
9 sinais para controlar escrita de dados do barramento C para registradores.
9 sinais para controlar habilitação de registradores dirigidos ao barramento B para a entrada da ULA.
8 sinais para controlar as funções da ULA e do deslocador.
2 sinais (não mostrados) para indicar leitura/escrita na memória via MAR/MDR.
1 sinal (não mostrado) para indicar busca na memória via PC/MBR.
Os valores desses 29 sinais de controle especificam as operações para um ciclo do caminho de dados. Um ciclo
consiste em copiar valores dos registradores para o barramento B, propagar os sinais pela ULA e pelo deslocador,
dirigi-los ao barramento C e, por fim, escrever os resultados no registrador ou registradores adequados. Além disso,
se um sinal de leitura de dados da memória for ativado, a operação de memória é iniciada no final do ciclo de cami-
nho de dados, após o MAR ter sido carregado. Os dados da memória estão disponíveis no final do ciclo seguinte em
MBR ou MDR e podem ser usados no ciclo que vem depois daquele. Em outras palavras, uma leitura de memória em
qualquer porta iniciada no final do ciclo k entrega dados que não podem ser usados no ciclo k + 1, porém, somente
no ciclo k + 2 ou mais tarde.
Esse comportamento que parece anti-intuitivo é explicado pela Figura 4.3. Os sinais de controle da memória
não são gerados no ciclo de clock 1 até que MAR e PC sejam carregados na borda ascendente do clock, próximo
ao final do ciclo de clock 1. Consideraremos que a memória coloca seus resultados nos barramentos de memória
dentro de um ciclo, portanto, que MBR e/ou MDR podem ser carregados na próxima borda ascendente do clock,
junto com os outros registradores.
Em outras palavras, carregamos MAR no final de um ciclo de caminho de dados e iniciamos a memória logo
após. Por conseguinte, na realidade não podemos esperar que os resultados de uma operação de leitura estejam
em MDR no início do próximo ciclo, em especial se a largura do pulso de clock for curta. Não há tempo suficiente
se a memória demora um ciclo de clock. Um ciclo de caminho de dados deve ser interposto entre o início de uma
leitura de memória e a utilização do resultado. É claro que outras operações podem ser executadas durante aquele
ciclo, mas não as que necessitam da palavra de memória.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 197
Supor que a memória leva um ciclo para operar equivale a supor que a taxa de presença na cache de nível 1
é 100%. Essa suposição nunca é verdadeira, mas a complexidade introduzida por um tempo de ciclo de memória
de duração variável é mais do que o que queremos discutir aqui.
Uma vez que MBR e MDR são carregados na borda ascendente do clock, com todos os outros registradores,
eles podem ser lidos durante ciclos em que está sendo realizada uma nova leitura de memória. Eles retornam aos
valores antigos, já que a leitura ainda não teve tempo de sobrescrevê-los. Aqui não há ambiguidade alguma; até
que novos valores sejam carregados em MBR e MDR na borda ascendente do clock, os precedentes ainda estão ali
e podem ser usados. Note que é possível fazer leituras seguidas em dois ciclos consecutivos, uma vez que uma
leitura leva apenas um. Além disso, ambas as memórias podem funcionar ao mesmo tempo. Contudo, tentar ler
e escrever o mesmo byte em simultâneo gera resultados indefinidos.
Embora talvez seja desejável escrever a saída no barramento C em mais de um registrador, nunca é aconselhável
habilitar mais de um por vez no barramento B. Na verdade, algumas implementações reais sofrerão dano físico se isso
for feito. Com um pequeno aumento no conjunto de circuitos podemos reduzir o número de bits necessários para
selecionar entre as possíveis fontes para comandar o barramento B. Há somente nove registradores de entrada possí-
veis que podem comandar o barramento B (onde cada versão do MBR com sinal e sem sinal é contada como uma ver-
são individual). Portanto, podemos codificar as informações do barramento B em 4 bits e usar um decodificador para
gerar os 16 sinais de controle, sete dos quais não são necessários. Em um projeto comercial, os arquitetos seriam ata-
cados por um desejo desesperado de se livrar de um dos registradores de modo que 3 bits fizessem o trabalho. Como
acadêmicos, podemos nos dar ao enorme luxo de desperdiçar 1 bit para obter um projeto mais limpo e mais simples.
Nesse ponto, podemos controlar o caminho de dados com 9 + 4 + 8 + 2 + 1 = 24 sinais, daí 24 bits. Contudo,
esses 24 bits só controlam o caminho de dados por um ciclo. A segunda parte do controle é determinar o que fazer
no ciclo seguinte. Para incluir isso no projeto do controlador, criaremos um formato para descrever as operações a
serem realizadas usando os 24 bits de controle mais dois campos adicionais: NEXT_ADDRESS e JAM. O conteúdo
de cada um desses campos será discutido em breve. A Figura 4.5 mostra um formato possível, dividido em seis
grupos (listados abaixo da instrução) e contendo os seguintes 36 sinais:
Addr – Contém o endereço de uma microinstrução potencial seguinte.
JAM – Determina como a próxima microinstrução é selecionada.
ULA – Funções da ULA e do deslocador.
C – Seleciona quais registradores são escritos a partir do barramento C.
Mem – Funções de memória.
B – Seleciona a fonte do barramento B; é codificado como mostrado.
A ordem dos grupos é, em princípio, arbitrária, embora na verdade a tenhamos escolhido com muito cuidado
para minimizar cruzamentos de linhas na Figura 4.6. Cruzamentos de linhas em diagramas esquemáticos como
essa figura costumam corresponder a cruzamento de fios em chips, o que causa problemas em projetos bidimen-
sionais, portanto, é melhor minimizá-los.
Figura 4.5 Formato da microinstruc
a
o para a Mic-1 (descrita em breve adiante).
Bits 9 3 8 9 3 4
NEXT_ADDRESS
Addr JAM ULA C Mem B
R
E
A
D
F
E
T
C
H
J
A
M
N
J
M
P
C
J
A
M
Z
S
L
L
8
S
R
A
1
F0 F1 E
N
A
E
N
B
I
N
V
A
I
N
C
H O
P
C
T
O
S
C
P
P
L
V
S
P
P
C
M
D
R
M
A
R
W
R
I
T
E
Barra-
mento
B
Registradores do barramento B
0 = MDR 1 = PC 2 = MBR 3 = MBRU 4 = SP 5 = LV 6 = CPP 7 = TOS 8 = OPC 9-15 nenhum
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
198
Figura 4.6 Diagrama de blocos completo de nossa microarquitetura de exemplo, a Mic-1.
H
Deslocador
ULA
2
N
Barramento B
6
Controle
da ULA
Sinais de
controle
Sinais de controle de memória (rd, wr, fetch)
Habilita para
barramento B
Escreve
barramento C
no registrador
Z
Barramento C
SP
LV
CPP
TOS
OPC
PC
MDR
MAR
MBR
9
O
Armazenamento de controle
de 512 × 36 bits para conter
o microprograma
3
8
Decodicador
4 para 16
2
9
4
MPC
MIR
Addr J ULA C M B
Flip-op de 1 bit
Bit
alto
JMPC
JAMN/JAMZ
4.1.3 Controle de microinstruc
a
o: a Mic-1
Até aqui, descrevemos como o caminho de dados é controlado, mas ainda não explicamos como é decidido
qual dos sinais de controle deve ser habilitado em cada ciclo. sso é determinado por um sequenciador, que é
responsável por escalonar a sequência de operações necessárias para a execução de uma única instrução SA.
O sequenciador deve produzir dois tipos de informação a cada ciclo:
1. O estado de cada sinal de controle no sistema.
2. O endereço da microinstrução que deve ser executada em seguida.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 199
A Figura 4.6 é um diagrama de blocos detalhado da microarquitetura completa de nossa máquina de exem-
plo, que denominaremos Mic-1. Ela pode parecer imponente de início, mas vale a pena estudá-la com cuidado.
Quando você entender totalmente cada retângulo e cada linha dessa figura, terá avançado bastante no entendi-
mento do nível de microarquitetura. O diagrama de blocos tem duas partes: o caminho de dados, à esquerda, que
já discutimos em detalhes, e a seção de controle, à direita, que estudaremos agora.
O maior item e também o mais importante na parte do controle da máquina é uma memória denominada
armazenamento de controle. É conveniente imaginá-la como uma memória que contém o microprograma com-
pleto, embora às vezes ele seja executado como um conjunto de portas lógicas. Em geral, vamos nos referir a ele
como o armazenamento de controle para evitar confusão com a memória principal, acessada por meio de MBR e
MDR. Contudo, em termos funcionais, o armazenamento de controle é uma memória que apenas contém microins-
truções em vez de instruções SA. No caso da nossa máquina de exemplo, ele contém 512 palavras, cada uma con-
sistindo em uma microinstrução de 36 bits do tipo ilustrado na Figura 4.5. Na verdade, nem todas essas palavras
são necessárias, mas (por razões que explicaremos em breve) precisamos de endereços para 512 palavras distintas.
Em um aspecto importante, o armazenamento de controle é bem diferente da memória principal: instruções
na memória principal são sempre executadas em ordem de endereço (exceto para os desvios); microinstruções
não são. O ato de incrementar o contador de programa na Figura 2.3 expressa o fato de que a instrução padrão
(default) a executar após a instrução corrente é a instrução seguinte àquela corrente na memória. Microprogramas
precisam de mais flexibilidade (porque as sequências de microinstruções tendem a ser curtas), e, portanto, não
costumam ter essa propriedade. Em vez disso, cada microinstrução especifica explicitamente sua sucessora.
Uma vez que, em termos funcionais, o armazenamento de controle é uma memória (só de leitura), ele pre-
cisa de seu próprio registrador de endereço de memória e de seu próprio registrador de dados de memória. Não
precisa ler nem escrever sinais porque está sendo lido continuamente. Denominaremos o registrador de endereço
de memória do armazenamento de controle MPC (MicroProgram Counter  contador de microprograma). Esse
nome é irônico, já que as localizações nele são explicitamente não ordenadas, portanto, o conceito de contagem
não é útil (mas quem somos nós para discutir uma tradição?). O registrador de dados de memória é denominado
MIR (MicroInstruction Register  registrador de microinstrução). Sua função é conter a microinstrução corren-
te, cujos bits comandam os sinais de controle que operam o caminho de dados.
O registrador MIR na Figura 4.6 contém os mesmos seis grupos da Figura 4.5. Os grupos Addr e J (de JAM)
controlam a seleção da microinstrução seguinte e serão discutidos em breve. O grupo ULA contém os 8 bits que
selecionam a função ULA e comandam o deslocador. Os bits C fazem os registradores individuais carregarem a
saída da ULA vinda do barramento C. Os bits M controlam operações de memória.
Por fim, os últimos 4 bits comandam o decodificador que determina o que entra no barramento B. Nesse caso,
preferimos usar um decodificador padrão 4 para 16, mesmo que sejam requeridas apenas nove possibilidades. Em um
projeto mais afinado, poderia ser usado um decodificador 4 para 9. Nesse caso, o compromisso é usar um circuito
padrão que possa ser encontrado em uma biblioteca de circuitos em vez de projetar um circuito fabricado sob espe-
cificação. Usar o circuito padrão é mais simples e a probabilidade de introduzir bugs é menor. Construir seu próprio
circuito usa menos área de chip, mas leva mais tempo para projetar e há sempre a possibilidade de você errar.
A operação da Figura 4.6 é a seguinte. No início de cada ciclo de clock (a borda descendente na Figura 4.3),
MIR é carregado a partir da palavra no armazenamento de controle apontada pelo MPC. O tempo de carga do MIR
é indicado na figura por ∆w. Se pensarmos em termos de subciclos, MIR é carregado durante o primeiro.
Assim que a microinstrução é estabelecida em MIR, os vários sinais se propagam para dentro do caminho de
dados. Um registrador é copiado para o barramento B, a ULA sabe qual operação realizar e a atividade é frenética.
Esse é o segundo subciclo. Após um intervalo ∆w + ∆x a partir do início do ciclo, as entradas da ULA estão estáveis.
Após mais um ∆y, tudo se acomoda e as saídas da ULA, N, Z e do deslocador estão estáveis. Então, os valores
N e Z são salvos em um par de flip-flops de 1 bit. Esses bits, como os registradores que são carregados a partir do
barramento C e na memória, são salvos na borda ascendente do clock, próximo ao final do ciclo do caminho de
dados. A saída da ULA não é serializada, mas apenas alimentada no deslocador. A atividade da ULA e do deslo-
cador ocorre durante o subciclo 3.
Após um intervalo adicional, ∆z, a saída do deslocador alcançou os registradores via barramento C. Então,
estes podem ser carregados perto do final do ciclo (borda ascendente do pulso de clock na Figura 4.3). O subciclo
4 consiste em carregar os registradores e flip-flops N e Z e termina um pouco após a borda ascendente do clock,
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
200
quando todos os resultados foram salvos e os produtos das operações de memória anteriores estão disponíveis e
o MPC foi carregado. O processo continua até alguém se entediar e desligar a máquina.
Em paralelo com o comando do caminho de dados, o microprograma tem de determinar qual microinstru-
ção executar em seguida, porque elas precisam ser executadas na ordem em que aparecem no armazenamento de
controle. O cálculo do endereço da próxima microinstrução começa após MIR ter sido carregado e estar estável.
Primeiro, o campo NEXT_ADDRESS de 9 bits é copiado para MPC. Enquanto essa cópia está ocorrendo, o campo
JAM é inspecionado. Se tiver valor 000, nada mais é feito; quando a cópia de NEXT_ADDRESS estiver concluída,
o MPC apontará a próxima microinstrução.
Se um ou mais dos bits JAM for 1, é preciso mais trabalho. Se JAMN estiver ativado, o flip-flop N de 1 bit sofre
uma operação OR com o bit de ordem alta do MPC. De modo semelhante, se JAMZ estiver ativado, é o flip-flop
Z de 1 bit que passa pela operação OR. Se ambos estiverem ajustados, ambos passam por OR. A razão de os flip-
-flops N e Z serem necessários é que, após a borda ascendente do clock (enquanto o clock está alto), o barramento
B não está mais sendo comandado, portanto, as saídas da ULA não podem mais ser tomadas como corretas. Salvar
os flags de estado da ULA em N e Z torna os valores corretos disponíveis e estáveis para o cálculo do MPC, não
importa o que esteja ocorrendo na ULA.
Na Figura 4.6, a lógica que faz tal cálculo é denominada “bit alto”. A função booleana que ela calcula é
F = (JAMZ AND Z) OR (JAMN AND N) OR NEXT_ADDRESS[8]
Note que, em todos os casos, MPC só pode assumir um de dois valores possíveis:
1. O valor de NEXT_ADDRESS.
2. O valor de NEXT_ADDRESS com o bit de ordem alta que passa por uma operação OR com 1.
Não existe nenhuma outra possibilidade. Se o bit de ordem alta de NEXT_ADDRESS já for 1, usar JAMN ou
JAMZ não tem sentido.
Note que, quando os bits JAM são todos zeros, o endereço da próxima microinstrução a ser executada é
simplesmente o número de 9 bits em seu campo NEXT_ADDRESS. Quando ou JAMN ou JAMZ é 1, há dois
sucessores potenciais: NEXT_ADDRESS e NEXT_ADDRESS com operação OR com 0x100 (considerando que
NEXT_ADDRESS ≤ 0xFF). (Note que 0x indica que o número que vem em seguida está em hexadecimal.) Esse
ponto é ilustrado na Figura 4.7. A microinstrução corrente, na localização 0x75, tem NEXT_ADDRESS = 0x92
e JAMZ ajustado para 1. Por conseguinte, o próximo endereço da microinstrução depende do bit Z armazenado
durante a operação de ULA anterior. Se o bit Z for 0, a próxima microinstrução vem de 0x92. Se o bit Z for 1, a
próxima microinstrução vem de 0x192.
O terceiro bit no campo JAM é JMPC. Se ele estiver ativado, os 8 bits MBR passam por uma operação OR bit
a bit com os 8 bits de ordem baixa do campo NEXT_ADDRESS que vem da microinstrução corrente. O resultado é
enviado a MPC. O retângulo com o rótulo “O” na Figura 4.6 faz uma OR de MBR com NEXT_ADDRESS se JMPC
for 1, mas apenas passa NEXT_ADDRESS diretamente para MPC se JMPC for 0. Quando JMPC é 1, os 8 bits de
ordem baixa de NEXT_ADDRESS em geral são zero. O bit de ordem alta pode ser 0 ou 1, portanto, o valor de
NEXT_ADDRESS usado com JMPC normalmente é 0x000 ou 0x100. A razão para usar às vezes 0x000 e às vezes
0x100 será discutida mais adiante.
A capacidade de efetuar OR entre MBR e NEXT_ADDRESS e armazenar o resultado em MPC permite uma
execução eficiente de um desvio (jump) multivias. Note que qualquer um dos 256 endereços pode ser especifica-
do, determinado exclusivamente pelos bits presentes em MBR. Em uma utilização típica, MBR contém um código
de operação, que chamaremos de opcode, portanto, a utilização de JMPC resultará em uma seleção única para a
próxima microinstrução a ser executada para todo opcode possível. Esse método é útil para fazer desvios rápidos
diretamente para a função correspondente ao opcode que acabou de ser buscado.
Entender a temporização da máquina é crítico para o que vem a seguir, portanto, talvez valha a pena repeti-
-la. Faremos isso em termos de subciclos, uma vez que é fácil de visualizar, mas os únicos eventos de clock reais
são a borda descendente, que inicia o ciclo, e a borda ascendente, que carrega os registradores e os flip-flops N
e Z. Favor consultar a Figura 4.3 mais uma vez.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 201
Figura 4.7 Microinstruc
a
o com JAMZ ajustado para 1 tem duas sucessoras potenciais.
…
…
Endereço Addr Bits de controle do caminho de dados
Um desses
virá após 0x75
dependendo de Z
JAM
Bit JAMZ ajustado
0x75 0x92
0x92
0x192
001
Durante o subciclo 1, iniciado pela borda descendente do clock, MIR é carregado a partir do endereço con-
tido em MPC no instante em questão. Durante o subciclo 2, os sinais de MIR se propagam e o barramento B é
carregado a partir do registrador selecionado. Durante o subciclo 3, a ULA e o deslocador funcionam e produzem
um resultado estável. Durante o subciclo 4, os valores do barramento C, dos barramentos de memória e da ULA
tornam-se estáveis. Na borda ascendente do clock, os registradores são carregados a partir do barramento C, flip-
-flops N e Z são carregados e MBR e MDR obtêm seus resultados da operação de memória iniciada no final do ciclo
de caminho de dados anterior (se houver algum). Assim que o valor de MBR estiver disponível, MPC é carregado
em preparação para a próxima microinstrução. Assim, MPC obtém seu valor em algum instante durante o meio do
intervalo quando o clock está alto, mas após MBR/MDR estarem prontos. Ele poderia ser ativado no nível (em vez
de ativado pela borda) ou ativado pela borda com um atraso fixo após a borda ascendente do clock. O que real-
mente importa é que MPC não seja carregado até que os registradores dos quais ele depende (MBR, N e Z) estejam
prontos. Tão logo o clock caia, MPC pode endereçar o armazenamento de controle e um novo ciclo pode começar.
Note que cada ciclo é autossuficiente. Ele especifica o que ocorre no barramento B, o que a ULA e o deslo-
cador têm de fazer, onde o barramento C deve ser armazenado e, por fim, qual deve ser o próximo valor de MPC.
ale a pena fazer uma observação final sobre a Figura 4.6. Estamos tratando o MPC como um registrador
propriamente dito, com 9 bits de capacidade de armazenamento, que é carregado enquanto o clock está alto.
Na realidade, não há necessidade alguma de um registrador ali. Todas as suas entradas podem ser alimentadas
diretamente para o armazenamento de controle. Basta que elas estejam presentes no armazenamento de contro-
le na borda descendente do clock quando MIR é selecionado e lido. Na verdade, não há necessidade alguma de
armazená-las em MPC. Por essa razão, o MPC pode perfeitamente ser executado como um registrador virtual, que
é apenas um lugar de reunião para sinais, mais como se fosse um painel de conexão eletrônico do que um regis-
trador real. Transformar o MPC em um registrador virtual simplifica a temporização: agora, os eventos acontecem
somente nas bordas descendentes e ascendentes do clock e em nenhum outro lugar. Porém, se for mais fácil para
você imaginar um MPC como um registrador real, esse ponto de vista também é válido.
4.2 Exemplo de ISA: IJVM
amos continuar nosso exemplo introduzindo o nível SA da máquina a ser interpretado pelo microprogra-
ma que é executado na microarquitetura da Figura 4.6 (JM). Por conveniência, às vezes vamos nos referir a
nstruction Set Architecture (SA) como a macroarquitetura, para contrastá-la com a microarquitetura. Contudo,
antes de descrever a JM, vamos fazer uma ligeira digressão com o intuito de motivação.
4.2.1 Pilhas
Praticamente todas as linguagens de programação trabalham com o conceito de procedimentos (métodos),
que têm variáveis locais. Essas variáveis podem ser acessadas de dentro dos procedimentos, mas deixam de ser
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
202
acessíveis assim que o procedimento é devolvido. Portanto, surge a pergunta: “Em que lugar da memória essas
variáveis devem ser mantidas?”.
A solução mais simples, dar a cada variável um endereço de memória absoluto, não funciona. O problema é
que um procedimento pode chamar a si mesmo. Estudaremos esses procedimentos recursivos no Capítulo 5. Por
enquanto, basta dizer que, se um procedimento for ativado – isto é, chamado – duas vezes, é impossível armaze-
nar suas variáveis em localizações absolutas de memória porque a segunda chamada irá interferir com a primeira.
Em vez disso, é usada uma estratégia diferente. Uma área da memória, denominada pilha, é reservada para
variáveis, mas variáveis individuais não obtêm endereços absolutos nela. Em vez disso, um registrador, por exem-
plo, LV, é preparado para apontar para a base das variáveis locais para o procedimento em questão. Na Figura
4.8(a), um procedimento A, que tem variáveis locais a1, a2 e a3, foi chamado, portanto, foi reservado armazena-
mento para suas variáveis locais, começando na localização de memória apontada por LV. Outro registrador, SP,
aponta para a palavra mais alta das variáveis locais de A. Se LV for 100 e as palavras tiverem 4 bytes, então SP será
108. ariáveis são referenciadas dando seu deslocamento (distância) em relação a LV. A estrutura de dados entre
LV e SP (e incluindo ambas as palavras apontadas) é denominada quadro de variáveis locais de A.
Figura 4.8 Utilizac
a
o de uma pilha para armazenar varia
veis locais. (a) Enquanto A esta
 ativo. (b) Apo
s A chamar B. (c) Apo
s B chamar
C. (d) Apo
s C e B retornarem e A chamar D.
SP
LV
a3
a1
(a)
108
100
a2 104
SP
LV
a3
a1
(b)
a2
b3
b4
b1
b2
a3
a1
(c)
a2
b3
b4
LV c1
SP c2
b1
b2
LV
a3
a1
(d)
a2
d3
d4
SP d5
d1
d2
Agora, vamos considerar o que acontece se A chamar outro procedimento, B. Onde deveriam ser armaze-
nadas as quatro variáveis locais de B (b1, b2, b3, b4)? Resposta: na pilha, em cima das variáveis de A, conforme
mostra a Figura 4.8(b). Observe que LV foi ajustado pela chamada de procedimento para que aponte para as
variáveis locais de B em vez das de A. As variáveis locais de B podem ser referenciadas dando seu deslocamento
em relação a LV. De modo semelhante, se B chamar C, LV e SP são ajustados novamente para alocar espaço para
as duas variáveis de C, como mostra a Figura 4.8(c).
Quando C retorna, B torna-se ativo de novo e a pilha volta a ser ajustada para a Figura 4.8(b), de modo que
LV agora aponta outra vez para as variáveis locais de B. Da mesma forma, quando B retorna, voltamos à situação
da Figura 4.8(a). Sob todas as condições, LV aponta para a base do quadro da pilha para o procedimento ativo no
momento em questão e SP aponta para o topo do quadro da pilha.
Agora, suponha que A chama D, que tem cinco variáveis locais. Essa é a situação da Figura 4.8(d), na qual
as variáveis locais de D usam a mesma memória que as de B usaram, bem como parte das de C. Com essa orga-
nização, a memória só é alocada para procedimentos que estão ativos no momento em questão. Quando um
procedimento retorna, a memória usada por suas variáveis locais é liberada.
Pilhas têm outra utilização além de conter variáveis locais. Elas podem ser usadas para reter operandos
durante o cálculo de uma expressão aritmética. Quando usada dessa maneira, a pilha é denominada pilha de
operandos. Suponha, por exemplo, que, antes de chamar B, A tenha de calcular
a1 = a2 + a3;
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 203
Um modo de efetuar essa soma é passar a2 para a pilha, como ilustra a Figura 4.9(a). Nesse caso, SP foi incre-
mentado pelo número de bytes em uma palavra, por exemplo, 4, e o primeiro operando foi armazenado no endereço
agora apontado por SP. Em seguida, a3 é passada para a pilha, conforme mostra a Figura 4.9(b). (Como parte da
notação, usaremos uma fonte Helvetica para todos os fragmentos de programa, como fizemos anteriormente. Também
usaremos essa fonte para opcodes em linguagem de montagem e registradores de máquina, mas, em texto corrente,
variáveis de programa e procedimentos serão dados em itálico. A diferença é que nomes de variáveis de programas e
nomes de procedimento são escolhidos pelo usuário; nomes de opcodes e registradores vêm com a máquina.)
Figura 4.9 Utilizac
a
o de uma pilha de operandos para efetuar um ca
lculo aritme
tico.
LV
a3
SP a2
a1
(a)
a2
LV
a3
a2
SP a3
a1
(b)
a2
LV
a3
SP a2 + a3
a1
(c)
a2
LV
SP a3
a2 + a3
(d)
a2
Agora, o cálculo propriamente dito pode ser feito executando uma instrução que retira duas palavras da
pilha, soma as duas e devolve o resultado para a pilha, conforme a Figura 4.9(c). Por fim, a palavra que está no
topo pode ser retirada da pilha e armazenada de novo na variável local a1, como ilustrado na Figura 4.9(d).
Os quadros de variáveis locais e as pilhas de operandos podem ser misturados. Por exemplo, ao calcular uma
expressão como x2
+ f(x), parte dela (por exemplo, x2
) pode estar em uma pilha de operandos quando a função f é
chamada. O resultado da função é deixado na pilha, em cima de x2
, de modo que a próxima instrução pode somá-la.
ale a pena observar que, enquanto todas as máquinas usam uma pilha para armazenar variáveis locais, nem
todas usam uma pilha de operandos como essa para efetuar aritmética. Na verdade, a maioria delas não usa, mas
a JM e a JM trabalham assim, e é por isso que apresentamos aqui as operações com a pilha. amos estudá-las
com mais detalhes no Capítulo 5.
4.2.2 Modelo de memo
ria IJVM
Agora, estamos prontos para estudar a arquitetura da JM. Em essência, ela consiste em uma memória que
pode ser vista de dois modos: um arranjo de 4.294.967.296 bytes (4 GB) ou um arranjo de 1.073.741.824 pala-
vras, cada uma consistindo em 4 bytes. Diferente da maioria das SAs, a Java irtual Machine (máquina virtual
Java) não deixa nenhum endereço absoluto de memória diretamente visível no nível SA, mas há vários endereços
implícitos que fornecem a base para um ponteiro. nstruções JM só podem acessar a memória indexando a
partir desses ponteiros. Em qualquer instante, as seguintes áreas de memória são definidas:
1. O conjunto de constantes. Essa área não pode ser escrita por um programa JM e consiste em constan-
tes, cadeias e ponteiros para outras áreas da memória que podem ser referenciadas. Ele é carregado
quando o programa é trazido para a memória e não é alterado depois. Há um registrador implícito,
CPP, que contém o endereço da primeira palavra do conjunto de constantes.
2. O quadro de variáveis locais. Para cada invocação de um método é alocada uma área para armazenar
variáveis durante o tempo de vida da invocação, denominada quadro de variáveis locais. No início
desse quadro estão os parâmetros (também denominados argumentos) com os quais o método foi
invocado. O quadro de variáveis locais não inclui a pilha de operandos, que é separada. Contudo,
por questões de eficiência, nossa implementação prefere executar a pilha de operandos logo acima do
quadro de variáveis locais. Há um registrador implícito que contém o endereço da primeira localização
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
204
do quadro de variáveis locais. Nós o denominaremos LV. Os parâmetros passados na chamada do
método são armazenados no início do quadro de variáveis locais.
3. A pilha de operandos. É garantido que o quadro não exceda certo tamanho, calculado com antecedên-
cia pelo compilador Java. O espaço da pilha de operandos é alocado diretamente acima do quadro de
variáveis locais, como ilustrado na Figura 4.10. Em nossa implementação, é conveniente imaginar a
pilha de operandos como parte do quadro de variáveis locais. De qualquer modo, há um registrador
implícito que contém o endereço da palavra do topo da pilha. Note que, diferente do CPP e do LV, esse
ponteiro, SP, muda durante a execução do método à medida que operandos são passados para a pilha
ou retirados dela.
4. A área de método. Por fim, há uma região da memória que contém o programa, à qual nos referimos como a
área de “texto” em um processo UN. Há um registrador implícito que contém o endereço da instrução a ser
buscada em seguida. Esse ponteiro é denominado contador de programa (Program Counter) ou PC. Diferente
das outras regiões da memória, a área de método é tratada como um vetor de bytes.
Figura 4.10 As va
rias partes da memo
ria IJVM.
SP
LV
PC
CPP
Conjunto de
constantes
Pilha 3 de
operandos
correntes
Quadro 3
de variáveis
locais
correntes
Quadro 2
de variáveis
locais
Quadro 1
de variáveis
locais
Área de
método
É preciso esclarecer uma questão em relação aos ponteiros. Os registradores CPP, LV e SP são todos pon-
teiros para palavras, não para bytes, e são deslocados pelo número de palavras. Para o subconjunto de inteiros
que escolhemos, todas as referências a itens no conjunto de constantes, o quadro de variáveis locais e as pilhas
são palavras, e todos os deslocamentos usados para indexar esses quadros são deslocamentos de palavras. Por
exemplo, LV, LV + 1 e LV + 2 se referem às primeiras três palavras do quadro de variáveis locais. Em comparação,
LV, LV + 4 e LV + 8 se referem a palavras em intervalos de quatro palavras (16 bytes).
Ao contrário, PC contém um endereço de byte, e uma adição ou subtração ao PC altera o endereço por um
número de bytes, e não por um número de palavras. O endereçamento para PC é diferente dos outros e esse fato
é aparente na porta de memória especial fornecida para PC na Mic-1. Lembre-se de que a largura dessa porta é
de apenas 1 byte. ncrementar o PC por um fator de um e iniciar uma leitura resulta em uma busca pelo próximo
byte. ncrementar o SP por um fator de um e iniciar uma leitura resulta em uma busca pela próxima palavra.
4.2.3 Conjunto de instruc
o
es da IJVM
O conjunto de instruções da JM é mostrado na Figura 4.11. Cada instrução consiste em um opcode e às
vezes um operando, tal como um deslocamento de memória ou uma constante. A primeira coluna dá a codificação
hexadecimal da instrução. A segunda dá seu mnemônico em linguagem de montagem. A terceira dá uma breve
descrição de seu efeito.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 205
Figura 4.11 Conjunto de instruc
o
es da IJVM. Os operandos byte, const e varnum sa
o de 1 byte. Os operandos disp, index e offset sa
o
de 2 bytes.
Hexa Mnemônico Significado
0x10 BIPUSH byte Carregue o byte para a pilha
0x59 DUP Copie a palavra do topo da pilha e passe-a para a pilha
0xA7 GOTO offset Desvio incondicional
0x60 IADD Retire duas palavras da pilha; carregue sua soma
0x7E IAND Retire duas palavras da pilha; carregue AND booleano
0x99 IFEQ offset Retire palavra da pilha e desvie se for zero
0x9B IFLT offset Retire palavra da pilha e desvie se for menor do que zero
0x9F IF_ICMPEQ offset Retire duas palavras da pilha; desvie se iguais
0x84 IINC varnum const Some uma constante a uma variável local
0x15 ILOAD varnum Carregue variável local para pilha
0xB6 INVOKEVIRTUAL disp Invoque um método
0x80 IOR Retire duas palavras da pilha; carregue OR booleano
0xAC IRETURN Retorne do método com valor inteiro
0x36 ISTORE varnum Retire palavra da pilha e armazene em variável local
0x64 ISUB Retire duas palavras da pilha; carregue sua diferença
0x13 LDC_W index Carregue constante do conjunto de constantes para pilha
0x00 NOP Não faça nada
0x57 POP Apague palavra no topo da pilha
0x5F SWAP Troque as duas palavras do topo da pilha uma pela outra
0xC4 WIDE Instrução prefixada; instrução seguinte tem um índice de 16 bits
São fornecidas instruções para passar para a pilha uma palavra que pode vir de diversas fontes. Entre essas fontes
estão o conjunto de constantes (LDC_W), o quadro de variáveis locais (ILOAD) e a própria instrução (BIPUSH). Uma
variável também pode ser retirada da pilha e armazenada no quadro de variáveis locais (ISTORE). Duas operações
aritméticas (IADD e ISUB), bem como duas operações lógicas booleanas (IAND e IOR), podem ser efetuadas usando
as duas palavras de cima da pilha como operandos. Em todas as operações aritméticas e lógicas, duas palavras são
retiradas da pilha e o resultado é devolvido a ela. São fornecidas quatro instruções de desvio, uma incondicional
(GOTO) e três condicionais (IFEQ, IFLT e IF_ICMPEQ). Todas as instruções de ramificação, se tomadas, ajustam o
valor de PC conforme o tamanho de seus deslocamentos (16 bits com sinal), que vem após o opcode na instrução.
Esse deslocamento é adicionado ao endereço do opcode. Há também instruções JM para trocar as duas palavras do
topo da pilha uma pela outra (SWAP), duplicando a palavra do topo (DUP) e retirando-a (POP).
Algumas instruções têm vários formatos, o que permite uma forma abreviada para versões comumente usa-
das. Na JM, incluímos dois dos vários mecanismos que a JM usa para fazer isso. Em um caso, ignoramos a
forma abreviada em favor da mais geral. Em outro caso, mostramos como a instrução prefixada WIDE pode ser
usada para modificar a instrução resultante.
Por fim, há uma instrução (INVOKEVIRTUAL) para invocar (chamar) outro método e outra instrução
(IRETURN) para sair dele e devolver o controle ao método que o invocou. Pela complexidade do mecanismo,
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
206
simplificamos de leve a definição, possibilitando produzir um mecanismo direto para invocar uma chamada e um
retorno. A restrição é que, diferente da Java, só permitimos que um método invoque outro existente dentro de
seu próprio objeto. Essa restrição prejudica seriamente a orientação de objetos, mas nos permite apresentar um
mecanismo muito mais simples, evitando o requisito de localizar o método dinamicamente. (Se você não estiver
familiarizado com programação orientada a objeto, pode ignorar essa observação sem susto. O que fizemos foi
levar Java de volta a uma linguagem não orientada a objeto, como C ou Pascal.) Em todos os computadores,
exceto JM, o endereço do procedimento para chamar é determinado diretamente pela instrução CALL, portanto,
nossa abordagem é, na verdade, o caso normal, e não a exceção.
O mecanismo para invocar um método é o seguinte. Primeiro, o chamador passa para a pilha uma referência
(ponteiro) ao objeto a ser chamado. (Essa referência não é necessária na JM, visto que nenhum outro objeto
pode ser especificado, mas é mantida para preservar a consistência com a JM.) Na Figura 4.12(a), essa referência
é indicada por OBJREF. Em seguida, o chamador passa os parâmetros do método para a pilha, nesse exemplo,
Parâmetro 1, Parâmetro 2 e Parâmetro 3. Finalmente, INVOKEVIRTUAL é executada.
A instrução INVOKEVIRTUAL inclui um deslocamento que indica a posição no conjunto de constantes que
contêm o endereço de início dentro da área de método para o método que está sendo invocado. Contudo, embora
o código do método resida na localização apontada por esse ponteiro, os primeiros 4 bytes na área de método
contêm dados especiais. Os primeiros 2 bytes são interpretados como um inteiro de 16 bits que indica o número
de parâmetros para o método (os parâmetros em si já foram passados para a pilha). Nessa contagem, OBJREF é
contado como um parâmetro: parâmetro 0. Esse inteiro de 16 bits, junto com o valor de SP, fornece a localização
de OBJREF. Note que LV aponta para OBJREF, e não para o primeiro parâmetro real. Para onde o LV aponta é
uma escolha um tanto arbitrária.
Os 2 bytes seguintes na área de método são interpretados como outro inteiro de 16 bits, que indica o tama-
nho da área de variáveis locais para o método que está sendo chamado. sso é necessário porque uma nova pilha
será estabelecida para o método, começando imediatamente acima do quadro de variáveis locais. Por fim, o quinto
byte na área de método contém o primeiro opcode a ser executado.
A sequência real que ocorre para INVOKEVIRTUAL é a seguinte, e está retratada na Figura 4.12. Os dois bytes
de índice sem sinal que seguem o opcode são usados para construir um índice na tabela do conjunto de constantes
(o primeiro byte é o byte de ordem alta). A instrução calcula o endereço da base do novo quadro de variáveis locais
subtraindo o número de parâmetros do ponteiro da pilha e ajustando LV para apontar para OBJREF. Nesse local,
sobrescrevendo OBJREF, a implementação guarda o endereço do local onde o antigo PC deve ser armazenado. Esse
endereço é calculado adicionando o tamanho do quadro de variáveis locais (parâmetros + variáveis locais) ao endere-
ço contido em LV. mediatamente acima do endereço onde o antigo PC deve ser armazenado está o endereço onde o
antigo LV deve ser armazenado. Logo acima daquele endereço está o início da pilha para o procedimento que acabou
de ser chamado. O SP é ajustado para apontar para o antigo LV, que é o endereço logo abaixo do primeiro local vazio
na pilha. Lembre-se de que o SP sempre aponta para a palavra no topo da pilha. Se esta estiver vazia, ele aponta para
o primeiro local abaixo do final, porque nossas pilhas crescem para cima, na direção de endereços mais altos. Em
nossas figuras, as pilhas sempre crescem para cima, na direção dos endereços mais altos, no topo da página.
A última operação necessária para efetuar INVOKEVIRTUAL é ajustar PC para apontar para o quinto byte no
espaço de código do método.
A instrução IRETURN inverte as operações da instrução INVOKEVIRTUAL, conforme mostra Figura 4.13.
Ela libera o espaço usado pelo método que retorna. Também restaura a pilha a seu estado anterior, exceto que
(1) a palavra OBJREF (agora sobrescrita) e todos os parâmetros foram retirados da pilha e (2) o valor retornado
foi colocado no topo da pilha, no local antes ocupado por OBJREF. Para restaurar o antigo estado, a instrução
IRETURN deve ser capaz de restaurar os ponteiros PC e LV para seus antigos valores. Ela faz isso acessando o
ponteiro de ligação (que é a palavra identificada pelo ponteiro LV corrente). Lembre-se de que, nesse local, onde
a OBJREF estava armazenada originalmente, a instrução INVOKEVIRTUAL armazenou o endereço contendo o
PC antigo. Essa palavra e a palavra acima dela são recuperadas para restaurar PC e LV para seus valores antigos.
O valor de retorno, que estava armazenado no topo da pilha do método que está encerrando, é copiado para o
local onde a OBJREF estava armazenada, e SP é restaurado para apontar para esse local. Portanto, o controle é
devolvido à instrução imediatamente após a instrução INVOKEVIRTUAL.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 207
Figura 4.12 (a) Memo
ria antes de executar INVOKEVIRTUAL. (b) Apo
s executa
-la.
Parâmetros
passados
Quadro de
variáveis
locais do
chamador
Pilha antes de
INVOKEVIRTUAL
Pilha após
INVOKEVIRTUAL
SP
SP
LV
LV
(a) (b)
Base da
pilha após
INVOKEVIRTUAL
Base da
pilha antes de
INVOKEVIRTUAL
Parâmetro 3
Parâmetro 2
Parâmetro 1
OBJREF
LV anterior
PC anterior PC anterior
Variáveis
locais do
chamador
Parâmetro 2
Parâmetro 1
Ponteiro de ligação
Variáveis
locais do
chamador
Espaço para
variáveis locais
do chamador
Parâmetro 2
Parâmetro 1
Ponteiro de ligação
LV do chamador
PC do chamador
LV anterior
Parâmetro 3
Parâmetro 2
Parâmetro 1
Ponteiro de ligação
Figura 4.13 Memo
ria antes de executar IRETURN. (b) Apo
s executa
-la.
Frame da
variável
local do
chamador
Pilha antes
de IRETURN
Pilha após
IRETURN
SP
SP
LV
LV
(a) (b)
Base da
pilha antes
de IRETURN
Base da
pilha após
IRETURN
Parâmetro 3
Parâmetro 2
Parâmetro 1
Ponteiro de ligação
PV anterior
PC anterior PC anterior
Variáveis
locais do
chamador
Variáveis
locais do
chamador
Parâmetro 2
Parâmetro 1
LV anterior
Valor de retorno
PC anterior
Ponteiro de ligação
Variáveis
locais do
chamador
Parâmetro 2
Parâmetro 1
Ponteiro de ligação
LV anterior
Valor de retorno
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
208
Até aqui, nossa máquina não tem nenhuma instrução de entrada/saída. Tampouco vamos adicionar alguma.
Ela não precisa dessas instruções, nem a Java irtual Machine, e a especificação oficial para a JM sequer men-
ciona E/S. A teoria é que uma máquina que não efetua entrada nem saída é “segura”. (Na JM, leitura e escrita
são realizadas por meio de uma chamada a métodos especiais de E/S.)
4.2.4 Compilando Java para a IJVM
Agora, vamos ver como Java e JM estão relacionadas uma com a outra. Na Figura 4.14(a), mostramos um
fragmento simples de código Java. Quando alimentado em um compilador Java, este provavelmente produziria a
linguagem de montagem JM mostrada na Figura 4.14(b). Os números de linhas de 1 a 15 à esquerda do pro-
grama de linguagem de montagem não fazem parte da saída do compilador; o mesmo vale para os comentários
(que começam com //). Eles estão ali para ajudar a explicar a figura seguinte. Então, o assembler Java traduziria
o programa de montagem para o programa binário mostrado na Figura 4.14(c). (Na verdade, o compilador Java
faz sua própria montagem e produz o programa binário diretamente.) Para este exemplo, consideremos que i é a
variável local 1, j é a variável local 2 e k é a variável local 3.
Figura 4.14 (a) Fragmento em Java. (b) Linguagem de montagem Java correspondente. (c) Programa IJVM em hexadecimal.
i = j + k; ILOAD j // i = j + k 0x15 0x02
if (i == 3) 2 ILOAD 0
k x15 0x03
k = 0; IADD 0x60
else 4 ISTORE i x36 0x01
j = j − 1; 5 ILOAD i // if (i == 3) 0x15 0x01
6 BIPUSH 3 x10 0x03
7 IF ICMPEQ L1 0x9F 0x00 0x0D
8 ILOAD j // j = j − 1 0x15 0x02
9 BIPUSH 1 x10 0x01
10 ISUB 0x64
11 ISTORE 0
j x36 0x02
12 GOTO L2 0xA7 0x00 0x07
13 L1: BIPUSH 0 // k = 0 0x10 0x00
14 ISTORE k x36 0x03
15 L2:
(a) (b) (c)
1
3
0
0
0
0
O código compilado é direto. Primeiro, j e k são passadas para a pilha, somadas e o resultado é armazenado
em i. Então, i e a constante 3 são passadas para a pilha e comparadas. Se forem iguais, é tomado um desvio para
L1, onde k é ajustada para 0. Se forem diferentes, a comparação falha e o código logo após IF_ICMPEQ é execu-
tado. Feito isso, ele desvia para L2, onde as partes then e else se fundem.
A pilha de operandos para o programa JM da Figura 4.14(b) é mostrada na Figura 4.15. Antes de o código
começar a executar, ela está vazia, o que é indicado pela linha horizontal acima do 0. Após a primeira ILOAD,
j está na pilha, como indicado por j no retângulo acima de 1 (o que significa que a instrução 1 foi executada).
Depois da segunda ILOAD, duas palavras estão na pilha, como mostrado acima de 2. Após a IADD, há somente
uma palavra na pilha, que contém a soma j + k. Quando a palavra do topo é retirada e armazenada em i, a pilha
está vazia, como mostrado acima do 4.
A instrução 5 (ILOAD) inicia a declaração if passando i para a pilha (em 5). Em seguida, vem a constante 3
(em 6). Após a comparação, a pilha está novamente vazia (7). A instrução 8 é o início da parte else do fragmento
de programa Java. A parte else continua até a instrução 12, quando então desvia para a parte then e vai para o
rótulo L2.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 209
Figura 4.15 Pilha apo
s cada instruc
a
o da Figura 4.14(b).
j
2
j + k
3
j
1
0
k
i
6 7
3
4
i
5
j – 1
10 11
j
1
j
9
8 14 15
12
0
13
4.3 Exemplo de implementac
a
o
Agora que já especificamos em detalhes a micro e a macroarquitetura, resta a questão da implementação. Em
outras palavras, como é um programa que está rodando na primeira e interpretando a última, e como ele funcio-
na? Antes de podermos responder a essas perguntas, devemos considerar com cuidado a notação que usaremos
para descrever a implementação.
4.3.1 Microinstruc
o
es e notac
a
o
Em princípio, poderíamos descrever o armazenamento de controle em linguagem binária, 36 bits por pala-
vra. Mas, em linguagens de programação convencionais, é um grande benefício introduzir uma notação que
transmita a essência das questões que precisamos tratar e, ao mesmo tempo, oculte os detalhes que podem ser
ignorados ou que podem ser mais bem tratados automaticamente. Nesse caso, é importante perceber que a lingua-
gem que escolhemos pretende ilustrar os conceitos, e não facilitar projetos eficientes. Se esse fosse nosso objetivo,
usaríamos uma notação diferente para maximizar a flexibilidade disponível para o projetista. Um aspecto em que
essa questão é importante é a escolha de endereços. Uma vez que a memória não é ordenada logicamente, não
há nenhuma “próxima instrução” natural a ser subentendida quando especificamos uma sequência de operações.
Grande parte do poder dessa organização de controle deriva da capacidade do projetista [ou do montador (assem-
bler)] de selecionar endereços com eficiência. Portanto, começamos introduzindo uma linguagem simbólica
simples que dá uma descrição completa de cada operação sem explicar completamente como todos os endereços
poderiam ter sido determinados.
Nossa notação especifica todas as atividades que ocorrem num único ciclo de clock em uma única linha. Em
teoria, poderíamos usar uma linguagem de alto nível para descrever as operações. Contudo, o controle ciclo por
ciclo é muito importante porque dá oportunidade de realizar várias operações ao mesmo tempo e é necessário que
possamos analisar cada um para entender e verificar as operações. Se a meta for uma execução rápida e eficiente
(se os outros aspectos forem iguais, rápido e eficiente é sempre melhor que lento e ineficiente), então, cada ciclo
conta. Em uma implementação real, há muitos truques sutis ocultos no programa, que usam sequências ou ope-
rações obscuras para economizar um único ciclo que seja. Há uma grande compensação por economizar ciclos:
uma instrução de quatro ciclos que pode ser reduzida em dois agora será executada com uma velocidade duas
vezes maior – e essa aceleração é obtida toda vez que executamos a instrução.
Uma abordagem possível é simplesmente fazer uma lista dos sinais que deveriam ser ativados a cada ciclo
de clock. Suponha que, em determinado ciclo, queremos incrementar o valor de SP. Também queremos iniciar
uma operação de leitura e queremos que a próxima instrução seja a que reside no local 122 do armazenamento
de controle. Poderíamos escrever
ReadRegister = SP, ULA = INC, WSP, Read, NEXT_ADDRESS = 122
onde WSP significa “escreva no registrador SP”. Essa notação é completa, mas difícil de entender. Em vez disso,
combinaremos as operações de modo natural e intuitivo para captar o efeito daquilo que está acontecendo:
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
210
SP = SP + 1; rd
amos dar à nossa Microlinguagem Assembly de alto nível o nome “MAL” (palavra de raiz latina que significa
“doente”, o que com certeza você ficará se tiver de escrever muito código utilizando essa linguagem). A MAL é
projetada para refletir as características da microarquitetura. Durante cada ciclo, qualquer um dos registradores
pode ser escrito, mas o normal é que somente um o seja. Apenas um registrador pode ser copiado para o lado B
da ULA. No lado A, as opções são +1, 0, –1 e o registrador H. Assim, podemos usar uma declaração de atribuição
simples, como em Java, para indicar a operação a ser executada. Por exemplo, para copiar algo de SP para MDR,
podemos dizer
MDR = SP
Para indicar a utilização das funções ULA, exceto passar pelo barramento B, podemos escrever, por exemplo,
MDR = H + SP
que adiciona o conteúdo do registrador H a SP e escreve o resultado no MDR. O operador + é comutativo – o que
significa que a ordem dos operandos não importa –, portanto, a declaração anterior também pode ser escrita como
MDR = SP + H
e gerar a mesma microinstrução de 36 bits, ainda que, em termos estritos, H deve ser o operando esquerdo da ULA.
Temos de tomar o cuidado de usar somente operações válidas. As operações válidas mais importantes são
mostradas na Figura 4.16, na qual SOURCE pode ser qualquer um dentre MDR, PC, MBR, MBRU, SP, LV, CPP,
TOS ou OPC (MBRU implica a versão sem sinal de MBR). Todos esses registradores podem agir como fontes para
a ULA no barramento B. De modo semelhante, DEST pode ser qualquer um dentre MAR, MDR, PC, SP, LV, CPP,
TOS, OPC ou H; todos eles são destinos possíveis para a saída da ULA no barramento C. Esse formato pode ser
enganoso, pois muitas declarações aparentemente razoáveis são ilegais. Por exemplo,
MDR = SP + MDR
parece perfeitamente razoável, mas não há nenhum modo de executá-la em um ciclo no caminho de dados
da Figura 4.6. Essa restrição existe porque, para uma adição (exceto um incremento ou decremento), um dos
operandos tem de ser o registrador H. Da mesma forma,
H = H – MDR
poderia ser útil, mas também ela é impossível porque a única fonte possível de um subtraendo – valor que está
sendo subtraído – é o registrador H. Cabe ao montador rejeitar declarações que pareçam válidas, mas que, na
verdade, são ilegais.
Ampliamos a notação para permitir múltiplas atribuições pela utilização de múltiplos sinais de igual. Por exem-
plo, adicionar 1 a SP e armazená-lo de volta em SP, bem como escrevê-lo em MDR, pode ser conseguido por
SP = MDR = SP + 1
Para indicar leituras e escritas de memória de palavras de dados de 4 bytes, basta acrescentar rd e wr à
microinstrução. Buscar um byte pela porta de 1 byte é indicado por fetch. Atribuições e operações de memória
podem ocorrer no mesmo ciclo, o que é indicado escrevendo-as na mesma linha.
Para evitar qualquer confusão, vamos repetir que a Mic-1 tem dois modos de acessar a memória. Leituras e
escritas de palavras de dados de 4 bytes usam MAR/MDR e são indicadas nas microinstruções por rd e wr, respec-
tivamente. Leituras de opcodes de 1 byte a partir da sequência de instruções usam PC/MBR e são indicadas por
fetch nas microinstruções. Ambos os tipos de operações de memória podem ocorrer simultaneamente.
Contudo, o mesmo registrador não pode receber um valor da memória e o caminho de dados no mesmo
ciclo. Considere o código
MAR = SP; rd
MDR = H
O efeito da primeira microinstrução é atribuir um valor da memória a MDR no final da segunda microinstru-
ção. Contudo, esta também atribui um valor a MDR ao mesmo tempo. Essas duas atribuições estão em conflito e
não são permitidas porque os resultados são indefinidos.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 211
Figura 4.16 Todas as operac
o
es permitidas. Qualquer uma das operac
o
es anteriores pode ser estendida somando << 8” a elas para des-
locar o resultado para a esquerda por 1 byte. Por exemplo, uma operac
a
o comum e
 H = MBR << 8.
DEST = H
DEST = SOURCE
DEST = H
DEST = SOURCE
DEST = H + SOURCE
DEST = H + SOURCE + 1
DEST = H + 1
DEST = SOURCE + 1
DEST = SOURCE – H
DEST = SOURCE – 1
DEST = –H
DEST = H AND SOURCE
DEST = H OR SOURCE
DEST = 0
DEST = 1
DEST = –1
Lembre-se de que cada microinstrução deve fornecer explicitamente o endereço da próxima a ser executada.
Todavia, é comum ocorrer que uma microinstrução seja chamada somente por uma outra, a saber, por aquela
que está na linha imediatamente acima dela. Para facilitar o trabalho do microprogramador, o microassembler
atribui um endereço a cada microinstrução, não necessariamente consecutivas no armazenamento de controle, e
preenche o próximo campo NEXT_ADDRESS de modo que microinstruções escritas em linhas consecutivas são
executadas consecutivamente.
Todavia, às vezes o microprogramador quer desviar, condicional ou incondicionalmente. A notação para
desvios incondicionais é fácil:
goto label
e pode ser incluída em qualquer microinstrução para nomear explicitamente sua sucessora. Por exemplo, a maio-
ria das sequências de microinstrução termina com um retorno à primeira instrução do laço principal, portanto, a
última instrução em cada uma dessas sequências normalmente inclui
goto Main1
Note que o caminho de dados está disponível para operações normais mesmo durante a microinstrução que
contém um goto. Afinal, toda microinstrução individual contém um campo NEXT_ADDRESS. A tarefa de goto
é instruir o microassembler a colocar um valor específico nesse campo em vez de no endereço onde ele decidiu
colocar a microinstrução na linha seguinte. Em princípio, toda linha deveria ter uma declaração goto; apenas
como uma conveniência para o microprogramador, quando o endereço visado for a próxima linha, ele pode ser
omitido.
Para desvios condicionais, precisamos de uma notação diferente. Lembre-se de que JAMN e JAMZ usam os
bits N e Z, que são ajustados com base na saída da ULA. Às vezes, é preciso testar um registrador para ver se ele
é zero, por exemplo. Um modo de fazer isso seria passá-lo pela ULA e armazená-lo em si mesmo. Escrever
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
212
TOS = TOS
parece peculiar, embora exerça sua função (ajustar o flip-flop Z com base no TOS). Contudo, para que os micro-
programas pareçam melhores, agora estendemos MAL adicionando dois registradores imaginários, N e Z, aos quais
se podem designar atribuições. Por exemplo,
Z = TOS
passa TOS pela ULA, ajustando assim os flip-flops Z (e N), mas não faz um armazenamento em qualquer registra-
dor. Usar Z ou N como um destino equivale a dizer ao microassembler que ajuste todos os bits no campo C da
Figura 4.5 para 0. O caminho de dados executa um ciclo normal, com todas as operações normais permitidas, mas
nenhum registrador é escrito. Note que não importa se o destino é N ou Z; a microinstrução gerada pelo micro-
assembler é idêntica. Programadores que escolhem intencionalmente a forma “errada” deveriam, como castigo,
ser obrigados a trabalhar em um BM PC original de 4,77 MHz durante uma semana.
A sintaxe para dizer ao microassembler que ajuste o bit JAMZ é
if (Z) goto L1; else goto L2
Uma vez que o hardware requer que os 8 bits de ordem baixa desses dois endereços sejam idênticos, cabe
ao microassembler designá-los a endereços com essa propriedade. Por outro lado, visto que L2 pode estar em
qualquer lugar nas 256 palavras que estão mais embaixo no armazenamento de controle, o microassembler tem
bastante liberdade para achar um par disponível.
Normalmente, essas duas declarações serão combinadas; por exemplo:
Z = TOS; if (Z) goto L1; else goto L2
O efeito dessa declaração é que MAL gera uma microinstrução na qual TOS é passada pela ULA (mas não
é armazenada em lugar algum) de modo que seu valor ajusta o bit Z. Logo após Z ser carregado a partir do bit
de condição da ULA, ele passa por uma operação OR com o bit de ordem alta do MPC, forçando o endereço da
próxima microinstrução a ser buscado em L2 ou L1 (que deve ser exatamente 256 mais do que L2). O MPC estará
estável e pronto a ser utilizado para buscar a próxima microinstrução.
Por fim, precisamos de uma notação para usar o bit JMPC. A notação que usaremos será
goto (MBR OR value)
Essa sintaxe diz ao microassembler para usar value para NEXT_ADDRESS e ajustar o bit JMPC de modo que
MBR e NEXT_ADDRESS sejam combinados por uma operação OR, e o resultado, armazenado em MPC. Se value
for 0, que é o caso normal, basta escrever
goto (MBR)
Note que somente os 8 bits de ordem baixa de MBR são ligados ao MPC (veja a Figura 4.6), portanto, a
questão da extensão de sinal (isto é, MBR versus MBRU) não surge aqui. Além disso, note que o MBR disponível
no final do ciclo em questão é o que é utilizado. Uma busca iniciada nessa microinstrução está muito atrasada
para afetar a escolha da próxima microinstrução.
4.3.2 Implementac
a
o de IJVM que usa a Mic-1
Chegamos enfim ao ponto em que podemos juntar todas as partes. A Figura 4.17 é o microprograma que
executa em Mic-1 e interpreta a JM. É um programa surpreendentemente curto – somente 112 microinstruções
no total. São dadas três colunas para cada microinstrução: o rótulo simbólico, o microcódigo propriamente dito e
um comentário. Note que microinstruções consecutivas não precisam ser localizadas em endereços consecutivos
no armazenamento de controle, como já havíamos comentado.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 213
Figura 4.17 Microprograma para a Mic-1.
Rótulo Operações Comentários
Main1 PC = PC + 1; fetch;1
goto (MBR) MBR contém opcode; obtenha o próximo byte; despache
nop1 goto Main1 Não faça nada
iadd1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
iadd2 H = TOS H = topo da pilha
iadd3 MDR = TOS = MDR + H; wr; goto Main1
Some as duas palavras do topo; escreva para o topo da
pilha
isub1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
isub2 H = TOS H = topo da pilha
isub3 MDR = TOS = MDR – H; wr; goto Main1 Efetue subtração; escreva para topo da pilha
iand1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
iand2 H = TOS H = topo da pilha
iand3 MDR = TOS = MDR AND H; wr; goto Main1 Faça AND; escreva para novo topo da pilha
ior1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
ior2 H = TOS H = topo da pilha
ior3 MDR = TOS = MDR OR H; wr; goto Main1 Faça OR; escreva para novo topo da pilha
dup1 MAR = SP = SP + 1 Incremente SP e copie para MAR
dup2 MDR = TOS; wr; goto Main1 Escreva nova palavra da pilha
pop1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
pop2 Espere nova TOS ser lida da memória
pop3 TOS = MDR; goto Main1 Copie nova palavra para TOS
swap1 MAR = SP – 1; rd Ajuste MAR para SP – 1; leia 2a
palavra da pilha
swap2 MAR = SP Ajuste MAR para palavra do topo
swap3 H = MDR; wr Salve TOS em H; escreva 2a
palavra para topo da pilha
swap4 MDR = TOS Copie TOS antigo para MDR
swap5 MAR = SP – 1; wr Ajuste MAR para SP – 1; escreva como 2a
palavra na pilha
swap6 TOS = H; goto Main1 Atualize TOS
bipush1 SP = MAR = SP + 1 MBR = o byte para passar para a pilha
bipush2 PC = PC + 1; fetch Incremente PC, busque próximo opcode
bipush3 MDR = TOS = MBR; wr; goto Main1 Estenda sinal da constante e passe para a pilha
iload1 H = LV MBR contém índice; copie LV para H
iload2 MAR = MBRU + H; rd MAR = endereço de variável local para passar para pilha
iload3 MAR = SP = SP + 1 SP aponta para novo topo da pilha; prepare escrita
iload4 PC = PC + 1; fetch; wr
Incremente PC; obtenha próximo opcode; escreva topo da
pilha
iload5 TOS = MDR; goto Main1 Atualize TOS
1 N.R.: O termo fetch” indica a leitura de um byte da área de programa.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
214
Rótulo Operações Comentários
istore1 H = LV MBR contém índice; copie LV para H
istore2 MAR = MBRU + H MAR = endereço de variável local onde armazenar
istore3 MDR = TOS; wr Copie TOS para MDR; escreva palavra
istore4 SP = MAR = SP – 1; rd Leia a palavra seguinte à do topo da pilha
istore5 PC = PC + 1; fetch Incremente PC; busque próximo opcode
istore6 TOS = MDR; goto Main1 Atualize TOS
wide1 PC = PC + 1; fetch Busque byte de operando ou próximo opcode
wide2 goto (MBR OR 0x100) Ramificação multivias com bit alto ajustado
wide_iload1 PC = PC + 1; fetch MBR contém 1o
byte de índice; busque 2o
wide_iload2 H = MBRU << 8 H = 1o
byte de índice deslocado 8 bits para esquerda
wide_iload3 H = MBRU OR H H = índice de 16 bits de variável local
wide_iload4 MAR = LV + H; rd; goto iload3 MAR = endereço de variável local a carregar
wide_istore1 PC = PC + 1; fetch MBR contém 1o
byte de índice; busque 2o
wide_istore2 H = MBRU << 8 H = 1o
byte de índice deslocado 8 bits para esquerda
wide_istore3 H = MBRU OR H H = índice de 16 bits de variável local
wide_istore4 MAR = LV + H; goto istore3 MAR = endereço de variável local no qual armazenar
ldc_w1 PC = PC + 1; fetch MBR contém 1o
byte de índice; busque 2o
ldc_w2 H = MBRU << 8 H = 1o
byte de índice << 8
ldc_w3 H = MBRU OR H H = índice de 16 bits dentro do conjunto de constantes
ldc_w4 MAR = H + CPP; rd; goto iload3 MAR = endereço de constante no conjunto de constantes
iinc1 H = LV MBR contém índice; copie LV para H
iinc2 MAR = MBRU + H; rd Copie LV + índice para MAR; leia variável
iinc3 PC = PC + 1; fetch Busque constante
iinc4 H = MDR Copie variável para H
iinc5 PC = PC + 1; fetch Busque próximo opcode
iinc6 MDR = MBR + H; wr; goto Main1 Ponha soma em MDR; atualize variável
goto1 OPC = PC – 1 Salve endereço de opcode
goto2 PC = PC + 1; fetch MBR = 1o
byte de deslocamento; busque 2o
byte
goto3 H = MBR << 8 Desloque e salve primeiro byte com sinal em H
goto4 H = MBRU OR H H = deslocamento de desvio de 16 bits
goto5 PC = OPC + H; fetch Adicione deslocamento a OPC
goto6 goto Main1 Espere para buscar o próximo opcode
iflt1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
iflt2 OPC = TOS Salve TOS em OPC temporariamente
iflt3 TOS = MDR Ponha novo topo da pilha em TOS
iflt4 N = OPC; if (N) goto T; else goto F Desvio de bit N
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 215
Rótulo Operações Comentários
ifeq1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
ifeq2 OPC = TOS Salve TOS em OPC temporariamente
ifeq3 TOS = MDR Ponha novo topo da pilha em TOS
ifeq4 Z = OPC; if (Z) goto T; else goto F Desvio de bit Z
if_icmpeq1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
if_icmpeq2 MAR = SP = SP – 1 Ajuste MAR para ler novo topo da pilha
if_icmpeq3 H = MDR; rd Copie segunda palavra da pilha para H
if_icmpeq4 OPC = TOS Salve TOS em OPC temporariamente
if_icmpeq5 TOS = MDR Ponha novo topo da pilha em TOS
if_icmpeq6 Z = OPC – H; if (Z) goto T; else goto F
Se 2 palavras do topo da pilha forem iguais, vá para T,
senão vá para F
T OPC = PC – 1; goto goto2 O mesmo que goto1; necessário para endereço de destino
F PC = PC + 1 Salte primeiro byte de deslocamento
F2 PC = PC + 1; fetch PC agora aponta para próximo opcode
F3 goto Main1 Espere por busca de opcode
invokevirtual1 PC = PC + 1; fetch MBR = byte de índice 1; incremente PC, obtenha 2o
byte
invokevirtual2 H = MBRU << 8 Desloque e salve primeiro byte em H
invokevirtual3 H = MBRU OR H H = deslocamento de ponteiro de método em relação a CPP
invokevirtual4 MAR = CPP + H; rd Obtenha ponteiro para método da área CPP
invokevirtual5 OPC = PC + 1 Salve PC de retorno em OPC temporariamente
invokevirtual6 PC = MDR; fetch
PC aponta para novo método; obtenha contagem de parâ-
metros
invokevirtual7 PC = PC + 1; fetch Busque 2o
byte da contagem de parâmetro
invokevirtual8 H = MBRU << 8 Desloque e salve primeiro byte em H
invokevirtual9 H = MBRU OR H H = número de parâmetros
invokevirtual10 PC = PC + 1; fetch Busque 1o
byte de # locais
invokevirtual11 TOS = SP – H TOS = endereço de OBJREF – 1
invokevirtual12 TOS = MAR = TOS + 1 TOS = endereço de OBJREF (novo LV)
invokevirtual13 PC = PC + 1; fetch Busque 2o
byte de # locais
invokevirtual14 H = MBRU << 8 Desloque e salve primeiro byte em H
invokevirtual15 H = MBRU OR H H = # locais
invokevirtual16 MDR = SP + H + 1; wr Sobrescreva OBJREF com ponteiro de enlace
invokevirtual17 MAR = SP = MDR Ajuste SP, MAR para localização para conter PC antigo
invokevirtual18 MDR = OPC; wr Salve PC antigo acima das variáveis locais
invokevirtual19 MAR = SP = SP + 1 SP aponta para localização para conter LV antigo
invokevirtual20 MDR = LV; wr Salve LV antigo acima do PC salvo
invokevirtual21 PC = PC + 1; fetch Busque primeiro opcode do novo método
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
216
Rótulo Operações Comentários
invokevirtual22 LV = TOS; goto Main1 Ajuste LV para apontar para quadro LV
ireturn1 MAR = SP = LV; rd Reajuste SP, MAR para obter ponteiro de ligação
ireturn2 Espere por leitura
ireturn3 LV = MAR = MDR; rd Ajuste LV para ponteiro de ligação; obtenha PC antigo
ireturn4 MAR = LV + 1 Ajuste MAR para ler LV antigo
ireturn5 PC = MDR; rd; fetch Restaure PC; busque próximo opcode
ireturn6 MAR = SP Ajuste MAR para escrever TOS
ireturn7 LV = MDR Restaure LV
ireturn8 MDR = TOS; wr; goto Main1 Salve valor de retorno no topo de pilha original
A essa altura a escolha de nomes para a maioria dos registradores na Figura 4.1 já deve ser óbvia: CPP, LV e
SP são usados para conter os ponteiros para o conjunto de constantes, variáveis locais e o topo da pilha, enquanto
PC contém o endereço do próximo byte a ser buscado no fluxo de instruções. MBR é um registrador de 1 byte que
contém os bytes da sequência de instrução, à medida que eles chegam da memória para ser interpretados. TOS e
OPC são registradores extras. Sua utilização é descrita a seguir.
Em certas ocasiões, é garantido que cada um desses registradores contenha certo valor, mas cada um pode
ser usado como um registrador transitório, se necessário. No início e no final de cada instrução, TOS contém o
valor do endereço de memória apontado por SP, a palavra que está no topo da pilha. Esse valor é redundante, uma
vez que sempre pode ser lido da memória, mas tê-lo em um registrador muitas vezes economiza uma referência
à memória. Para algumas poucas instruções, manter TOS significa mais operações de memória. Por exemplo, a
instrução POP joga fora a palavra do topo e, portanto, deve buscar a nova palavra do topo da pilha na memória
e passá-la para TOS.
O registrador OPC é um registrador temporário . Ele não tem nenhuma utilização predeterminada. É usado, por
exemplo, para salvar o endereço do opcode para uma instrução de desvio enquanto o PC é incrementado para acessar
parâmetros. Também é usado como um registrador temporário nas instruções de desvio condicional da JM.
Como todos os interpretadores, o microprograma da Figura 4.17 tem um laço principal que busca, decodi-
fica e executa instruções do programa que está sendo interpretado, nesse caso, instruções JM. Seu laço prin-
cipal começa na linha de rótulo Main1. nicia com a invariante de que o PC tenha sido previamente carregado
com um endereço de um local da memória que contém um opcode. Além do mais, esse opcode já foi trazido para
dentro do MBR. Contudo, observe que isso implica que, quando voltarmos a esse local, devemos assegurar que
o PC foi atualizado para apontar o próximo opcode a ser interpretado e o próprio byte do opcode já foi trazido
para dentro do MBR.
Essa sequência inicial de instruções é executada no início de cada instrução, então, é importante que ela seja
a mais curta possível. Por meio de um projeto muito cuidadoso do hardware e do software da Mic-1, conseguimos
reduzir o laço principal a uma única microinstrução. Uma vez iniciada a máquina, toda vez que essa microins-
trução for executada, o opcode JM a executar já está presente no MBR. A tarefa dessa microinstrução é desviar
para o microcódigo para executar a instrução JM e também iniciar a busca do byte após o opcode, que pode ser
um byte de operando ou o próximo opcode.
Agora podemos revelar a razão real por que cada microinstrução nomeia sua sucessora em vez de executá-las
em sequência. Todos os endereços do armazenamento de controle correspondentes a opcodes devem ser reserva-
dos para a primeira palavra do interpretador de instrução correspondente. Assim, pela Figura 4.11, vemos que
o código que interpreta POP começa em 0x57 e o código que interpreta DUP começa em 0x59. (Como o MAL
consegue colocar POP em 0x57? Possivelmente, há um arquivo em algum lugar que o informa.)
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 217
nfelizmente, o código para POP tem três microinstruções de comprimento, portanto, se colocado em
palavras consecutivas, interferiria com o início de DUP. Uma vez que todos os endereços do armazenamento de
controle correspondentes a opcodes são de fato reservados, as microinstruções, exceto a inicial em cada sequência,
devem ser colocadas nos espaços entre os endereços reservados. Por essa razão, há muitos saltos para lá e para cá;
dessa maneira, ter um microdesvio explícito – microinstrução que desvia – a cada poucas microinstruções para
saltar de buraco em buraco seria muito desperdício.
Para ver como o interpretador trabalha, vamos considerar, por exemplo, que MBR contém o valor 0x60, isto
é, o opcode para IADD (veja a Figura 4.11). No laço principal de uma só microinstrução realizamos três coisas:
1. ncrementamos o PC, que fica contendo o endereço do primeiro byte após o opcode.
2. niciamos uma busca do próximo byte para MBR. Mais cedo ou mais tarde, esse byte sempre será
necessário, seja como um operando para a instrução JM corrente, seja como o próximo opcode (como
no caso da instrução IADD, que não tem bytes de operando).
3. Executamos um desvio multivias até o endereço contido em MBR no início de Main1. Esse endereço é
igual ao valor numérico do opcode que está sendo executado no momento em questão. Ele foi colocado
ali pela microinstrução anterior. Não se esqueça de observar que o valor que está sendo buscado nessa
microinstrução não desempenha nenhum papel no desvio multivias.
A busca do próximo byte é iniciada aqui, portanto, ele estará disponível no início da terceira microinstrução.
Ele pode ser ou não necessário nesse momento, porém, mais cedo ou mais tarde, será necessário. Portanto, em
todo caso, iniciar a busca agora não poderá fazer mal algum.
Se acaso os bytes em MBR forem todos zeros, o opcode para uma instrução NOP, a microinstrução seguinte,
é a que tem rótulo nop1, buscada da localização 0. Como essa instrução nada faz, ela apenas desvia de volta ao
início do laço principal, onde a sequência é repetida, mas com um novo opcode buscado em MBR.
Mais uma vez destacamos que as microinstruções na Figura 4.17 não são consecutivas na memória e que
Main1 não está no endereço 0 do armazenamento de controle (porque nop1 tem de estar no endereço 0). Cabe ao
microassembler colocar cada microinstrução em um endereço adequado e ligá-las em sequências curtas usando o
campo NEXT_ADDRESS. Cada sequência começa no endereço correspondente ao valor numérico do opcode JM
que interpreta (por exemplo, POP começa em 0x57), mas o resto da sequência pode estar em qualquer lugar do
armazenamento de controle, e não necessariamente no endereço consecutivo.
Agora, considere a instrução JM IADD. A microinstrução para a qual o laço principal desviou é a que tem
o rótulo iadd1. Essa instrução inicia o trabalho específico de IADD:
1. O TOS já está presente, mas a palavra anterior à que está no topo da pilha deve ser buscada na memória.
2. O TOS deve ser adicionado à palavra anterior à do topo da pilha que foi buscada na memória.
3. O resultado, que deve ser passado para a pilha, deve ser armazenado de volta na memória, bem como
armazenado no registrador TOS.
Para buscar o operando na memória, é necessário decrementar o ponteiro da pilha e escrevê-lo em MAR. Note
que, por conveniência, esse endereço também é o endereço que será usado para a escrita subsequente. Além do
mais, visto que tal localização será o novo topo da pilha, esse valor deve ser atribuído a SP. Portanto, uma única
operação pode determinar o novo valor de SP e MAR, decrementar SP e escrevê-lo em ambos os registradores.
Essas coisas são realizadas no primeiro ciclo, iadd1, e a operação de leitura é iniciada. Além disso, MPC
obtém o valor do campo NEXT_ADDRESS de iadd1, que é o endereço de iadd2, onde quer que ele possa estar.
Então, iadd2 é lida do armazenamento de controle. Durante o segundo ciclo, enquanto espera o operando ser
lido da memória, copiamos a palavra do topo da pilha do TOS para H, onde ela ficará disponível para a adição
quando a leitura for concluída.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
218
No início do terceiro ciclo, iadd3, MDR contém o somando buscado na memória. Neste ciclo, ele é adicionado ao
conteúdo de H, e o resultado é armazenado de volta em MDR, bem como em TOS. Também é iniciada uma operação
de escrita, armazenando a nova palavra de topo de pilha de volta à memória. Neste ciclo, o goto tem o efeito de atri-
buir o endereço de Main1 ao MPC, o que nos leva de volta ao ponto de partida para a execução da próxima instrução.
Se o opcode JM subsequente, agora contido em MBR, for 0x64 (ISUB), quase exatamente a mesma sequên-
cia de eventos ocorre de novo. Após a execução de Main1, o controle é transferido para a microinstrução em 0x64
(isub1). Essa microinstrução é seguida por isub2 e isub3, e então novamente Main1. A única diferença entre essa
sequência e a anterior é que em isub3, o conteúdo de H é subtraído de MDR em vez de somado a ele.
A interpretação de IAND é quase idêntica à de IADD e ISUB, exceto que as duas palavras do topo da pilha pas-
sam por uma operação AND bit a bit em vez de serem somadas ou subtraídas. Algo semelhante acontece para IOR.
Se o opcode JC for DUP, POP ou SWAP, a pilha deve ser ajustada. A instrução DUP apenas duplica a pala-
vra do topo da pilha. Uma vez que o valor dessa palavra já está armazenado em TOS, a operação é tão simples
quanto incrementar SP para apontar para a nova localização e armazenar TOS naquela localização. A instrução
POP é quase tão simples, apenas decrementa SP para descartar a palavra que está no topo da pilha. Contudo,
para manter a palavra do topo em TOS, agora é necessário ler a nova palavra do topo na memória e escrevê-la em
TOS. Por fim, a instrução SWAP envolve permutar entre si os valores em duas localizações de memória: as duas
palavras do topo da pilha. A operação é facilitada de certa forma pelo fato de o TOS já conter um desses valores,
portanto, ele não precisa ser lido da memória. Essa instrução será discutida com mais detalhes mais adiante.
A instrução BIPUSH é um pouco mais complicada porque o opcode é seguido por um único byte, conforme
mostra a Figura 4.18. O byte deve ser interpretado como um inteiro com sinal. Esse byte, que já foi buscado para
MBR em Main1, deve ser estendido em sinal para 32 bits e passado para o topo da pilha. Portanto, essa sequência
deve estender em sinal o byte em MBR para 32 bits e copiá-lo para MDR. Por fim, SP é incrementado e copiado
para MAR, permitindo que o operando seja escrito para o topo da pilha. No caminho, esse operando também
deve ser copiado para o TOS. Além disso, antes de retornar para o programa principal, note que o PC deve ser
incrementado de modo que o próximo opcode estará disponível em Main1.
Figura 4.18 Formato da instruc
a
o BIPUSH.
BYTE
BIPUSH
(0x10)
Em seguida, considere a instrução ILOAD. Ela também tem um byte após o opcode, como ilustra a Figura
4.19(a), mas esse byte é um índice (sem sinal) para identificar a palavra no espaço de variáveis locais que será
passada para a pilha. Uma vez que há somente 1 byte, apenas 28
= 256 palavras podem ser distinguidas, a saber, as
primeiras 256 palavras no espaço de variáveis locais. A instrução ILOAD requer uma leitura (para obter a palavra),
bem como uma escrita (para passá-la para o topo da pilha). Para determinar o endereço para leitura, entretanto,
o deslocamento, contido em MBR, deve ser adicionado ao conteúdo de LV. Uma vez que ambos, MBR e LV, só
podem ser acessados pelo barramento B, LV primeiro é copiado para H (em iload1), então MBR é adicionado. O
resultado dessa adição é copiado para MAR e uma leitura é iniciada (em iload2).
Figura 4.19 (a) ILOAD com um 
ndice de 1 byte. (b) WIDE ILOAD com um 
ndice de 2 bytes.
INDEX
BYTE 1
INDEX
BYTE 2
WIDE
(0xC4)
ILOAD
(0x15)
ILOAD
(0x15)
INDEX
(a) (b)
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 219
Contudo, a utilização de MBR como um índice é um pouco diferente do que em BIPUSH, onde ele era
estendido em sinal. No caso de um índice, o deslocamento é sempre positivo, portanto, o deslocamento do byte
deve ser interpretado como um inteiro sem sinal, diferente de BIPUSH, onde era interpretado como um inteiro
de 8 bits com sinal. A interface de MBR ao barramento B é projetada para possibilitar ambas as operações. No
caso de BIPUSH (inteiro de 8 bits com sinal), a operação adequada é a extensão de sinal, isto é, o bit da extrema
esquerda no MBR de 1 byte é copiado para os 24 bits superiores no barramento B. No caso de ILOAD (inteiro de
8 bits sem sinal), a operação adequada é preencher com zeros. Nesse caso, os 24 bits superiores do barramento B
são simplesmente fornecidos com zeros. Essas duas operações são distinguidas por sinais separados que indicam
qual operação deve ser executada (veja a Figura 4.6). No microcódigo, isso é indicado por MBR (estendido em
sinal, como em BIPUSH 3) ou MBRU (sem sinal, como em iload2).
Enquanto está esperando que a memória forneça o operando (em iload3), SP é incrementado para conter o
valor para armazenar o resultado, o novo topo da pilha. Esse valor também é copiado para MAR em preparação
para escrever o operando para o topo. Mais uma vez, o PC deve ser incrementado para buscar o próximo opcode
(em iload4). Por fim, MDR é copiado para TOS para refletir o novo topo da pilha (em iload5).
ISTORE é a operação inversa de ILOAD, isto é, uma palavra é retirada do topo da pilha e armazenada na loca-
lização especificada pela soma de LV e do índice contido na instrução. Ela usa o mesmo formato de ILOAD, mos-
trado na Figura 4.19(a), exceto que o opcode é 0x36 em vez de 0x15. Essa instrução é um pouco diferente do que
poderíamos esperar porque a palavra do topo da pilha já é conhecida (em TOS), portanto, ela pode ser armazenada
de imediato. Contudo, a nova palavra do topo da pilha deve ser buscada. Assim, são necessárias uma escrita, bem
como uma leitura, mas elas podem ser realizadas em qualquer ordem (ou até em paralelo, se isso fosse possível).
Ambas, ILOAD e ISTORE, são restritas, já que só podem acessar as primeiras 256 variáveis locais. Ao passo
que para grande parte dos programas esse espaço de variáveis locais seja mais do que suficiente, claro que é
necessário poder acessar uma variável onde quer que ela esteja localizada no espaço de variáveis locais. Para fazer
isso, a JM usa o mesmo mecanismo empregado na JM: um opcode especial WIDE (largo), conhecido como
byte de prefixo, seguido pelo opcode ILOAD ou ISTORE. Quando essa sequência ocorre, as definições de ILOAD
e ISTORE são modificadas, com um índice de 16 bits após o opcode, em vez de um índice de 8 bits, como mostra
a Figura 4.19(b).
WIDE é decodificada do modo usual, levando um desvio para wide1 que manipula o opcode WIDE. Embora o
opcode para alargar (ou ampliar – widen) já esteja disponível em MBR, wide1 busca o primeiro byte após o opcode,
porque a lógica do microprograma sempre espera que ele esteja ali. Então, é feito um segundo desvio multivias
em wide2, agora usando o byte após a WIDE para despachar. Contudo, já que WIDE ILOAD requer microcódigo
diferente do de ILOAD, e WIDE ISTORE requer microcódigo diferente do de ISTORE etc., o segundo desvio mul-
tivias não pode só usar o opcode como endereço de destino, do mesmo modo que faz Main1.
Em vez disso, wide2 efetua uma operação OR de 0x100 com o opcode enquanto o coloca em MPC. O resulta-
do é que a interpretação de WIDE ILOAD começa em 0x115 (em vez de 0x15), a interpretação de WIDE ISTORE
começa em 0x136 (e não 0x36) e assim por diante. Desse modo, todo opcode WIDE começa em um endereço 256
palavras mais alto, isto é, 0x100, no armazenamento de controle que o opcode regular correspondente. A sequên-
cia inicial de microinstruções para ambas, ILOAD e WIDE ILOAD, é mostrada na Figura 4.20.
Uma vez alcançado o código para implementar WIDE ILOAD (0x115), a diferença entre ele e o ILOAD normal
é apenas que o índice deve ser construído concatenando 2 bytes de índice em vez de simplesmente estender em
sinal um byte único. A concatenação e subsequente adição devem ser efetuadas em etapas, primeiro copiando
INDEX BYTE 1 em H deslocado 8 bits para a esquerda. isto que o índice é um inteiro sem sinal, o MBR é esten-
dido em zeros usando MBRU. Agora, o segundo byte do índice é adicionado (a operação de adição é idêntica à
concatenação, já que o byte de ordem baixa de H agora é zero, garantindo que não haverá vai-um entre os bytes)
e, de novo, o resultado é armazenado em H. Daí em diante, a operação pode seguir exatamente como se fosse
uma ILOAD padrão. Em vez de duplicar as instruções finais de ILOAD (iload3 a iload5), apenas desviamos de
wide_iload4 para iload3. Todavia, note que PC deve ser incrementado duas vezes durante a execução da instru-
ção de modo que passe a apontar para o próximo opcode. A instrução ILOAD o incrementa uma vez; a sequência
WIDE_ILOAD também o incrementa uma vez.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
220
Figura 4.20 Seque
ncia inicial de microinstruc
o
es para ILOAD e WIDE ILOAD. Os enderec
os sa
o exemplos.
Endereço
Armazenamento
de controle
Ordem de execução
de microinstrução
ILOAD
WIDE
ILOAD
wide_iload1
Main1 1
wide1
iload1
3
1
2
2
0x1FF
0x115
0x100
0xC4
0x15
0x00
A mesma situação ocorre para WIDE_ISTORE: após a execução das primeiras quatro microinstruções
(wide_istore1 até wide_istore4), a sequência é a mesma de ISTORE após as duas primeiras instruções, portanto,
wide_istore4 desvia para istore3.
Nosso próximo exemplo é uma instrução LDC_W. Esse opcode tem duas diferenças em relação a ILOAD.
A primeira é que ele tem um deslocamento sem sinal de 16 bits (como a versão larga, ou ampliada, de ILOAD). A
segunda, ele é indexado a partir de CPP em vez de LV, pois sua função é ler do conjunto de constantes em vez do
quadro de variáveis locais. (Na verdade, há uma forma curta de LDC_W (LDC), mas não incluímos em JM, já
que a forma longa incorpora todas as possíveis variações da forma curta, mas toma 3 bytes em vez de 2.)
A instrução IINC é a única da JM, exceto a instrução ISTORE, que pode modificar uma variável local. Ela
o faz incluindo dois operandos, cada um de 1 byte de comprimento, como apresenta a Figura 4.21.
Figura 4.21 A instruc
a
o IINC tem dois campos de operando diferentes.
INDEX CONST
IINC
(0x84)
A instrução IINC usa INDEX para especificar o deslocamento em relação ao início do quadro de variáveis
locais. Ela lê aquela variável, incrementando-a por CONST, um valor contido na instrução, e volta a armazená-la
no mesmo local. Note que essa instrução pode incrementar por uma quantidade negativa, isto é, CONST é uma
constante de 8 bits com sinal, na faixa –128 a +127. A JM completa inclui uma versão ampliada da IINC, onde
cada operando tem 2 bytes de comprimento.
Agora, chegamos à primeira instrução de desvio da JM: GOTO. A função exclusiva dessa instrução é alterar
o valor de PC, de modo que a próxima instrução JM executada seja a que está no endereço calculado adicio-
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 221
nando o deslocamento de 16 bits (com sinal) ao endereço opcode do desvio. Uma complicação que surge nesse
caso é que o deslocamento é relativo ao valor que o PC tinha no início da decodificação da instrução, e não ao
valor que ele tem depois que os 2 bytes de deslocamento foram buscados.
Para esclarecer esse ponto, na Figura 4.22(a) vemos a situação no início de Main1. O opcode já está em MBR,
mas o PC ainda não foi incrementado. Na Figura 4.22(b), vemos a situação no início de goto1. A essa altura, o PC
já foi incrementado, mas o primeiro byte do deslocamento ainda não foi buscado para MBR. Uma microinstrução
depois, temos a Figura 4.22(c), na qual o antigo PC, que aponta para o opcode, foi salvo em OPC e o primeiro byte
do deslocamento está em MBR. Esse valor é necessário porque o deslocamento da instrução GOTO da JM é rela-
tiva a ele e não ao valor corrente de PC. Na verdade, essa é a razão primordial por que precisamos do registrador.
Figura 4.22 Situac
a
o no in
cio de va
rias microinstruc
o
es. (a) Main1. (b) goto1. (c) goto2. (d) goto3 (e) goto4.
Memória
1 byte
n + 3
n + 2
n + 1
n
OFFSET BYTE 2
OFFSET BYTE 1
GOTO (0xA7)
OFFSET BYTE 2
OFFSET BYTE 1
GOTO (0xA7)
OFFSET BYTE 2
OFFSET BYTE 1
GOTO (0xA7)
OFFSET BYTE 2
OFFSET BYTE 1
GOTO (0xA7)
OFFSET BYTE 2
OFFSET BYTE 1
GOTO (0xA7)
Registradores
PC
OPC
MBR
H
n
n n n
n + 1 n + 1 n + 2 n + 2
OFFSET BYTE 1 OFFSET BYTE 2
0xA7 OFFSET BYTE 1
0xA7
OFFSET 1 << 8
(a) (b) (c) (d) (e)
A microinstrução em goto2 inicia a busca do segundo byte de deslocamento, o que leva à Figura 4.22(d)
no início de goto3. Depois que o primeiro byte do deslocamento foi deslocado 8 bits para a esquerda e copiado
para H, chegamos em goto4 e à Figura 4.22(e). Agora, temos o primeiro byte de deslocamento desviado para a
esquerda em H, o segundo byte de deslocamento em MBR e a base em OPC. Construindo o deslocamento de
16 bits completo em H e então o adicionando à base, obtemos o novo endereço para colocar em PC, em goto5.
Não se esqueça de observar que usamos MBRU em goto4 em vez de MBR porque não queremos extensão de sinal
do segundo byte. Na verdade, o deslocamento de 16 bits é construído efetuando uma operação OR com as duas
metades. Por fim, temos de buscar o próximo opcode antes de voltar a Main1 porque o código que ali está espera
o próximo opcode em MBR. O último ciclo, goto6, é necessário porque os dados da memória podem ser buscados
a tempo de aparecer em MBR durante Main1.
Os deslocamentos usados na instrução goto da JM são valores de 16 bits com sinal, com um mínimo de
–32768 e um máximo de +32767. sso significa que desvios para qualquer lado para rótulos mais distantes do que
esses valores não são possíveis. Essa propriedade pode ser considerada um bug ou uma característica na JM (e
também na JM). A turma do bug diria que a definição da JM não deveria restringir seu estilo de programação.
A turma da qualidade diria que o trabalho de muitos programadores sofreria uma melhoria radical se eles tivessem
pesadelos com a temida mensagem do compilador:
Program is too big and hairy. You must rewrite it. Compilation aborted.
(Programa muito grande e confuso. ocê precisa reescrevê-lo. Compilação abortada.)
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
222
nfelizmente (de nosso ponto de vista), essa mensagem só aparece quando uma cláusula then ou else passa
de 32 KB, o que normalmente representa 50 páginas de Java.
Agora, considere as três instruções JM de desvio condicional: IFLT, IFEQ e IF_ICMPEQ. As duas primeiras
retiram a palavra que está no topo da pilha, desviando se a palavra for menor do que zero ou igual a zero, respec-
tivamente. IF_ICMPEQ retira as duas palavras do topo da pilha e desvia se, e somente se, elas forem iguais. Em
todos os três casos, é necessário ler uma nova palavra do topo da pilha para armazenar no TOS.
O controle para essas três instruções é semelhante: o operando ou operandos são primeiro colocados em
registradores, depois o novo valor do topo de pilha é lido para o TOS e, por fim, são realizados o teste e o desvio.
Considere IFLT em primeiro lugar. A palavra a testar já está em TOS, porém, como IFLT retira uma palavra da
pilha, o novo topo tem de ser lido para armazenar em TOS. Essa leitura é iniciada em iflt1. Em iflt2, a palavra a ser
testada é salva em OPC por enquanto, portanto, o novo valor pode ser colocado em TOS dentro em pouco sem
perder o valor corrente. Em iflt3, a nova palavra do topo da pilha está disponível em MDR, portanto, é copiada
para TOS. Por fim, em iflt4, a palavra a ser testada, agora salva em OPC, é passada pela ULA sem ser armazenada
e o bit N é amostrado e testado. Essa microinstrução também contém um desvio, que escolhe T se o teste foi
bem-sucedido e F, caso contrário.
Se bem-sucedido, o restante da operação é, em essência, a mesma que no início da instrução GOTO, e a sequên-
cia simplesmente continua no meio da sequência GOTO, com goto2. Se malsucedida, é necessária uma sequência
curta (F, F2 e F3) para pular o resto da instrução (o deslocamento) antes de voltar a Main1 para continuar com
a instrução seguinte.
O código em ifeq2 e ifeq3 segue a mesma lógica, só que usando o bit Z em vez do bit N. Em ambos os casos,
cabe ao assembler de MAL reconhecer que os endereços T e F são especiais e garantir que seus endereços sejam
colocados em endereços de armazenamento de controle cuja diferença seja apenas o bit da extrema esquerda.
A lógica para IF_ICMPEQ é bastante semelhante à IFEQ, exceto que nesse caso precisamos ler também o
segundo operando. Esse operando é armazenado em H em if_icmpeq3, onde a leitura da nova palavra do topo da
pilha é iniciada. Mais uma vez, a palavra do topo da pilha corrente é salva em OPC e a nova é instalada em TOS.
Por fim, o teste em if_icmpeq6 é semelhante a ifeq4.
Agora, consideramos a execução de INVOKEVIRTUAL e IRETURN, as instruções para invocar um procedimento
de chamada e retorno, como descrito na Seção 4.2.3. INVOKEVIRTUAL é uma sequência de 22 microinstruções e é a
mais complexa instrução realizada em JM. Sua operação foi mostrada na Figura 4.12. A instrução usa seu desloca-
mento de 16 bits para determinar o endereço do método a ser invocado. Em nossa implementação, esse deslocamento
é simplesmente um deslocamento no conjunto de constantes. Sua localização nesse conjunto aponta o método a ser
invocado. Contudo, lembre-se de que os primeiros 4 bytes de cada método não são instruções, e sim dois ponteiros de
16 bits. O primeiro dá o número de palavras de parâmetro – incluindo OBJREF (veja a Figura 4.12). O segundo dá o
tamanho da área de variáveis locais em palavras. Esses campos são buscados por meio da porta de 8 bits e montados
exatamente como se fossem deslocamentos de 16 bits dentro de uma instrução.
Então, a informação de enlace necessária para restaurar a máquina a seu estado anterior – o endereço do
início da área de variáveis antiga e o PC antigo – é armazenada imediatamente acima da área de variáveis locais
recém-criada e abaixo da nova pilha. Por fim, o opcode da próxima instrução é buscado e o PC é incrementado
antes de retornar a Main1 para iniciar a próxima instrução.
IRETURN é uma instrução simples que não contém operandos. Ela apenas usa o endereço armazenado na
primeira palavra da área de variáveis locais para recuperar a informação de ligação, então, restaura SP, LV e PC
a seus valores anteriores e copia o valor de retorno do topo da pilha corrente para o topo da pilha original, con-
forme ilustra a Figura 4.13.
4.4 Projeto do n
vel de microarquitetura
Como quase tudo na ciência da computação, o projeto da microarquitetura está repleto de compromissos.
Computadores têm muitas características desejáveis, entre elas velocidade, custo, confiabilidade, facilidade de
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 223
utilização, requisitos de energia e tamanho físico. Contudo, um compromisso comanda as decisões mais impor-
tantes que os projetistas de CPU devem tomar: velocidade versus custo. Nesta seção, estudaremos esse assunto
detalhadamente, para ver o que pode ser permutado pelo que, que grau de desempenho pode ser alcançado e a que
preço em hardware e complexidade.
4.4.1 Velocidade versus custo
Embora a tecnologia mais rápida tenha resultado no maior dos aumentos de velocidade em qualquer perío-
do de tempo considerado, esse assunto não se enquadra no escopo deste livro. Melhorias de velocidade graças
à organização, embora menos espetaculares do que as propiciadas por circuitos mais rápidos, ainda assim são
impressionantes. elocidade pode ser medida de várias maneiras, mas dadas uma tecnologia de circuitos e uma
SA, há três abordagens básicas para aumentar a velocidade de execução:
1. Reduzir o número de ciclos de clock necessários para executar uma instrução.
2. Simplificar a organização de modo que o ciclo de clock possa ser mais curto.
3. Sobrepor a execução de instruções.
As duas primeiras são óbvias, mas há uma surpreendente variedade de oportunidades de projeto que pode afe-
tar drasticamente o número de ciclos de clock, o período de clock, ou – em grande parte das vezes – ambos. Nesta
seção, daremos um exemplo de como a codificação e a decodificação de uma operação podem afetar o ciclo de clock.
O número de ciclos de clock necessários para executar um conjunto de operações é conhecido como compri-
mento do caminho. Às vezes, o comprimento do caminho pode ser encurtado adicionando-se hardware especiali-
zado. Por exemplo, adicionando um incrementador – conceitualmente, um somador com um lado ligado de modo
permanente a “some 1” (add 1) – ao PC, não precisamos mais usar a ULA para fazer avançar o PC, eliminando
ciclos. O preço a pagar é mais hardware. Todavia, essa capacidade não ajuda tanto como seria de esperar. Na
maioria das instruções, os ciclos consumidos para incrementar o PC também são ciclos em que uma operação de
leitura está sendo executada. Em todo caso, a instrução seguinte não pode ser executada mais cedo porque ela
depende dos dados que vêm da memória.
Reduzir o número de ciclos de instrução necessários para buscar instruções requer mais do que apenas um
circuito adicional para incrementar o PC. Para acelerar a busca de instrução em qualquer grau significativo, a
terceira técnica – sobreposição de execução – deve ser explorada. Separar o circuito de busca de instruções – a
porta de memória de 8 bits e os registradores MBR e PC – é mais efetivo se, em termos funcionais, a unidade for
montada independentemente do caminho de dados principal. Desse modo, ela pode buscar o próximo opcode
ou operando por conta própria, talvez até mesmo executando fora de sincronia em relação ao restante da CPU e
buscando uma ou mais instruções com antecedência.
Uma das fases que mais consome o tempo da execução de muitas das instruções é buscar um deslocamento
de 2 bytes, estendê-lo adequadamente e acumular no registrador H em preparação para uma adição, por exemplo,
em um desvio para PC ± n bytes. Uma solução potencial – construir uma porta de memória de 16 bits de largu-
ra – complica muito a operação porque, na verdade, a memória tem 32 bits de largura. Os 16 bits necessários
podem se espalhar por fronteiras de palavras, de modo que até mesmo uma única leitura de 32 bits não buscará
necessariamente ambos os bytes necessários.
Sobrepor a execução de instruções é, de longe, o mais interessante e oferece a melhor oportunidade para
drásticos aumentos de velocidade. A simples sobreposição da busca e execução de instruções dá um resultado
surpreendentemente efetivo. Entretanto, técnicas mais sofisticadas avançam muito mais, sobrepondo a execução
de muitas instruções. Na verdade, essa ideia está no coração do projeto de computadores modernos. Mais adiante,
discutiremos algumas das técnicas básicas para sobrepor a execução de instruções e apresentaremos o motivo
para as mais sofisticadas.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
224
elocidade é apenas uma metade do quadro; custo é a outra. O custo pode ser medido de vários modos,
mas uma definição precisa é problemática. Algumas medidas são muito simples, tal como uma contagem do
número de componentes, o que era válido em particular na época em que os processadores eram compostos de
componentes discretos, que eram comprados e montados. Hoje, o processador inteiro está contido em um único
chip, mas chips maiores e mais complexos são muito mais caros do que os menores, mais simples. Componentes
individuais – por exemplo, transistores, portas ou unidades funcionais – podem ser contados, mas quase sempre
o número resultante não é tão importante quanto a quantidade de área requerida no circuito integrado. Quanto
mais área for requerida para as funções incluídas, maior será o chip, e o custo de fabricação deste cresce com
rapidez muito maior do que sua área. Por essa razão, projetistas costumam falar de custo em termos utilizados na
área imobiliária, isto é, a área exigida por um circuito (imagino que seja medida em pico-hectares).
Um dos circuitos mais exaustivamente estudados na história é o somador binário. Há milhares de projetos
e os mais rápidos são muito mais velozes do que os mais lentos – e também muito mais complexos. O projetista
de sistemas tem de decidir se a maior velocidade vale o preço do espaço.
Somadores não são os únicos componentes que têm muitas opções. Praticamente qualquer componente do
sistema pode ser projetado para executar de modo mais rápido ou mais lento, com um diferencial de custo. O
desafio para o projetista é identificar os componentes que mais podem melhorar o sistema e então aumentar a
velocidade deles. O interessante é que muitos componentes individuais podem ser substituídos por um muito
mais veloz e causar pouco ou nenhum efeito sobre a velocidade. Nas seções seguintes, examinaremos algumas
das questões de projeto e os compromissos correspondentes.
Um dos fatores fundamentais para determinar a velocidade em que um clock pode executar é a quantidade
de trabalho que deve ser realizada em cada ciclo de clock. É óbvio que, quanto mais trabalho a ser realizado,
mais longo será o ciclo. Claro que não é assim tão simples, porque o hardware é muito bom para fazer coisas em
paralelo. Portanto, na verdade, o que determina o comprimento do ciclo de clock é a sequência de operações que
devem ser executadas em série em um único ciclo.
Um aspecto que pode ser controlado é a quantidade de decodificação que deve ser realizada. Lembre-se, por
exemplo, de que na Figura 4.6 vimos que, embora qualquer um de nove registradores pudesse ser lido para a
ULA a partir do barramento B, precisávamos de apenas 4 bits na palavra de microinstrução para especificar qual
registrador devia ser selecionado. nfelizmente, essas economias têm um preço. O circuito de decodificação agrega
atraso ao caminho crítico, e isso significa que qualquer registrador que habilite seus dados para o barramento B
receberá o comando um pouquinho mais tarde e obterá seus dados no barramento um pouquinho mais tarde.
sso provoca um efeito em cascata, com a ULA recebendo suas entradas um pouco mais tarde e produzindo seus
resultados um pouco mais tarde. Por fim, o resultado estará disponível no barramento C para ser escrito nos regis-
tradores também um pouco mais tarde. Como esse atraso muitas vezes é o fator que determina o comprimento do
ciclo de clock, isso pode significar que o clock não pode funcionar com tanta rapidez e todo o computador deve
funcionar um pouco mais lentamente. Assim, há uma permuta entre velocidade e custo. A redução do armaze-
namento de controle em 5 bits por palavra é obtida ao custo da redução da velocidade do clock. O engenheiro
deve levar em conta os objetivos do projeto ao decidir qual é a opção correta. Para uma implementação de alto
desempenho, usar um decodificador talvez não seja uma boa ideia; para uma de baixo custo, pode ser.
4.4.2 Reduc
a
o do comprimento do caminho de execuc
a
o
A Mic-1 foi projetada para ser moderadamente simples e moderadamente rápida, embora admitamos que há
uma enorme tensão entre esses dois objetivos. Em poucas palavras, máquinas simples não são rápidas e máquinas
rápidas não são simples. A CPU da Mic-1 também usa uma quantidade mínima de hardware: 10 registradores, a
ULA simples da Figura 3.19 repetida 32 vezes, um deslocador, um decodificador, um armazenamento de controle
e um pouquinho de cola aqui e ali. O sistema inteiro poderia ser montado com menos de 5.000 transistores mais
o tanto que o armazenamento de controle (ROM) e a memória principal (RAM) precisarem.
Agora que já vimos como JM pode ser executada de modo direto em microcódigo com pouco hardware, é
hora de examinar implementações alternativas, mais rápidas. A seguir, vamos estudar modos de reduzir o número
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 225
de microinstruções por instrução SA (isto é, reduzir o comprimento do caminho de execução). Depois disso,
vamos considerar outras técnicas.
Incorporac
a
o do lac
o do interpretador ao microco
digo
Na Mic-1, o laço principal consiste em uma microinstrução que deve ser executada no início de cada ins-
trução JM. Em alguns casos, é possível sobrepô-la à instrução anterior. Na verdade, isso já foi conseguido, ao
menos em parte. Note que, quando Main1 é executada, o opcode a ser interpretado já está em MBR. O opcode está
ali porque foi buscado pelo laço principal anterior (se a instrução anterior não tinha operandos) ou durante a
execução da instrução anterior.
Esse conceito de sobrepor o início da instrução pode ser levado mais adiante e, na realidade, em alguns casos
o laço principal pode ser reduzido a nada. sso pode ocorrer da seguinte maneira. Considere cada sequência de
microinstruções que termina desviando para Main1. Em cada lugar, a microinstrução do laço principal pode ser
agregada ao final da sequência, em vez de ao início da próxima, e o desvio multivias agora é repetido em muitos
lugares, mas sempre com o mesmo conjunto de alvos. Em alguns casos, a microinstrução Main1 pode ser incor-
porada a microinstruções anteriores, já que elas nem sempre são totalmente utilizadas.
Na Figura 4.23, é mostrada a sequência dinâmica de instruções para uma instrução POP. O laço principal
ocorre antes e depois de cada instrução; na figura, mostramos apenas a ocorrência após a instrução POP. Note
que a execução dessa instrução leva quatro ciclos de clock: três para as microinstruções específicas para POP e
um para o laço principal.
Figura 4.23 Seque
ncia original de microprograma para executar POP.
Rótulo Operações Comentários
pop1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
pop2 Espere novo TOS ser lido da memória
pop3 TOS = MDR; goto Main1 Copie nova palavra para TOS
Main1 PC = PC + 1; fetch; goto (MBR) MBR contém o opcode; obtenha próximo byte; despache
Na Figura 4.24, a sequência foi reduzida a três instruções que incorporam as instruções do laço principal,
aproveitando um ciclo de clock no qual a ULA não é usada em pop2 para economizar um ciclo e novamente em
Main1. Não se esqueça de observar que o final dessa sequência desvia diretamente para o código específico para a
instrução seguinte, portanto, são requeridos apenas três ciclos no total. Esse pequeno estratagema reduz em um
ciclo o tempo de execução da próxima microinstrução; portanto, por exemplo, uma IADD subsequente passa de
quatro ciclos para três. Assim, isso equivale a aumentar a velocidade do clock de 250 MHz (microinstruções de 4
ns) para 333 MHz (microinstruções de 3 ns) sem pagar nada.
Figura 4.24 Seque
ncia de microprograma melhorada para executar POP.
Rótulo Operações Comentários
pop1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
Main1.pop PC = PC + 1; fetch MBR contém opcode; busque próximo byte
pop3 TOS = MDR; goto (MBR) Copie nova palavra para TOS; despache em opcode
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
226
A instrução POP se encaixa particularmente nesse tratamento porque ela tem um ciclo ocioso no meio que não
usa a ULA. Contudo, o laço principal usa a ULA. Por isso, reduzir o comprimento da instrução por um fator dentro
dela requer achar um ciclo na instrução no qual a ULA não está em uso. Esses ciclos ociosos não são comuns, mas
ocorrem; portanto, vale a pena incorporar Main1 ao final de cada sequência de microinstrução. Tudo isso custa um
pouco de armazenamento de controle. Assim, temos nossa primeira técnica para reduzir o comprimento do caminho:
Incorpore o laço do interpretador ao final de cada sequência de microcódigo.
Arquitetura de tre
s barramentos
O que mais podemos fazer para reduzir o comprimento do caminho de execução? Outra solução fácil é ter
dois barramentos completos de entrada para ULA, um barramento A e um B, o que dá três barramentos no total.
Todos os registradores (ou ao menos a maioria deles) devem ter acesso a ambos os barramentos de entrada. A
vantagem de ter dois barramentos de entrada é que então é possível adicionar qualquer registrador a qualquer
outro registrador em um só ciclo. Para ver o valor dessa característica, considere a execução de ILOAD na Mic-1,
apresentada novamente na Figura 4.25.
Figura 4.25 Co
digo Mic-1 para executar ILOAD.
Rótulo Operações Comentários
iload1 H = LV MBR contém índice; copie LV para H
iload2 MAR = MBRU + H; rd MAR = endereço de variáveis locais a buscar
iload3 MAR = SP = SP + 1 SP aponta para novo topo da pilha; prepare escrita
iload4 PC = PC + 1; fetch; wr Incremente PC; obtenha novo opcode; escreva topo da pilha
iload5 TOS = MDR; goto Main1 Atualize TOS
Main1 PC = PC + 1; fetch; goto (MBR) MBR contém opcode; obtenha próximo byte; despache
emos aqui que, em iload1, LV é copiado para H. A única razão para LV ser copiado para H é que, assim, ele
poder ser adicionado a MBRU em iload2. Em nosso projeto original de dois barramentos, não há nenhum modo
de adicionar registradores arbitrários, portanto, primeiro um deles tem de ser copiado para H. Com nosso novo
projeto de três barramentos, podemos economizar um ciclo, conforme mostra a Figura 4.26. Nesse caso, adi-
cionamos o laço do interpretador a ILOAD, mas isso nem aumenta nem diminui o comprimento do caminho de
execução. Ainda assim, o barramento adicional reduziu o tempo total de execução de ILOAD de seis para cinco
ciclos. Agora, temos nossa segunda técnica para reduzir o comprimento de caminho:
Passe de um projeto de dois barramentos para um projeto de três barramentos.
Figura 4.26 Co
digo de tre
s barramentos para executar ILOAD.
Rótulo Operações Comentários
iload1 MAR = MBRU + LV; rd MAR = endereço de variável local a buscar
iload2 MAR = SP = SP + 1 SP aponta para novo topo da pilha; prepare escrita
iload3 PC = PC + 1; fetch; wr Incremente PC; obtenha novo opcode; escreva topo da pilha
iload4 TOS = MDR Atualize TOS
iload5 PC = PC + 1; fetch; goto (MBR) MBR já contém opcode; busque byte de índice
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 227
Unidade de busca de instruc
a
o
ale a pena usar essas duas técnicas, mas, para conseguir uma melhoria drástica, precisamos de algo muito
mais radical. amos voltar atrás um pouco e examinar as partes comuns de toda instrução: a busca e a decodifi-
cação dos campos da instrução. Observe que, para cada instrução, podem ocorrer as seguintes operações:
1. O PC é passado pela ULA e incrementado.
2. O PC é usado para buscar o próximo byte na sequência de instruções.
3. Operandos são lidos da memória.
4. Operandos são escritos para a memória.
5. A ULA efetua um cálculo e os resultados são armazenados de volta.
Se uma instrução tiver campos adicionais (para operandos), cada campo deve ser buscado explicitamente,
um byte por vez, e montado antes de poder ser usado. Buscar e montar um campo ocupa a ULA por no mínimo
um ciclo por byte para incrementar o PC, e então de novo para montar o índice ou deslocamento resultante. A
ULA é usada em praticamente todos os ciclos para uma série de operações que têm a ver com buscar a instrução
e montar os campos dentro da instrução, além do “trabalho” real da instrução.
Para sobrepor o laço principal, é necessário liberar a ULA de algumas dessas tarefas. sso poderia ser feito
com a introdução de uma segunda ULA, embora não seja necessária uma completa para grande parte da atividade.
Observe que, em muitos casos, ela é apenas usada como um caminho para copiar um valor de um registrador para
outro. Esses ciclos poderiam ser eliminados introduzindo-se caminhos de dados adicionais que não passem pela
ULA. Como exemplo, pode-se conseguir algum benefício criando um caminho de TOS a MDR, ou de MDR a TOS,
uma vez que a palavra do topo da pilha é muitas vezes copiada entre esses dois registradores.
Na Mic-1, grande parte da carga pode ser retirada da ULA criando uma unidade independente para buscar e
processar as instruções. Essa unidade, denomina IFU (Instruction Fetch Unit  unidade de busca de instrução),
pode incrementar o PC independentemente e buscar bytes antes de eles serem necessários. Essa unidade requer
apenas um incrementador, um circuito muito mais simples do que um somador completo. Levando essa ideia
mais adiante, a FU também pode montar operandos de 8 e 16 bits de modo que eles estejam prontos para uso
imediato sempre que necessário. Há no mínimo dois modos de fazer isso:
1. A FU pode interpretar cada opcode, determinando quantos campos adicionais devem ser buscados, e
montá-los em um registrador pronto para a utilização pela unidade de execução principal.
2. A FU pode aproveitar a natureza sequencial das instruções e disponibilizar os próximos fragmentos de
8 e 16 bits todas as vezes, quer isso tenha ou não algum sentido. Então, a unidade de execução principal
pode requisitar o que precisar.
Mostramos os rudimentos do segundo esquema na Figura 4.27. Em vez de um único MBR de 8 bits, agora há
dois MBRs: o MBR1 de 8 bits e o MBR2 de 16 bits. A FU monitora o(s) byte(s) mais recentemente consumido(s)
pela unidade de execução principal. Também disponibiliza o próximo byte em MBR1 como na Mic-1, exceto que
percebe automaticamente quando MBR1 é lido, busca o próximo byte por antecipação e o carrega em MBR1 de
imediato. Como na Mic-1, ela tem duas interfaces com o barramento B: MBR1 e MBR1U. A primeira é estendida
em sinal para 32 bits; a outra é estendida para zero.
De modo semelhante, o MBR2 oferece a mesma funcionalidade, mas contém os próximos 2 bytes. Também
tem duas interfaces com o barramento B: MBR2 e MBR2U, que copiam os valores de 32 bits estendidos em sinal
e estendidos em zeros, respectivamente.
A FU é responsável por buscar uma sequência de bytes, e faz isso usando uma porta de memória con-
vencional de 4 bytes, buscando palavras inteiras de 4 bytes antes da hora e carregando os bytes consecutivos
em um registrador de deslocamento que os fornece um ou dois por vez, na ordem em que foram buscados. A
função do registrador de deslocamento é manter uma fila de bytes da memória, para alimentar MBR1 e MBR2.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
228
Figura 4.27 Unidade de busca para a Mic-1.
MBR2
Registrador de deslocamento
Da memória
MBR1
+1
Escreva PC
2 bits de ordem baixa
Barramento B
Barramento C
IMAR
PC
+1, 2
Em todas as vezes, MBR1 contém o byte mais antigo no registrador de deslocamento e MBR2 contém os 2
bytes mais antigos (byte mais antigo na esquerda), para formar um inteiro de 16 bits (veja a Figura 4.19(b)).
Os 2 bytes em MBR2 podem ser de palavras de memória diferentes, porque instruções JM não se alinham em
fronteiras de palavras na memória.
Sempre que MBR1 é lido, o registrador de deslocamento desloca 1 byte para a direita. Sempre que MBR2 é lido,
ele desloca 2 bytes para a direita. Então, MBR1 e MBR2 são recarregados a partir do byte mais antigo e do par de
bytes mais antigo, respectivamente. Se agora restar espaço suficiente no registrador de deslocamento para mais outra
palavra inteira, a FU inicia um ciclo de memória para lê-la. Admitimos que, quando qualquer um dos registradores
MBR é lido, ele é preenchido outra vez no início do ciclo seguinte, de modo que pode ser lido em ciclos consecutivos.
O projeto da FU pode ser modelado por uma FSM (Finite State Machine  máquina de estado finito),
como ilustra a Figura 4.28. Todas as FSMs consistem em duas partes: estados, representados por círculos, e
transições, representadas por arcos que vão de um estado a outro. Cada estado representa uma situação possível
na qual a FSM pode estar. Essa FSM particular tem sete estados, correspondentes aos estados do registrador de
deslocamento da Figura 4.27. Os sete estados correspondem à quantidade de bytes que estão naquele registrador
no momento em questão, um número entre 0 e 6, inclusive.
Cada arco representa um evento que pode ocorrer. Três eventos diferentes podem ocorrer nesse caso. O pri-
meiro deles é a leitura de 1 byte do MBR1. Esse evento faz o registrador de deslocamento ser ativado e 1 byte ser
deslocado para fora da extremidade direita, que reduz o estado por um fator de 1. O segundo evento é a leitura
de 2 bytes do MBR2, o que reduz o estado por um fator de dois. Essas duas transições fazem MBR1 e MBR2 serem
recarregados. Quando a FSM passa para os estados 0, 1 ou 2, é iniciada uma referência à memória para buscar
uma nova palavra (considerando que a memória já não esteja ocupada lendo uma). A chegada da palavra adianta
o estado por um fator de 4.
Para trabalhar corretamente, a FU deve bloquear quando requisitada a fazer algo que não pode, tal como for-
necer o valor de MBR2 quando há somente 1 byte no registrador de deslocamento e a memória ainda está ocupada
buscando uma nova palavra. Além disso, ela só pode fazer uma coisa por vez, portanto, eventos que estão chegan-
do devem ser serializados. Por fim, sempre que o PC é alterado, a FU deve ser atualizada. Esses detalhes a tornam
mais complicada do que mostramos. Ainda assim, muitos dispositivos de hardware são construídos como FSMs.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 229
Figura 4.28 Ma
quina de estado finito para implementar a IFU.
Palavra buscada
Palavra buscada
Palavra buscada
0
MBR1
MBR2
MBR2
MBR2 MBR2
MBR2
Transições
MBR1: ocorre quando MBR1 é lido
MBR2: ocorre quando MBR2 é lido
Palavra buscada: ocorre quando uma palavra da memória é lida e 4 bytes são colocados
no registrador de deslocamento
1
MBR1
2
MBR1
3
MBR1
4
MBR1
5
MBR1
6
A FU tem seu próprio registrador de endereço de memória, denominado IMAR, que é usado para endereçar
a memória quando uma nova palavra tem de ser buscada. Esse registrador tem seu próprio incrementador dedi-
cado, de modo que a ULA principal não é necessária para incrementá-lo nem para buscar a próxima palavra. A
FU deve monitorar o barramento C de modo que, sempre que PC for carregado, o novo valor de PC é copiado
para IMAR. Uma vez que o novo valor em PC pode não estar sobre uma fronteira de palavra, a FU tem de buscar
a palavra necessária e fazer o ajuste adequado do registrador de deslocamento.
Com a FU, a unidade de execução principal escreve para o PC somente quando for necessário alterar a natu-
reza sequencial do fluxo de bytes da instrução. Ela escreve por causa de uma instrução de desvio bem-sucedida
e em virtude da INVOKEVIRTUAL e IRETURN.
Já que o microprograma não mais incrementa o PC explicitamente, porque opcodes são buscados, a FU deve
manter o PC atualizado. Ela o faz percebendo quando um byte da instrução foi consumido, isto é, quando MBR1
ou MBR2, ou as versões sem sinal, foram lidos. Associado com o PC há um incrementador separado, capaz de
incrementar por fatores de 1 ou 2, dependendo de quantos bytes foram consumidos. Assim, o PC sempre contém
o endereço do primeiro byte que não foi consumido. No início de cada instrução, MBR contém o endereço do
opcode para aquela instrução.
Note que há dois incrementadores separados e eles executam funções diferentes. O PC conta bytes e incre-
menta por um fator de 1 ou 2. O IMAR conta palavras, e incrementa somente por um fator de 1 (para 4 bytes
novos). Como o MAR, o IMAR está ligado “obliquamente” ao barramento de endereço, sendo que o bit 0 do IMAR
está conectado à linha de endereço 2, e assim por diante, para efetuar uma conversão implícita de endereços de
palavras para endereços de bytes.
Como detalharemos em breve, não ter de incrementar o PC no laço principal representa um grande ganho,
porque a microinstrução na qual ele é incrementado costuma fazer pouco mais do que isso. Se tal microinstrução
puder ser eliminada, o caminho de execução pode ser reduzido. Nesse caso, a permuta é mais hardware por uma
máquina mais rápida, portanto, nossa terceira técnica para reduzir o comprimento do caminho é:
Busque instruções na memória com uma unidade funcional especializada.
4.4.3 O projeto com busca antecipada: a Mic-2
A FU pode reduzir muito o comprimento do caminho da instrução média. Primeiro, ela elimina todo o laço
principal, visto que o final de cada instrução apenas desvia diretamente para a próxima. Segundo, evita ocupar
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
230
a ULA com a tarefa de incrementar o PC. Terceiro, reduz o comprimento do caminho sempre que um índice de
16 bits ou um deslocamento é calculado, porque ela monta o valor de 16 bits e o passa diretamente para a ULA
como um valor de 32 bits, evitando a necessidade de montagem em H. A Figura 4.29 mostra a Mic-2, uma versão
melhorada da Mic-1 à qual foi acrescentada a FU da Figura 4.27. O microcódigo para a máquina melhorada é
ilustrado na Figura 4.30.
Figura 4.29 O caminho de dados para a Mic-2.
H
Deslocador
ULA
N
Barramento B
Barramento C
6
Controle
da ULA
Sinais de controle
Registradores
de controle de
memória
Habilite para barramento B
Escreva barramento C para registrador
De e
para a
memória
principal
Z
MBR2
SP
LV
CPP
TOS
PC
MDR
MAR
MBR
OPC
Unidade
de busca
de instrução
(IFU)
Barramento A
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 231
Figura 4.30 Microprograma para a Mic-2.
Rótulo Operações Comentários
nop1 goto (MBR) Desvie para a próxima instrução
iadd1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
iadd2 H = TOS H = topo da pilha
iadd3 MDR = TOS = MDR + H; wr; goto (MBR1)
Some duas palavras do topo; escreva para novo topo da
pilha
isub1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
isub2 H = TOS H = topo da pilha
isub3 MDR = TOS = MDR – H; wr; goto (MBR1) Subtraia TOS da palavra anterior na pilha
iand1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
iand2 H = TOS H = topo da pilha
iand3 MDR = TOS = MDR AND H; wr; goto (MBR1) AND palavra anterior da pilha com TOS
ior1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
ior2 H = TOS H = topo da pilha
ior3 MDR = TOS = MDR OR H; wr; goto (MBR1) OR palavra anterior da pilha com TOS
dup1 MAR = SP = SP + 1 Incremente SP; copie para MAR
dup2 MDR = TOS; wr; goto (MBR1) Escreva nova palavra da pilha
pop1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
pop2 Espere pela leitura
pop3 TOS = MDR; goto (MBR1) Copie nova palavra para TOS
swap1 MAR = SP – 1; rd Leia a segunda palavra da pilha; ajuste MAR para SP
swap2 MAR = SP Prepare para escrever nova 2a
palavra
swap3 H = MDR; wr Salve novo TOS; escreva 2a
palavra para pilha
swap4 MDR = TOS Copie antigo TOS para MDR
swap5 MAR = SP – 1; wr Escreva antigo TOS para 2o
lugar na pilha
swap6 TOS = H; goto (MBR1) Atualize TOS
bipush1 SP = MAR = SP + 1 Ajuste MAR para escrever para novo topo da pilha
bipush2 MDR = TOS = MBR1; wr; goto (MBR1) Atualize pilha em TOS e memória
iload1 MAR = LV + MBR1U; rd Passe LV + índice para MAR; leia operando
iload2 MAR = SP = SP + 1 Incremente SP; passe novo SP para MAR
iload3 TOS = MDR; wr; goto (MBR1) Atualize pilha em TOS e memória
istore1 MAR = LV + MBR1U Ajuste MAR para LV + índice
istore2 MDR = TOS; wr Copie TOS para armazenamento
istore3 MAR = SP = SP – 1; rd Decremente SP; leia novo TOS
istore4 Espere por leitura
istore5 TOS = MDR; goto (MBR1) Atualize TOS
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
232
Rótulo Operações Comentários
wide1 goto (MBR1 OR 0x100)
Próximo endereço é 0x100 com operação OR efetuada com
opcode
wide_iload1 MAR = LV + MBR2U; rd; goto iload2 Idêntica a iload1 mas usando índice de 2 bytes
wide_istore1 MAR = LV + MBR2U; goto istore2 Idêntica a istore1 mas usando índice de 2 bytes
ldc_w1 MAR = CPP + MBR2U; rd; goto iload2 O mesmo que wide_iload1 mas indexando a partir de CPP
iinc1 MAR = LV + MBR1U; rd Ajuste MAR para LV + índice para leitura
iinc2 H = MBR1 Ajuste H para constante
iinc3 MDR = MDR + H; wr; goto (MBR1) Incremente por constante e atualize
goto1 H = PC – 1 Copie PC para H
goto2 PC = H + MBR2 Some deslocamento e atualize PC
goto3 Tem de esperar que IFU busque novo opcode
goto4 goto (MBR1) Despache para a próxima instrução
iflt1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
iflt2 OPC = TOS Salve TOS em OPC temporariamente
iflt3 TOS = MDR Ponha novo topo da pilha em TOS
iflt4 N = OPC; if (N) goto T; else goto F Desvie no bit N
ifeq1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
ifeq2 OPC = TOS Salve TOS em OPC temporariamente
ifeq3 TOS = MDR Ponha novo topo da pilha em TOS
ifeq4 Z = OPC; if (Z) goto T; else goto F Desvie no bit Z
if_icmpeq1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha
if_icmpeq2 MAR = SP = SP – 1 Ajuste MAR para ler novo topo da pilha
if_icmpeq3 H = MDR; rd Copie segunda palavra da pilha para H
if_icmpeq4 OPC = TOS Salve TOS em OPC temporariamente
if_icmpeq5 TOS = MDR Ponha novo topo da pilha em TOS
if_icmpeq6 Z = H – OPC; if (Z) goto T; else goto F Se 2 palavras do topo forem iguais, vá para T, senão vá para F
T H = PC – 1; goto goto2 O mesmo que goto1
F H = MBR2 Toque bytes em MBR2 para descartar
F2 goto (MBR1)
invokevirtual1 MAR = CPP + MBR2U; rd Ponha endereço de ponteiro de método em MAR
invokevirtual2 OPC = PC Salve Return PC em OPC
invokevirtual3 PC = MDR Ajuste PC para 1o
byte do código de método
invokevirtual4 TOS = SP – MBR2U TOS = endereço de OBJREF – 1
invokevirtual5 TOS = MAR = H = TOS + 1 TOS = endereço de OBJREF
invokevirtual6 MDR = SP + MBR2U + 1; wr Sobrescreva OBJREF com ponteiro de ligação
invokevirtual7 MAR = SP = MDR Ajuste SP, MAR à localização para conter PC antigo
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 233
Rótulo Operações Comentários
invokevirtual8 MDR = OPC; wr Prepare para salvar PC antigo
invokevirtual9 MAR = SP = SP + 1
Incremente SP para apontar para a localização para conter LV
antigo
invokevirtual10 MDR = LV; wr Salve LV antigo
invokevirtual11 LV = TOS; goto (MBR1) Ajuste LV para apontar para o parâmetro de ordem zero
ireturn1 MAR = SP = LV; rd Reajuste SP, MAR para ler ponteiro de ligação
ireturn2 Espere por ponteiro de ligação
ireturn3 LV = MAR = MDR; rd Ajuste LV, MAR para ponteiro de ligação; leia PC antigo
ireturn4 MAR = LV + 1 Ajuste MAR para apontar para LV antigo; leia LV antigo
ireturn5 PC = MDR; rd Restaure PC
ireturn6 MAR = SP
ireturn7 LV = MDR Restaure LV
ireturn8 MDR = TOS; wr; goto (MBR1) Salve valor de retorno no topo da pilha original
Como exemplo do modo de funcionamento da Mic-2, examine a IADD. Ela pega a segunda palavra em uma
pilha e efetua a adição como antes, só que agora, quando termina, ela não tem de ir até Main1 para incremen-
tar PC e despachar para a próxima microinstrução. Quando a FU vê que MBR1 foi referenciado em iadd3, seu
registrador de deslocamento interno empurra tudo para a direita e recarrega MBR1 e MBR2. Ela também faz a
transição para um estado um grau mais baixo do que o corrente. Se o novo estado for 2, a FU começa a buscar
uma palavra da memória. Tudo isso é feito em hardware – o microprograma não tem de fazer nada. É por isso
que a IADD pode ser reduzida de quatro para três microinstruções.
A Mic-2 melhora algumas instruções mais do que outras. LDC_W passa de nove microinstruções para ape-
nas três, reduzindo seu tempo de execução por um fator de três. Por outro lado, SWAP só passa de oito para seis
microinstruções. O que de fato conta para o desempenho geral é o ganho para as instruções mais comuns. Podemos
citar ILOAD (eram 6, agora são 3), IADD (eram 4, agora são 3) e IF_ICMPEQ (eram 13, agora são 10 para o caso
do desvio tomado; eram 10, agora são 8 para o caso do desvio não tomado). Para medir a melhoria, teríamos de
escolher e executar alguns padrões de comparação, mas é claro que tudo isso representa um grande ganho.
4.4.4 Projeto com pipeline: a Mic-3
A Mic-2 é uma melhoria clara em relação à Mic-1. É mais rápida e usa menos armazenamento de controle, em-
bora o custo da FU sem dúvida seja maior do que o ganho obtido por ter um armazenamento de controle menor.
Portanto, ela é uma máquina bem mais rápida por um preço pouca coisa mais alto. amos ver se podemos fazê-la
ficar ainda mais rápida.
Que tal tentar reduzir o tempo de ciclo? Ele é determinado, em considerável proporção, pela tecnologia sub-
jacente. Quanto menores os transistores e mais curtas as distâncias físicas entre eles, mais rapidamente o clock
pode ser executado. Para uma determinada tecnologia, o tempo requerido para executar uma operação completa
de caminho de dados é fixo (ao menos de nosso ponto de vista). Ainda assim, temos certa liberdade e em breve
a exploraremos ao máximo.
Nossa outra opção é introduzir mais paralelismo na máquina. No momento, a Mic-2 é altamente sequencial.
Ela coloca registradores em seus barramentos, espera que a ULA e o deslocador os processem para depois escrever
os resultados de volta nos registradores. Exceto pela FU, há pouco paralelismo presente. Adicionar paralelismo
é uma oportunidade real.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
234
Como já dissemos, o ciclo de clock é limitado pelo tempo necessário para que os sinais se propaguem pelo
caminho de dados. A Figura 4.3 mostra um desdobramento do atraso em vários componentes durante cada ciclo.
Há três componentes importantes no ciclo do caminho de dados propriamente dito:
1. O tempo para levar os registradores selecionados até os barramentos A e B.
2. O tempo para que a ULA e o deslocador realizem seu trabalho.
3. O tempo para os resultados voltarem aos registradores e serem armazenados.
Na Figura 4.31, mostramos uma nova arquitetura e três barramentos, incluindo a FU, mas com três regis-
tradores adicionais, cada um inserido no meio de cada barramento. Os registradores são escritos em todo o ciclo.
Na realidade, eles repartem o caminho de dados em partes distintas que agora podem funcionar de modo inde-
pendente. Denominaremos isso Mic-3, ou modelo pipeline.
Figura 4.31 Caminho de dados de tre
s barramentos usados em Mic-3.
H
Latch A
Latch C Latch B
Deslocador
ULA
N
Barramento B
Barramento C
6
Controle
da ULA
Sinais de controle
Registradores
de controle
da memória
Habilite para barramento B
Escreva barramento C no registrador
De e
para
memória
principal
Z
MBR2
SP
LV
CPP
TOS
PC
MDR
MAR
MBR1
OPC
Unidade
de busca
de instrução
Barramento A
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 235
Como esses registradores extras podem ajudar? Agora, leva três ciclos de clock para usar o caminho de dados:
um para carregar os latches A e B, um para executar a ULA e deslocador e carregar o latch C, e um para armazenar
o latch C de volta nos registradores. Certamente, isso é pior do que tínhamos antes.
Estamos loucos? (Dica: Não!) nserir os registradores tem dupla finalidade:
1. Podemos aumentar a velocidade do clock porque o atraso máximo agora é mais curto.
2. Podemos usar todas as partes do caminho de dados durante cada ciclo.
Desmembrando o caminho de dados em três partes, o atraso máximo é reduzido e o resultado é que a
frequência do clock pode ser mais alta. amos supor que, desmembrando o ciclo do caminho de dados em três
intervalos de tempo, o comprimento de cada um seja cerca de 1/3 do original, de modo que podemos triplicar a
velocidade do clock. (sso não é de todo realidade, já que também adicionamos dois registradores ao caminho de
dados, mas serve como uma primeira aproximação.)
Como estamos considerando que todas as leituras e escritas da memória podem ser satisfeitas na cache de nível
1, e que esta é feita do mesmo material que os registradores, continuaremos a supor que uma operação de memória
leva um ciclo. Porém, na prática, isso pode não ser fácil de conseguir.
O segundo ponto trata do rendimento, e não da velocidade, de uma instrução individual. Na Mic-2, durante
a primeira e a terceira partes de cada ciclo de clock, a ULA fica ociosa. Desmembrando o caminho de dados em
três pedaços, poderemos usar a ULA em cada ciclo, obtendo três vezes mais trabalho da máquina.
Agora, vamos ver como o caminho de dados da Mic-3 funciona. Antes de começar, precisamos de uma
notação para lidar com os registradores. A óbvia é denominar os registradores A, B e C e tratá-los como os outros
registradores, tendo em mente as restrições do caminho de dados. A Figura 4.32 mostra um exemplo de sequência
de código, a execução de SWAP para a Mic-2.
Figura 4.32 Co
digo Mic-2 para SWAP.
Rótulo Operações Comentários
swap1 MAR = SP – 1; rd Leia a segunda palavra da pilha; ajuste MAR a SP
swap2 MAR = SP Prepare para escrever nova segunda palavra
swap3 H = MDR; wr Salve novo TOS; escreva segunda palavra para pilha
swap4 MDR = TOS Copie TOS antigo para MDR
swap5 MAR = SP – 1; wr Escreva TOS antigo para o segundo lugar na pilha
swap6 TOS = H; goto (MBR1) Atualize TOS
Agora, vamos reimplementar essa sequência na Mic-3. Lembre-se de que o caminho de dados agora requer
três ciclos para operar: um para carregar A e B, um para efetuar a operação e carregar C e um para escrever o
resultado de volta para os registradores. Denominaremos cada um desses pedaços microetapa.
A implementação de SWAP para Mic-3 é mostrada na Figura 4.33. No ciclo 1, começamos em swap1 copian-
do SP para B. Não importa o que acontece em A porque, para subtrair 1 de B, ENA é negado (veja a Figura 4.2).
Para simplificar, não mostramos atribuições que não são usadas. No ciclo 2, efetuamos a subtração. No ciclo 3, o
resultado é armazenado em MAR e a operação de leitura é iniciada no final do ciclo 3, após MAR ter sido armaze-
nado. Já que leituras de memória agora levam um ciclo, essa não estará concluída até o final do ciclo 4, o que é
indicado mostrando a atribuição MDR no ciclo 4. O valor em MDR não pode ser lido antes do ciclo 5.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
236
Figura 4.33 A implementac
a
o de SWAP na Mic-3.
Swap1 Swap2 Swap3 Swap4 Swap5 Swap6
Ciclo MAR = SP – 1; rd MAR = SP H = MDR; wr MDR = TOS MAR = SP – 1; wr TOS = H; goto (MBR1)
1 B = SP
2 C = B – 1 B = SP
3 MAR = C; rd C = B
4 MDR = Mem MAR = C
5 B = MDR
6 C = B B = TOS
7 H = C; wr C = B B = SP
8 Mem = MDR MDR = C C = B – 1 B = H
9 MAR = C; wr C = B
10 Mem = MDR TOS = C
11 goto (MBR1)
amos voltar ao ciclo 2. Agora, podemos começar a desmembrar swap2 em microetapas e iniciá-las também.
No ciclo 2, podemos copiar SP para B, então passá-lo pela ULA no ciclo 3 e por fim armazená-lo em MAR no ciclo 4.
Até aqui, tudo bem. Deve estar claro que, se pudermos continuar nesse ritmo, iniciando uma nova microinstrução
a cada ciclo, triplicaremos a velocidade da máquina. Esse ganho vem do fato de que podemos emitir uma nova
microinstrução a cada ciclo de clock, que a Mic-3 tem três vezes mais ciclos de clock por segundo do que a Mic-2.
Na verdade, construímos uma CPU com pipeline.
nfelizmente, encontramos um empecilho no ciclo 3. Gostaríamos de começar a trabalhar em swap3, mas a
primeira coisa que ela faz é passar MDR pela ULA, e MDR não estará disponível na memória até o início do ciclo 5.
A situação em que uma microetapa não pode iniciar porque está esperando um resultado que uma microetapa
anterior ainda não produziu é denominada dependência verdadeira ou dependência RW. Dependências cos-
tumam ser denominadas ocorrências (hazards). RAW quer dizer Read After Write (leitura após escrita) e indica
que uma microetapa quer ler um registrador que ainda não foi escrito. A única coisa sensata a fazer nesse caso
é atrasar o início de swap3 até MDR estar disponível no ciclo 5. Esperar por um valor necessário é denominado
protelação (stalling). Depois disso, podemos continuar iniciando microinstruções a cada ciclo, pois não há mais
dependências, embora swap6 escape por um triz, uma vez que lê H no ciclo após swap3 escrevê-lo. Se swap5
tivesse tentado ler H, ela (swap6) teria sido protelada por um ciclo.
Embora o programa Mic-3 leve mais ciclos do que o programa Mic-2, ainda assim é mais rápido. Se denomi-
narmos o tempo de ciclo da Mic-3 ∆T ns, então, ela vai requerer 11 ∆T ns para executar SWAP. Por comparação,
a Mic-2 leva 6 ciclos a 3 ∆T cada, para um total de 18 ∆T. O pipeline deixou a máquina mais rápida, ainda que
tivéssemos de protelar uma vez para evitar uma dependência.
Pipeline é uma técnica fundamental em todas as CPUs modernas, portanto, é importante entendê-lo bem.
Na Figura 4.34, vemos o caminho de dados da Figura 4.31 ilustrado graficamente como um pipeline. A primeira
coluna representa o que está acontecendo no ciclo 1, a segunda representa o ciclo 2 e assim por diante (consi-
derando que não haja protelação). A região sombreada no ciclo 1 para a instrução 1 indica que a FU está ocupada
buscando a instrução 1. Uma batida de clock mais tarde, durante o ciclo 2, os registradores requisitados pela instru-
ção 1 estão sendo carregados nos registradores A e B enquanto, ao mesmo tempo, a FU está ocupada buscando
a instrução 2, de novo mostrada pelos dois retângulos sombreados no ciclo 2.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 237
Figura 4.34 Ilustrac
a
o gra
fica do funcionamento do pipeline.
1
Instrução
Ciclo 1 Ciclo 2
Tempo
Ciclo 3 Ciclo 4
IFU
ULA
Reg
A
C B
IFU
ULA
Reg
A
C B
IFU
ULA
Reg
A
C B
IFU
ULA
Reg
A
C B
IFU
ULA
Reg
A
C B
IFU
ULA
Reg
A
C B
IFU
ULA
Reg
A
C B
IFU
ULA
Reg
A
C B
IFU
ULA
Reg
A
C B
IFU
ULA
Reg
A
C B
2
IFU
ULA
Reg
A
C B
IFU
ULA
Reg
A
C B
IFU
ULA
Reg
A
C B
3
IFU
ULA
Reg
A
C B
IFU
ULA
Reg
A
C B
4
IFU
ULA
Reg
A
C B
Deslocador Deslocador
Deslocador Deslocador Deslocador
Deslocador Deslocador Deslocador
Deslocador
Deslocador
Deslocador Deslocador Deslocador Deslocador
Deslocador
Deslocador
Durante o ciclo 3, a instrução 1 está usando a ULA e o deslocador para executar sua operação e os regis-
tradores A e B estão sendo carregados para a instrução 2, e a instrução 3 está sendo buscada. Por fim, durante o
ciclo 4, quatro instruções estão sendo processadas ao mesmo tempo. Os resultados da instrução 1 estão sendo
armazenados, o trabalho da ULA para a instrução 2 está sendo realizado, os registradores A e B para a instrução
3 estão sendo carregados e a instrução 4 está sendo buscada.
Se tivéssemos mostrado o ciclo 5 e os subsequentes, o padrão teria sido o mesmo do ciclo 4: todas as qua-
tro partes do caminho de dados que podem executar independentemente estariam fazendo isso. Esse projeto
representa um pipeline de quatro estágios: para busca de instrução, acesso a operando, operações de ULA e escrita
de volta para os registradores. sso é semelhante ao pipeline da Figura 2.4(a), exceto pela ausência do estágio de deco-
dificação. A questão importante a entender aqui é que, embora uma única instrução leve quatro ciclos de clock para
executar, a cada ciclo uma nova instrução é iniciada e uma velha instrução é concluída.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
238
Outro modo de ver a Figura 4.34 é seguir cada instrução na página em sentido horizontal. Para a instrução
1, no ciclo 1 a FU está trabalhando nela. No ciclo 2, seus registradores estão sendo colocados nos barramentos
A e B. No ciclo 3, a ULA e o deslocador estão trabalhando para ela. Por fim, no ciclo 4, seus resultados estão
sendo armazenados de volta nos registradores. O que se deve notar nesse caso é que há quatro seções do hardware
disponíveis, e durante cada ciclo, uma determinada instrução usa só um deles, liberando as outras seções para
instruções diferentes.
Uma analogia útil para nosso projeto com pipeline é uma linha de montagem de uma fábrica de automó-
veis. Para abstrair os aspectos essenciais desse modelo, imagine que um gongo é tocado a cada minuto, quando
então todos os automóveis passam para uma estação seguinte na linha. Em cada estação, os trabalhadores que
ali estão executam alguma operação no carro que está à sua frente no momento em questão, como adicionar o
volante ou instalar os freios. A cada batida do gongo (1 ciclo), um novo carro é introduzido no início da linha
de montagem e um carro é concluído. Assim, ainda que leve centenas de ciclos para terminar um carro, a cada
ciclo um carro inteiro é concluído. A fábrica pode produzir um carro por minuto, independente do tempo que
realmente leva para montar um carro. Essa é a força do pipelining, e ela se aplica igualmente bem a CPUs e
fábricas de automóveis.
4.4.5 Pipeline de sete esta
gios: a Mic-4
Uma questão a que não demos o devido destaque é o fato de que toda microinstrução seleciona sua própria
sucessora. A maioria delas apenas seleciona a instrução seguinte na sequência corrente, mas a última, tal como
swap6, muitas vezes faz um desvio multivias que atrapalha o pipeline, já que é impossível continuar fazendo busca
antecipada após o desvio. Precisamos de um modo melhor de lidar com essa questão.
Nossa última microarquitetura é a Mic-4. Suas partes principais estão ilustradas na Figura 4.35, embora mui-
tos detalhes tenham sido suprimidos em benefício da clareza. Como a Mic-3, ela tem uma FU que busca palavras
da memória antecipadamente e mantém os vários MBRs.
A FU também alimenta o fluxo de bytes que está entrando para um novo componente, a unidade de decodi-
ficação. Essa unidade tem uma ROM interna indexada por opcode JM. Cada entrada (linha) contém duas partes:
o comprimento daquela instrução JM e um índice para outra ROM, a de micro-operação. O comprimento da
instrução JM é usado para permitir que a unidade de decodificação faça a análise sintática (parse) da sequência
de bytes que está entrando dividindo-a em instruções, de modo que ela sempre sabe quais bytes são opcodes e
quais são operandos. Se o comprimento da instrução em questão for 1 byte (por exemplo, POP), então, a unidade
de decodificação sabe que o próximo byte é um opcode. Contudo, se o comprimento da instrução em questão
for 2 bytes, a unidade de decodificação sabe que o próximo byte é um operando, seguido imediatamente por um
outro opcode. Quando o prefixo WIDE é visto, o próximo byte é transformado em um opcode largo especial, por
exemplo, WIDE + ILOAD se torna WIDE_ILOAD.
A unidade de decodificação despacha o índice na micro-operação ROM que encontrou em sua tabela para
o próximo componente, a unidade de enfileiramento. Essa unidade contém alguma lógica e mais duas tabelas
internas, uma em ROM e uma em RAM. A ROM contém o microprograma, sendo que cada instrução JM tem
certo número de entradas consecutivas denominadas micro-operações. As entradas devem estar em ordem, por-
tanto, não são permitidos truques como o desvio de wide_iload2 para iload2 na Mic-2. Cada sequência JM deve
ser escrita por extenso, duplicando sequências em alguns casos.
As micro-operações são semelhantes às microinstruções da Figura 4.5, exceto que os campos NEXT_
ADDRESS e JAM estão ausentes e um novo campo codificado é necessário para especificar a entrada do barra-
mento A. Dois novos bits também são fornecidos: Final e Goto. O bit Final é marcado na última micro-operação
de cada sequência de micro-operação JM para sinalizá-la. O bit Goto é ajustado para marcar micro-operações
que são microdesvios condicionais. Elas têm um formato diferente do das micro-operações normais, consistindo
nos bits JAM e um índice para a ROM de micro-operação. Microinstruções que fizeram alguma coisa antes com
o caminho de dados e também realizaram um microdesvio condicional (por exemplo, iflt4) agora têm de ser sub-
divididas em duas micro-operações.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 239
Figura 4.35 Principais componentes da Mic-4.
ULA
B
C
Deslocador
A
Unidade de enleiramento
IADD
ISUB
ILOAD
IFLT
ROM da micro-operação
Unidade
de busca
de instrução
Da
memória
Comprimento
da IJVM
Índice de
ROM da
micro-operação
Unidade de
decodicação
Fila de
micro-operações
pendentes
Final
Goto
1 2
3
4
5
6
7
De/para
memória
ULA C M A B
ULA C M A B
ULA C M A B
ULA C M A B
Comanda estágio 4
Comanda estágio 5
Comanda estágio 6
Comanda estágio 7
MIR1
MIR2
MIR4
MIR3
Registradores
A unidade de enfileiramento funciona da seguinte maneira. Ela recebe um índice de ROM de micro-operação
da unidade de decodificação. Depois, examina a micro-operação e a copia em uma fila interna. Em seguida, tam-
bém copia a próxima micro-operação para a fila, bem como a seguinte depois dessa e assim até encontrar uma
cujo bit Final é 1. Ela copia essa também, e então para. Considerando que não tenha encontrado uma micro-
-operação com o bit Goto ligado e que ainda tenha muito espaço de sobra na fila, a unidade de enfileiramento
então devolve um sinal de reconhecimento à de decodificação. Quando esta vê o reconhecimento, envia o índice
da próxima instrução JM para a unidade de enfileiramento.
Desse modo, por fim, a sequência de instruções JM na memória é convertida em uma sequência de
micro-operações em uma fila. Essas micro-operações alimentam os MIRs, que enviam os sinais para controlar o
caminho de dados. Contudo, há outro fator que temos de considerar agora: os campos em cada micro-operação
não estão ativos ao mesmo tempo. Os campos A e B estão ativos durante o primeiro ciclo, o campo ULA está
ativo durante o segundo ciclo, o campo C está ativo durante o terceiro ciclo, e quaisquer operações de memória
ocorrem no quarto ciclo.
Para fazer com que isso funcione adequadamente, introduzimos quatro MIRs independentes na Figura 4.35.
No início de cada ciclo de clock (o tempo ∆w na Figura 4.3), MIR3 é copiado para MIR4, MIR2 é copiado para
MIR3, MIR1 é copiado para MIR2, e MIR1 é carregado com uma nova micro-operação da fila. Então, cada MIR
emite seus sinais de controle, mas só alguns deles são usados. Os campos A e B de MIR1 são usados para selecio-
nar os registradores que serão enviados aos barramentos A e B, mas o campo ULA em MIR1 não é usado e não é
conectado a nada mais no caminho de dados.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
240
Um ciclo de clock mais tarde, essa micro-operação passou para MIR2 e os registradores que ela selecionou
agora estão seguros nos registradores A e B esperando pelas aventuras que hão de vir. Seu campo de ULA agora é
usado para comandar a ULA. No próximo ciclo, seu campo C escreverá os resultados de volta nos registradores.
Depois disso, ela passará para MIR4 e iniciará quaisquer operações de memória necessárias usando o MAR agora
carregado (e MDR, para uma escrita).
Um último aspecto da Mic-4 precisa de um pouco de discussão agora: microdesvios. Algumas instruções
JM, como IFLT, precisam desviar condicionalmente com base, por exemplo, no bit N. Quando ocorre um
microdesvio, o pipeline não pode continuar. Para lidar com isso, adicionamos o bit Goto à micro-operação.
Quando a unidade de enfileiramento atinge uma micro-operação que tenha esse bit ajustado enquanto a está
copiando para a fila, ela percebe que há problemas à frente e se abstém de enviar um reconhecimento à unidade
de decodificação. O resultado é que a máquina ficará parada nesse ponto até que o microdesvio tenha sido
resolvido.
É concebível que algumas instruções JM que estão além desse desvio já tenham sido alimentadas na uni-
dade de decodificação, mas não na de enfileiramento, já que ela não devolve um sinal de reconhecimento (isto
é, continuação) quando atinge uma micro-operação na qual o bit Goto está ligado. São necessários hardware e
mecanismos especiais para acabar com a confusão e voltar à trilha certa, mas eles estão além do escopo deste
livro. Quando Edsger Dijkstra escreveu seu famoso artigo “GOTO Statement Considered Harmful” [declaração
GOTO considerada perigosa (Dijkstra, 1968a)], ele não tinha ideia do quanto estava certo.
Percorremos um longo caminho desde a Mic-1. Ela era uma peça de hardware muito simples, com quase
todo o controle em software. A Mic-4 tem um projeto de alto pipelining, com sete estágios e hardware muito
mais complexo. O pipeline é mostrado em esquema na Figura 4.36. Os números dentro dos círculos referem-
-se diretamente aos componentes na Figura 4.35. A Mic-4 faz busca antecipada automática de uma sequência
de bytes da memória, decodifica-a para instruções JM, converte-a para uma sequência de micro-operações
usando uma ROM e a enfileira para usar quando necessário. Os primeiros três estágios do pipeline podem ser
vinculados ao clock do caminho de dados se desejado, mas nem sempre haverá trabalho a fazer. Por exemplo,
a FU certamente não pode alimentar um novo opcode JM à unidade de decodificação em cada ciclo de clock
porque instruções JM levam vários ciclos para executar e a fila logo transbordaria.
Figura 4.36 Pipeline da Mic-4.
1
IFU
2
Decodicador
3
Fila
4
Operandos
5
Execução
6
Escrita
7
Memória
Em cada ciclo de clock, os MIRs são deslocados para frente e a micro-operação que está no final da fila é
copiada para o MIR1 para iniciar sua execução. Os sinais de controle dos quatro MIRs então se espalham pelo
caminho de dados, fazendo com que ocorram ações. Cada MIR controla uma parte diferente do caminho de dados
e, portanto, microetapas diferentes.
Neste projeto, temos uma CPU de alto pipelining que permite que as etapas individuais sejam muito curtas
e, por isso, que a frequência de clock seja alta. Muitas CPUs são projetadas essencialmente dessa maneira, em
especial, as que têm de executar um conjunto de instruções mais antigo (CSC). Por exemplo, o conceito da
implementação do Core i7 é semelhante ao da Mic-4 em alguns aspectos, como veremos mais adiante neste
capítulo.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 241
4.5 Melhoria de desempenho
Todos os fabricantes de computadores querem que seus sistemas funcionem com a maior rapidez possível.
Nesta seção, veremos algumas técnicas avançadas que estão sendo investigadas para melhorar o desempenho do
sistema (em especial, CPU e memória). Pela natureza de alta competitividade da indústria de computadores, a
defasagem entre novas ideias que podem tornar um computador mais rápido e sua incorporação a produtos é
surpreendentemente curta. Por conseguinte, a maioria das ideias que discutiremos já está em uso em uma grande
maioria de produtos.
As ideias que discutiremos podem ser classificadas, de modo geral, em duas grandes categorias. Melhorias de
implementação e melhorias de arquitetura. Melhorias de implementação são modos de construir uma nova CPU
ou memória para fazer o sistema funcionar mais rápido sem mudar a arquitetura. Modificar a implementação sem
alterar a arquitetura significa que programas antigos serão executados na nova máquina, um importante argu-
mento de venda. Um modo de melhorar a implementação é usar um clock mais rápido, mas esse não é o único.
Os ganhos de desempenho obtidos na família 80386 a 80486, Pentium e projetos mais recentes, como o Core i7,
se devem a implementações melhores, porque, em essência, a arquitetura permaneceu a mesma em todos eles.
Alguns tipos de melhorias só podem ser feitos com a alteração da arquitetura. Às vezes, essas alterações são
incrementais, como adicionar novas instruções ou registradores, de modo que programas antigos continuarão a
ser executados nos novos modelos. Nesse caso, para conseguir um desempenho completo, o software tem de ser
alterado, ou ao menos recompilado com um novo compilador que aproveita as novas características.
Contudo, passadas algumas décadas, os projetistas percebem que a antiga arquitetura durou mais do que sua
utilidade e que o único modo de progredir é começar tudo de novo. A revolução RSC na década de 1980 foi uma
dessas inovações; outra está no ar agora. amos examinar um exemplo (ntel A-64) no Capítulo 5.
No restante desta seção, estudaremos quatro técnicas diferentes para melhorar o desempenho da CPU.
Começaremos com três melhorias de implementação já estabelecidas e depois passaremos para uma que precisa
de um pouco de suporte da arquitetura para funcionar melhor. Essas técnicas são memória cache, previsão de
desvio, execução fora da ordem com renomeação de registrador e execução especulativa.
4.5.1 Memo
ria cache
Um dos aspectos mais desafiadores do projeto de um computador em toda a história tem sido oferecer um
sistema de memória capaz de fornecer operandos ao processador à velocidade em que ele pode processá-los. A
recente alta taxa de crescimento na velocidade do processador não foi acompanhada de um aumento corres-
pondente na velocidade das memórias. Se comparadas com as CPUs, as memórias estão ficando mais lentas há
décadas. Dada a enorme importância da memória primária, essa situação limitou muito o desenvolvimento de
sistemas de alto desempenho e estimulou a pesquisa a encontrar maneiras de contornar o problema da velocida-
de das memórias que são muito menores do que as velocidades das CPUs e, em termos relativos, estão ficando
piores a cada ano.
Processadores modernos exigem muito de um sistema de memória, tanto em termos de latência (o atraso na
entrega de um operando) quanto de largura de banda (a quantidade de dados fornecida por unidade de tempo).
nfelizmente, há um grande antagonismo entre esses dois aspectos. Muitas técnicas para aumentar a largura de
banda também aumentam a latência. Por exemplo, as técnicas de pipelining usadas na Mic-3 podem ser aplica-
das a um sistema de memória que tenha várias memórias sobrepostas e elas serão manipuladas com eficiência.
Lamentavelmente, assim como na Mic-3, isso resulta em maior latência para operações individuais de memória.
À medida que aumentam as velocidades de clock do processador, fica cada vez mais difícil prover um sistema de
memória capaz de fornecer operandos em um ou dois ciclos de clock.
Um modo de atacar esse problema é providenciar caches. Como vimos na Seção 2.2.5, uma cache guarda as
palavras de memória usadas mais recentemente em uma pequena memória rápida, o que acelera o acesso a elas.
Se uma porcentagem grande o suficiente das palavras de memória estiver na cache, a latência efetiva da memória
pode ter enorme redução.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
242
Uma das técnicas mais efetivas para melhorar a largura de banda e também a latência é a utilização de várias
caches. Uma técnica básica que funciona com grande eficácia é introduzir uma cache separada para instruções e
dados. É possível obter muitos benefícios com caches separadas para instruções e dados, algo que muitas vezes
denominamos cache dividida. Primeiro, as operações de memória podem ser iniciadas de modo independente
em cada cache, o que efetivamente dobra a largura de banda do sistema de memória. É essa a razão por que faz
sentido fornecer duas portas de memória separadas, como fizemos na Mic-1: cada porta tem sua própria cache.
Note que cada uma tem acesso independente à memória principal.
Hoje, muitos sistemas de memória são mais complicados do que isso, e uma cache adicional, denominada
cache de nível 2, pode residir entre as caches de instrução e dados e a memória principal. Na verdade, pode
haver três ou mais níveis de cache à medida que se exigem sistemas de memória mais sofisticados. Na Figura
4.37, vemos um sistema com três níveis. O próprio chip da CPU contém uma pequena cache de instrução e uma
pequena cache de dados, em geral de 16 KB a 64 KB. Então, há a cache de nível 2, que não está no chip da CPU,
mas pode ser incluída no pacote da CPU próxima ao chip da CPU e conectada a ela por um caminho de alta velo-
cidade. Em geral, ela é unificada, contendo um misto de dados e instruções. Um tamanho típico para a cache L2
é de 512 KB a 1 MB. A cache de terceiro nível está na placa do processador e consiste em alguns poucos megabytes
de SRAM, que é muito mais rápida do que a memória principal DRAM. As caches são em geral inclusivas, sendo
que o conteúdo total da de nível 1 está na de nível 2 e todo o conteúdo da cache de nível 2 está na de nível 3.
Figura 4.37 Sistema com tre
s n
veis de cache.
Placa do
processador
Pacote
da CPU Chip da CPU
Controlador
de teclado
Controlador
gráco
Controlador
de disco
Memória
principal
(DRAM)
L1-I L1-D
Cache
L2
unicada
Cache
L3 unicada
Caches L1 divididas de instrução e dados Cache de nível de placa (SRAM)
Caches dependem de dois tipos de endereço de localidade para cumprir seu objetivo. Localidade espacial
é a observação de que localizações de memória com endereços numericamente similares a uma localização de
memória cujo acesso foi recente provavelmente serão acessadas no futuro próximo. Caches exploram essa pro-
priedade trazendo mais dados do que os requisitados, na expectativa de poder antecipar requisições futuras.
Localidade temporal ocorre quando localizações de memória recentemente acessadas são acessadas outra vez.
sso pode ocorrer, por exemplo, com localizações de memórias próximas ao topo da pilha, ou com instruções
dentro de um laço. A localidade temporal é explorada em projetos de cache, principalmente pela escolha do que
descartar quando ocorre uma ausência na cache. Muitos algoritmos de substituição de cache exploram a locali-
dade temporal descartando as entradas que não tiveram acesso recente.
Todas as caches usam o modelo a seguir. A memória principal é dividida em blocos de tamanho fixo, designa-
dos linhas de cache. Uma linha típica consiste em 4 a 64 bytes consecutivos. As linhas são numeradas em sequên-
cia, começando em 0; portanto, se tivermos uma linha de 32 bytes de tamanho, a linha 0 vai do byte 0 ao byte
31, a linha 1 do byte 32 ao 63, e assim por diante. Em qualquer instante, algumas linhas estão na cache. Quando
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 243
a memória é referenciada, o circuito de controle da cache verifica se a palavra referenciada está nela naquele
instante. Caso positivo, o valor que ali está pode ser usado, evitando uma viagem até a memória principal. Se a
palavra não estiver lá, alguma linha de entrada é removida da cache e a linha necessária é buscada na memória
ou na cache de nível mais baixo para substituí-la. Existem muitas variações desse esquema, mas em todas elas
a ideia é manter as linhas mais utilizadas na cache o quanto possível, para maximizar o número de referências à
memória satisfeitas pela cache.
Caches de mapeamento direto
A cache mais simples é conhecida como cache de mapeamento direto. Um exemplo de cache de mapeamento
direto de um só nível é mostrado na Figura 4.38(a). Esse exemplo contém 2.048 entradas. Cada entrada (linha)
pode conter exatamente uma linha de cache da memória principal. Se a linha tiver 32 bytes de tamanho, para esse
exemplo, a cache pode conter 2.048 entradas de 32 bytes, ou 64 KB no total. Cada entrada de cache consiste em
três partes:
1. O bit Valid indica se há ou não quaisquer dados válidos nessa entrada. Quando o sistema é iniciado,
todas as entradas são marcadas como inválidas.
2. O campo Tag consiste em um único valor de 16 bits que identifica a linha de memória correspondente
da qual vieram os dados.
3. O campo Data contém uma cópia dos dados na memória. Ele contém uma linha de cache de 32 bytes.
Figura 4.38 (a) Cache de mapeamento direto. (b) Enderec
o virtual de 32 bits.
Valid
Entrada
2047
Tag Data
Endereços que usam essa entrada
(a)
(b)
Bits 16 11 3 2
TAG LINE WORD BYTE
65504-65535, 131040-131071, …
96-127, 65632-65663, 131168-131199
64-95, 65600-65631, 131136-131167, …
32-63, 65568-65599, 131104-131135, …
0-31, 65536-65567, 131072-131103, …
7
6
5
4
3
2
1
0
Em uma cache de mapeamento direto, uma determinada palavra de memória pode ser armazenada em exa-
tamente um lugar dentro da cache. Dado um endereço de memória, há somente um lugar onde procurar por ele.
Se não estiver nesse lugar, então ele não está na cache. Para armazenar e recuperar dados da cache, o endereço é
desmembrado em quatro componentes, como ilustra a Figura 4.38(b):
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
244
1. O campo TAG corresponde aos bits Tag armazenados em uma entrada de cache.
2. O campo LINE indica qual entrada de cache contém os dados correspondentes, se eles estiverem
presentes.
3. O campo WORD informa qual palavra dentro de uma linha é referenciada.
4. O campo BYTE em geral não é usado, mas se for requisitado apenas um byte, ele informa qual byte
dentro da palavra é necessário. Para uma cache que fornece apenas palavras de 32 bits, esse campo será
sempre 0.
Quando a CPU produz um endereço de memória, o hardware extrai os 11 bits LINE do endereço e os utiliza
para indexá-lo na cache para achar uma das 2.048 entradas. Se essa entrada for válida, o campo TAG do endereço
de memória e o campo Tag na entrada da cache são comparados. Sendo compatíveis, a entrada de cache contém
a palavra que está sendo requisitada, uma situação denominada presença na cache. Se ocorrer uma presença na
cache, uma palavra que está sendo lida pode ser pega, eliminando a necessidade de ir até a memória. Somente a
palavra necessária é extraída da entrada da cache. O resto da entrada não é usado. Se a entrada for inválida ou os
tags não forem compatíveis, a entrada necessária não está presente, uma situação denominada ausência da cache.
Nesse caso, a linha de cache de 32 bytes é buscada na memória e armazenada na linha da cache, substituindo o que
lá estava. Contudo, se a linha de cache existente sofreu modificação desde que foi carregada, ela deve ser escrita
de volta na memória principal antes de ser sobrescrita.
A despeito da complexidade da decisão, o acesso à palavra necessária pode ser extraordinariamente rápido.
Assim que o endereço for conhecido, a exata localização da palavra é conhecida, se ela estiver presente na cache.
sso significa que é possível ler a palavra da cache e entregá-la ao processador ao mesmo tempo em que está sendo
determinado se essa é a palavra correta (por comparação de tags). Portanto, na verdade o processador recebe uma
palavra da cache simultaneamente ou talvez até antes de saber se essa é a palavra requisitada.
Esse esquema de mapeamento põe linhas de memória consecutivas em linhas de cache consecutivas. De
fato, até 64 KB de dados contíguos podem ser armazenados na cache. Contudo, quando a diferença entre o
endereço de duas linhas for exatamente 64 KB (65.536 bytes) ou qualquer múltiplo inteiro desse número, elas
não podem ser armazenadas na cache ao mesmo tempo (porque têm o mesmo valor de LINE). Por exemplo, se
um programa acessar dados na localização X e em seguida executar uma instrução que precisa dos dados na
localização X + 65.536 (ou em qualquer outra localização dentro da mesma linha), a segunda instrução forçará
a linha de cache a ser recarregada, sobrescrevendo o que lá estava. Se isso acontecer com certa frequência, pode
resultar em mau desempenho. Na verdade, o pior comportamento possível de uma cache é ainda pior do que
se não houvesse nenhuma, já que cada operação de memória envolve ler uma linha de cache inteira em vez de
apenas uma palavra.
Caches de mapeamento direto são as mais comuns e funcionam com bastante eficácia, porque com elas é
possível fazer colisões como a descrita ocorrerem apenas raramente, ou nunca ocorrerem. Por exemplo, um com-
pilador muito esperto pode levar em conta as colisões de cache quando colocar instruções e dados na memória.
Note que o caso particular descrito não ocorreria em um sistema com caches de instruções e dados separados,
porque as requisições conflitantes seriam atendidas por caches diferentes. Assim, vemos um segundo benefício de
ter duas caches em vez de uma: mais flexibilidade para lidar com padrões de memória conflitantes.
Caches associativas de conjunto
Como já dissemos, muitas linhas diferentes competem na memória pelas mesmas posições na cache (cache
slots). Se um programa que utiliza a cache da Figura 4.38(a) usar muito as palavras nos endereços 0 e 65.536,
haverá conflitos constantes porque cada referência potencialmente expulsaria a outra. Uma solução para esse
problema é permitir duas ou mais linhas em cada entrada de cache. Uma cache com n entradas possíveis para
cada endereço é denominada uma cache associativa de conjunto de n vias. Uma cache associativa de conjunto de
quatro vias é ilustrada na Figura 4.39.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 245
Figura 4.39 Cache associativa de conjunto de quatro vias.
Valid
Tag Data
2047
7
6
5
4
3
2
1
0
Entrada A
Valid
Tag Data
Entrada B
Valid
Tag Data
Entrada C
Valid
Tag Data
Entrada D
Uma cache associativa de conjunto é inerentemente mais complicada do que uma de mapeamento direto
porque, embora a linha de cache correta a examinar possa ser calculada do endereço de memória que está sendo
referenciado, um conjunto de n linhas de cache deve ser verificado para ver se a palavra necessária está presente.
Ainda assim, a experiência mostra que caches de duas vias e de quatro vias funcionam bem o suficiente para que
esses circuitos extras valham a pena.
A utilização de caches associativas de conjunto oferece uma opção ao projetista. Quando uma nova linha
deve ser trazida para dentro da cache, qual dos itens nela presentes deve ser descartado? É claro que a decisão
ideal requer uma olhadela no futuro, mas um algoritmo muito bom para a maioria das finalidades é o LRU (Least
Recently Used  usado menos recentemente). Esse algoritmo mantém uma ordenação de cada conjunto de loca-
lizações que poderia ser acessado de uma determinada localização de memória. Sempre que qualquer das linhas
presentes é acessada, ele atualiza a lista, marcando aquela entrada como a mais recentemente acessada. Quando
chega a hora de substituir uma entrada, a que está no final da lista (aquela acessada menos recentemente) é a
descartada.
Levada ao extremo, uma cache de 2.048 vias que contém 2.048 linhas de entrada também é possível. Nesse
caso, todos os endereços de memória mapeiam para um único conjunto, portanto, a consulta requer comparar o
endereço contra todos os 2.048 tags na cache. Note que agora cada entrada deve ter lógica de compatibilização
de tag. isto que o campo LINE tem comprimento 0, o campo TAG é o endereço inteiro, exceto para os campos
WORD e BYTE. Além do mais, quando uma linha de cache é substituída, todas as 2.048 localizações são possíveis
candidatas a substituição. Manter uma lista ordenada de 2.048 linhas requer muita contabilidade, o que torna
a substituição da LRU inviável. (Lembre-se de que essa lista tem de ser atualizada a cada operação de memória, e
não apenas quando ocorre uma ausência na cache.) O surpreendente é que caches de alto grau de associatividade não
melhoram muito o desempenho em relação às de baixo grau sob a maioria das circunstâncias e, em alguns casos,
até funcionam pior. Por essas razões, a associatividade de conjunto além de quatro vias é relativamente incomum.
Por fim, escritas propõem um problema especial para as caches. Quando um processador escreve uma palavra
e a palavra está na cache, é óbvio que ele tem de atualizar a palavra ou descartar a entrada da cache. Praticamente
todos os modelos atualizam a cache. Mas, e quanto a atualizar a cópia na memória principal? Essa operação pode
ser adiada até mais tarde, quando a linha de cache estiver pronta para ser substituída pelo algoritmo LRU. Essa
escolha é difícil, e nenhuma das opções é claramente preferível. A atualização imediata da entrada na memória
principal é denominada escrita direta (write through). Essa abordagem geralmente é mais simples de realizar e
mais confiável, uma vez que a memória está sempre atualizada – é útil, por exemplo, se ocorrer um erro e for
necessário recuperar o estado da memória. nfelizmente, também requer mais tráfego de escrita para a memória,
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
246
portanto, execuções mais sofisticadas tendem a empregar a alternativa, conhecida como escrita retardada (write
deferred) ou escrita retroativa (write back).
Há um problema relacionado com as escritas que é preciso atacar: e se ocorrer uma escrita para uma loca-
lização que não está na cache naquele momento? Os dados devem ser trazidos para dentro da cache ou apenas
escritos na memória? Mais uma vez, nenhuma das respostas é sempre a melhor. A maioria dos projetos que retar-
dam escritas para a memória tende a trazer os dados para dentro quando há uma ausência de escrita, uma técnica
conhecida como alocação de escrita. Por outro lado, a maioria dos projetos que empregam escrita direta tende a
não alocar uma linha em uma escrita porque essa opção complica um projeto que, quanto ao mais, seria simples.
Alocação de escrita é melhor apenas se houver escritas repetidas para a mesma palavra ou palavras diferentes
dentro de uma linha de cache.
O desempenho da cache é crítico para o desempenho do sistema porque a defasagem entre a velocidade da
CPU e a da memória é muito grande. Por conseguinte, a pesquisa de melhores estratégias de caching ainda é um
tópico muito discutido (Sanchez e Kozyrakis, 2011; e Gaur et al., 2011).
4.5.2 Previsa
o de desvio
Computadores modernos têm alto grau de pipelining. O pipeline da Figura 4.36 tem sete estágios; computa-
dores de última geração às vezes têm dez estágios ou até mais. O pipeline funciona melhor com código linear, de
modo que a unidade de busca pode apenas ler palavras consecutivas da memória e as enviar para a unidade de
decodificação antes de haver necessidade delas.
O único problema com esse maravilhoso modelo é que ele não é nem um pouco realista. Programas não são
sequências de código linear – estão repletos de instruções de desvio. Considere as declarações simples da Figura
4.40(a). Uma variável, i, é comparada com 0 (provavelmente o teste mais comum na prática). Dependendo do
resultado, um de dois valores possíveis é atribuído a outra variável, k.
Figura 4.40 (a) Fragmento de programa. (b) Sua traduc
a
o para uma linguagem de montagem gene
rica.
if (i == 0) CMP i,0 ; compare i com 0
k = 1 BNE Else
; ; Desvie se for diferente
else Then: MOV k,1 ; Mova 1 para k
k = 2 BR Next
; ; Desvio incondicional
Else: MOV k,2 ; Mova 2 para k
Next:
(a) (b)
Uma tradução possível para a linguagem de montagem é mostrada na Figura 4.40(b). Estudaremos a lingua-
gem de montagem mais adiante neste livro e os detalhes não são importantes agora, mas, dependendo da máquina
e do compilador, é provável que haja um código mais ou menos como o da Figura 4.40(b). A primeira instrução
compara i com 0. A segunda desvia para o rótulo Else (o início de uma cláusula else) se i não for 0. A terceira
instrução atribui 1 a k. A quarta desvia para saltar a próxima declaração. O compilador convenientemente colocou
ali um rótulo, Next, portanto, há um lugar para o qual desvia. A quinta instrução atribui 2 a k.
Nesse caso, devemos observar que duas das cinco instruções são desvios. Além do mais, uma delas, BNE, é
um desvio condicional (tomado se, e somente se, alguma condição for cumprida, nesse caso, que os dois operan-
dos da CMP anterior não sejam iguais). A sequência de código linear mais longa no caso são duas instruções. Por
conseguinte, buscar instruções a alta velocidade para alimentar o pipeline é muito difícil.
À primeira vista, pode parecer que desvios incondicionais, como a instrução BR Next na Figura 4.40(b), não
são um problema. Afinal, não há nenhuma ambiguidade sobre aonde ir. Por que a unidade de busca não pode
apenas continuar a ler as instruções a partir do endereço visado (o lugar para onde o desvio levará)?
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 247
O problema está na natureza do pipelining. Na Figura 4.36, por exemplo, vemos que a decodificação da ins-
trução ocorre no segundo estágio. Assim, a unidade de busca tem de decidir de onde buscar em seguida antes de
saber que tipo de instrução acabou de obter. Somente um ciclo mais tarde ela pode saber que acabou de pegar um
desvio incondicional e, a essa altura, já começou a buscar a instrução que vem após esse desvio. Por conseguinte,
um número substancial de máquinas com pipeline (como a UltraSPARC) tem a seguinte propriedade: a instru-
ção seguinte a um desvio incondicional é executada, ainda que logicamente não devesse ser. A posição após um
desvio é denominada posição de retardo (delay slot). O Core i7 (e a máquina usada na Figura 4.40(b)) não tem
essa propriedade, mas a complexidade interna para contornar o problema costuma ser enorme. Um compilador
otimizador tentará encontrar alguma instrução útil para colocar na posição de retardo, mas com frequência não
há nada disponível, então, ele é forçado a inserir ali uma instrução NOP. Assim, o programa fica correto, mas
também maior e mais lento.
Por mais que desvios incondicionais sejam irritantes, os desvios condicionais são piores. Além de também
terem posições de retardo, agora a unidade de busca não sabe de onde ler até muito mais adiante no pipeline. As
primeiras máquinas com pipeline apenas protelavam até saberem se o desvio seria tomado ou não. Uma protelação
de três ou quatro ciclos em cada desvio condicional, em especial se 20% das instruções forem desvios condicio-
nais, arrasa o desempenho.
Por conseguinte, o que a maioria das máquinas faz quando chega a um desvio condicional é prever se ele vai
ser tomado ou não. Seria maravilhoso se pudéssemos apenas ligar uma bola de cristal em um encaixe PC livre
para ajudar na previsão, mas até agora essa abordagem não deu frutos.
Na falta de tal periférico, foram arquitetadas várias maneiras de fazer a previsão. Um modo muito simples
é o seguinte: considere que todos os desvios condicionais para trás serão tomados e todos os desvios para frente
não serão tomados. O raciocínio que fundamenta a primeira parte é que os desvios para trás costumam estar
localizados no final de um laço. A maioria dos laços é executada várias vezes, portanto, prever que um desvio de
volta ao início do laço será tomado, em geral é um bom palpite.
A segunda parte é mais tumultuada. Alguns desvios para frente ocorrem quando são detectadas condições
de erro em software (por exemplo, um arquivo não pode ser aberto). Erros são raros, portanto, quase todos os
desvios associados a eles não são tomados. É claro que há uma grande quantidade de desvios para frente que não
estão relacionados com o tratamento de erros, portanto, a taxa de sucesso não é tão boa quanto a dos desvios para
trás. Embora não seja fantástica, essa regra é, no mínimo, melhor do que nada.
Se um desvio for previsto corretamente, não há nada de especial a fazer. A execução apenas continua no
endereço de destino. O problema começa quando o desvio é previsto de forma errada. maginar para onde ir e
ir para lá não é difícil. A parte difícil é desfazer as instruções que já foram executadas e não deveriam ter sido.
Há dois modos de resolver isso. O primeiro é permitir que as instruções buscadas após um desvio con-
dicional previsto executem até que tentem mudar o estado da máquina (por exemplo, armazenando em um
registrador). Em vez de sobrescrever o registrador, o valor calculado é colocado em um registrador transitório
(secreto) e somente copiado para o registrador real após saber que a previsão estava correta. O segundo é registrar
o valor de qualquer registrador que esteja pronto para ser sobrescrito – por exemplo, em um registrador transi-
tório secreto –, de modo que a máquina possa ser levada de volta ao estado em que estava no momento em que
tomou o desvio mal previsto. Ambas as soluções são complexas e requerem contabilidade de nível industrial para
conseguir efetuá-las direito. Além do mais, se um segundo desvio condicional for atingido antes de se saber se a
previsão do primeiro estava correta, as coisas podem ficar complicadas de fato.
Previsa
o dina
mica de desvios
Claro que previsões exatas têm grande valor, uma vez que permitem que a CPU funcione a toda velocidade.
Como consequência, grande parte da pesquisa em curso tem como objetivo melhorar algoritmos de previsão de
desvio (Chen et al., 2003; Falcon et al., 2004; Jimenez, 2003; e Parikh et al., 2004). Uma abordagem é a CPU man-
ter uma tabela histórica (em hardware especial) na qual registra desvios condicionais à medida que eles ocorrem,
de modo que eles possam ser consultados quando ocorrerem novamente. A versão mais simples desse esquema
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
248
é mostrada na Figura 4.41(a). Nesse exemplo, a tabela histórica contém uma linha para cada instrução de desvio
condicional. A linha contém o endereço da instrução de desvio junto com um bit que informa se ele foi tomado da
última vez que foi executado. Usando esse esquema, a previsão é apenas que o desvio irá para o mesmo lugar
da última vez. Se a previsão estiver errada, o bit na tabela de histórico é alterado.
Figura 4.41 (a) Histo
rico de desvio de 1 bit. (b) Histo
rico de desvio de 2 bits. (c) Mapeamento entre enderec
o de instruc
a
o de desvio e
enderec
o de destino.
Válido
6
5
4
3
2
1
0
Desvio/
nenhum
Posição
Endereço/tag
do desvio Posição
Endereço/tag
do desvio Posição
Endereço/tag
do desvio
Endereço
de destino
(a)
Válido
6
5
4
3
2
1
0
Bits de
previsão
(c)
Válido
6
5
4
3
2
1
0
Bits de
previsão
(b)
Há diversos modos de organizar a tabela de histórico. Na verdade, são exatamente os mesmos modos usa-
dos para organizar uma cache. Considere uma máquina com instruções de 32 bits que são alinhadas por palavra
de modo que os 2 bits de ordem baixa de cada endereço de memória sejam 00. Com uma tabela de histórico de
mapeamento direto que contém 2n
entradas, os n + 2 bits de ordem baixa de uma instrução de desvio podem ser
extraídos e deslocados 2 bits para a direita. Esse número de n bits pode ser usado como um índice para a tabela
de histórico, onde é feita uma verificação para ver se o endereço ali armazenado é compatível com o endereço do
desvio. Como acontece com uma cache, não há necessidade de armazenar os n + 2 bits de ordem baixa, portanto,
eles podem ser omitidos (isto é, somente os bits mais altos de endereço – o tag – são armazenados). Se houver
compatibilidade, ou seja, uma presença na tabela, o bit de previsão é usado para prever o desvio. Se o tag errado
estiver presente ou a entrada for inválida, ocorre uma ausência na tabela (ou não há compatibilidade), exatamente
como na cache. Nesse caso, pode ser usada a regra do desvio para frente e para trás.
Se a tabela de histórico de desvio tiver, por exemplo, 4.096 entradas, então os desvios nos endereços 0,
16384, 32768, ... serão conflitantes, um problema semelhante ao que encontramos na cache. A mesma solução
é possível: uma entrada associativa de duas vias, quatro vias ou n vias. Assim como para a cache, o caso limite é
uma única entrada associativa de n vias, que requer associatividade total de consulta.
Dada uma tabela de tamanho suficiente e suficiente associatividade, esse esquema funciona bem na maioria
das situações. Contudo, sempre ocorre um problema sistemático. Quando por fim se atingir a saída de um laço,
é feita uma previsão errada para o desvio e, pior ainda, a má previsão mudará o bit na tabela de histórico para
indicar uma futura previsão de “nenhum desvio”. Na próxima vez que se entrar no laço, haverá uma previsão
errada de desvio ao final da primeira iteração. Se o laço estiver dentro de um laço externo, ou dentro de um pro-
cedimento que é chamado muitas vezes, esse erro pode acontecer com frequência.
Para eliminar essa má previsão, podemos dar uma segunda chance à entrada da tabela. Por tal método, a
previsão só é alterada após duas previsões incorretas. Essa abordagem requer dois bits de previsão na tabela de
histórico, um para o que o desvio “deve” fazer e um para o que fez da última vez, como mostra a Figura 4.41(b).
Um modo ligeiramente diferente de considerar esse algoritmo é vê-lo como uma máquina de estado finito de
quatro estados, como ilustra a Figura 4.42. Após uma série de previsões sucessivas certas de “nenhum desvio”, a
FSM estará no estado 00 e preverá “nenhum desvio” na próxima vez. Se essa previsão estiver errada, ela passará
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 249
para o estado 01, mas preverá “nenhum desvio” também na proxima vez. Só se essa previsão estiver errada, ela pas-
sará agora para o estado 11 e preverá desvios o tempo todo. Na verdade, o bit da extrema esquerda do estado é a
previsão e o da extrema direita é o que o desvio fez da última vez. Embora esse projeto use apenas 2 bits para o
histórico, um projeto que monitora 4 ou 8 bits de histórico também é possível.
Figura 4.42 Ma
quina de estado finito de 2 bits para previsa
o de desvio.
Nenhum desvio
Desvio
Desvio
00
Nenhum
desvio
Prever
nenhum
desvio
01
Prever nenhum
desvio
uma vez
10
Prever desvio
mais uma vez
Desvio
Nenhum
desvio
Desvio
Nenhum desvio
11
Prever
desvio
Essa não é nossa primeira FSM. A Figura 4.28 também era uma FSM. Na realidade, todos os nossos micro-
programas podem ser considerados FSMs, uma vez que cada linha representa um estado específico no qual a
máquina pode estar, com transições bem definidas para um conjunto finito de outros estados. FSMs são muito
usadas em todos os aspectos do projeto de hardware.
Até aqui, consideramos que o alvo de cada desvio condicional era conhecido, ou como um endereço explícito
para o qual desviar (contido dentro da própria instrução), ou como um deslocamento relativo com referência à ins-
trução corrente (isto é, um número com sinal para adicionar ao contador de programa). Muitas vezes, essa suposição
é válida, mas algumas instruções de desvio calculam o endereço de destino efetuando a aritmética nos registradores
e então se dirigem para aquele endereço. Mesmo que a FSM da Figura 4.42 preveja com exatidão que o desvio será
tomado, essa previsão de nada serve se o endereço de destino for desconhecido. Um modo de lidar com essa situa-
ção é armazenar na tabela de histórico o endereço ao qual o desvio se dirigiu da última vez, como mostra a Figura
4.41(c). Desse modo, se a tabela informar que da última vez que o desvio no endereço 516 foi tomado ele foi para
o endereço 4.000, se a previsão agora for “desvio”, a suposição de trabalho será um desvio para 4.000 novamente.
Uma abordagem diferente para a previsão de desvio é monitorar se os últimos k desvios condicionais encon-
trados foram tomados, pouco importando quais instruções eram. Esse número de k bits, mantido no registrador
de deslocamento da tabela de histórico, é então comparado em paralelo com todas as entradas de uma tabela de
histórico que tenham uma chave de k bits e, se ocorrer um sucesso, a previsão encontrada será usada. Por mais
surpreendente que seja, essa técnica funciona bastante bem.
Previsa
o esta
tica de desvio
Todas as técnicas de previsão de desvio discutidas até agora são dinâmicas, isto é, são realizadas em tempo de
execução, durante a execução do programa. Elas também se adaptam ao comportamento corrente do programa,
o que é bom. A desvantagem é que elas requerem hardware especializado e caro e muita complexidade no chip.
Um modo diferente de trabalhar é fazer com que o compilador ajude. Quando o compilador vir uma decla-
ração como
for (i = 0; i < 1000000; i++) { ... }
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
250
ele sabe muito bem que o desvio no final do laço será tomado quase toda vez. Se ao menos houvesse um meio
de ele informar ao hardware, muito esforço seria poupado.
Embora seja uma alteração de arquitetura, e não apenas uma questão de execução, algumas máquinas, como
a UltraSPARC , têm um segundo conjunto de instruções de desvio condicional, além das normais, que são
necessárias por compatibilidade. As novas contêm um bit no qual o compilador pode especificar que ele acha
que o desvio será tomado (ou não tomado). Quando uma dessas é encontrada, a unidade de busca apenas faz
o que lhe disseram para fazer. Além do mais, não há necessidade de desperdiçar precioso espaço da tabela de
histórico de desvios com essas instruções, reduzindo assim o conflito que ali acontece.
Por fim, nossa última técnica de previsão de desvio é baseada na determinação de perfil (Fisher e
Freudenberger, 1992). Essa também é uma técnica estática, mas em vez de fazer o compilador tentar adivinhar
quais desvios serão tomados e quais não serão, o programa é executado (normalmente em um simulador) e o
comportamento do desvio é capturado. Essa informação é alimentada no compilador, que então usa as instruções
de desvio condicional especial para informar ao hardware o que ele deve fazer.
4.5.3 Execuc
a
o fora de ordem e renomeac
a
o de registrador
Grande parte das CPUs modernas tem pipeline e também são superescalares, conforme mostra a Figura 2.6. Em
geral, isso significa que há uma unidade de busca que retira palavras de instrução da memória antes que elas sejam
necessárias, para alimentar uma unidade de decodificação. Esta emite as instruções decodificadas para as unidades
funcionais adequadas para execução. Em alguns casos, ela pode desmembrar instruções individuais em micro-
-operações antes de emiti-las para as unidades funcionais, dependendo do que as unidades funcionais podem fazer.
Claro que o projeto da máquina é mais simples se as instruções forem executadas na ordem em que são
buscadas (considerando, por enquanto, que o algoritmo de previsão de desvio nunca faça uma previsão errada).
Contudo, a execução em ordem nem sempre resulta em desempenho ideal, devido às dependências entre instru-
ções. Se uma instrução precisar de um valor calculado pela anterior, a segunda não pode começar a executar até
que a primeira tenha produzido o valor necessário. Nessa situação (uma dependência RAW), a segunda instrução
tem de esperar. Também existem outros tipos de dependência, como veremos em breve.
Em uma tentativa de contornar esses problemas e produzir melhor desempenho, algumas CPUs permitem
saltar instruções dependentes para chegar a instruções futuras que não são dependentes. Não é preciso dizer que o
algoritmo de escalonamento de instruções internas usado deve causar o mesmo efeito que causaria se o programa
fosse executado na ordem escrita. Agora, demonstraremos como a reordenação de instruções funciona usando
um exemplo detalhado.
Para ilustrar a natureza do problema, começaremos com uma máquina que sempre emite instruções na
ordem do programa e também requer que sua execução seja concluída na ordem do programa. A significância
dessa última exigência ficará clara mais adiante.
Nosso exemplo de máquina tem oito registradores visíveis para o programador, R0 até R7. Todas as instru-
ções aritméticas usam três registradores: dois para os operandos e um para o resultado, igual à Mic-4. amos
considerar que, se uma instrução for decodificada no ciclo n, a execução inicia no ciclo n + 1. Para uma instrução
simples, como uma adição ou subtração, a escrita retroativa no registrador de destino ocorre ao final do ciclo
n + 2. Para uma instrução mais complicada, como uma multiplicação, a escrita retroativa ocorre ao final do
ciclo n + 3. Para tornar o exemplo realista, permitiremos que a unidade de decodificação emita até duas instruções
por ciclo de clock. Há várias CPUs escalares comerciais que podem emitir quatro ou até seis por ciclo de clock.
Nosso exemplo de sequência de execução é mostrado na Figura 4.43. Nesse caso, a primeira coluna dá o
número do ciclo e a segunda dá o número da instrução. A terceira coluna relaciona a instrução decodificada. A
quarta informa qual instrução está sendo emitida (com um máximo de duas por ciclo de clock). A quinta informa
qual instrução foi retirada, ou concluída. Lembre-se de que nesse exemplo estamos exigindo emissão em ordem,
bem como conclusão em ordem, portanto, a instrução k + 1 não pode ser emitida até que a k tenha sido emitida
e a instrução k + 1 não pode ser retirada (ou seja, não pode ser escrita retroativamente no registrador de destino)
até que k tenha sido retirada. As outras 16 colunas são discutidas logo adiante.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 251
Figura 4.43 CPU superescalar com emissa
o em ordem e conclusa
o em ordem.
Registradores lidos Registradores escritos
Ciclo # Decodificado Emit. Ret. 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
1 R3=R0
*R1 1 1 1 1
2 R4=R0+R2 2 2 1 1 1 1
2 R5=R0+R1 3 3 2 1 1 1 1
4 R6=R1+R4 – 3 2 1 1 1 1
3
3 2 1 1 1 1
1
4 2 1 1 1 1
2 1 1
1
3
4
5 1 1 1
5 R7=R1
*R2 5 2 1 1
1 1
6 R1=R0−R2 – 2 1 1
1 1
4
7 1 1 1
5
8
6
9 1 1 1
7 R3=R3
*R1 – 1 1 1
10 1 1 1
11 6
12 7 1 1 1
8 R1=R4+R4 – 1 1 1
13 1 1 1
14 1 1 1
15 7
16 2
8 1
17 2 1
18 8
6
3
1
Após decodificar a instrução, a unidade de decodificação tem de decidir se pode ou não emiti-la imediata-
mente. Para tomar essa decisão, a unidade de decodificação precisa conhecer o estado de todos os registradores.
Se, por exemplo, a instrução corrente precisar de um registrador cujo valor ainda não foi calculado, ela não pode
ser emitida e a CPU deve protelar.
A utilização do registrador será monitorada com um dispositivo denominado tabela de pontuação (score-
board), encontrado pela primeira vez no CDC 6600. A tabela tem um pequeno contador para cada registrador,
que informa quantas vezes um determinado registrador é usado como uma fonte por instruções que estão sendo
executadas naquele momento. Se, por exemplo, o número máximo de instruções que podem ser executadas ao
mesmo tempo for 15, então um contador de 4 bits será suficiente. Quando uma instrução é emitida, as entradas da
tabela de pontuação para seus registradores de operandos são incrementadas. Quando uma instrução é retirada,
as entradas são decrementadas.
A tabela de pontuação também tem contadores para monitorar os registradores usados como destino. Uma
vez que só é permitida uma escrita por vez, esses contadores podem ter um bit de largura. As 16 colunas da
extrema direita na Figura 4.43 mostram a tabela de pontuação.
Em máquinas reais, a tabela também monitora a utilização da unidade funcional, para evitar emitir uma
instrução para a qual não há nenhuma unidade funcional disponível. Para simplificar, consideraremos que há
sempre uma, portanto, não mostraremos as unidades funcionais na tabela de pontuação.
A primeira linha da Figura 4.43 mostra 1 (instrução 1), que multiplica R0 por R1 e coloca o resultado em
R3. Uma vez que nenhum desses registradores está em uso ainda, a instrução é emitida e a tabela de pontuação é
atualizada para refletir que R0 e R1 estão sendo lidos, e R3 está sendo escrito. Nenhuma instrução subsequente
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
252
pode escrever para qualquer um deles, nem pode ler R3, até que 1 seja retirada. isto que essa instrução é uma
multiplicação, ela será concluída no final do ciclo 4. Os valores da tabela de pontuação mostrados em cada linha
refletem seus estados após a emissão da instrução que está naquela linha. Entradas em branco são 0s.
isto que nosso exemplo é uma máquina superescalar que pode emitir duas instruções por ciclo, a segunda
instrução (2) é emitida durante o ciclo 1. Ela soma R0 e R2 e armazena o resultado em R4. Para ver se essa ins-
trução pode ser emitida, são aplicadas as seguintes regras:
1. Se qualquer operando estiver sendo escrito, não emita (dependência RAW).
2. Se o registrador de resultado estiver sendo lido, não emita (dependência WAR).
3. Se o registrador de resultado estiver sendo escrito, não emita (dependência WAW).
Já vimos dependências RAW, que ocorrem quando uma instrução precisa usar como fonte um resultado
que uma instrução prévia ainda não produziu. As outras duas dependências são menos sérias – são, em essência,
conflitos de recursos. Em uma dependência WR (Write fter Read – escrita após leitura), uma instrução está
tentando sobrescrever um registrador que uma instrução anterior pode não ter terminado de ler ainda. Uma
dependência WW (Write fter Write – escrita após escrita) é parecida. Muitas vezes, elas podem ser evitadas
obrigando a segunda instrução a colocar seus resultados em algum outro lugar (talvez temporariamente). Se não
existir nenhuma das três dependências citadas e a unidade funcional de que a instrução necessita estiver disponí-
vel, a instrução é emitida. Nesse caso, 2 usa um registrador (R0) que está sendo lido por uma instrução pendente,
mas essa sobreposição é permitida, portanto, 2 é emitida. De modo semelhante, 3 é emitida durante o ciclo 2.
Agora, chegamos à 4, que precisa usar R4. nfelizmente, vemos pela linha 3 que R4 está sendo escrita. Nesse
caso, temos uma dependência RAW, portanto, a unidade de decodificação protela até que R4 fique disponível.
Durante a protelação, a unidade de decodificação para de retirar instruções da unidade de busca. Quando os
buffers internos da unidade de busca estiverem cheios, ela para de fazer a busca antecipada.
ale a pena notar que a próxima instrução na ordem do programa, 5, não tem conflitos com nenhuma das
instruções pendentes. Ela poderia ter sido decodificada e emitida se não fosse pelo fato de esse projeto exigir que
as instruções sejam emitidas em ordem.
Agora, vamos ver o que acontece durante o ciclo 3. 2, por ser uma adição (dois ciclos), termina no final do
ciclo 3. nfelizmente, ela não pode ser retirada (e liberar R4 para 4). Por que não? A razão é que esse projeto
também requer retirada em ordem. Por quê? Que mal poderia acontecer por fazer o armazenamento em R4 agora
e marcá-lo como disponível?
A resposta é sutil, mas importante. Suponha que instruções pudessem concluir fora de ordem. Então, se
ocorresse uma interrupção, seria muito difícil salvar o estado da máquina de modo que ele pudesse ser restaura-
do mais tarde. Em particular, não seria possível afirmar que todas as instruções até algum endereço tinham sido
executadas e que todas as instruções depois dele, não. Essa característica é denominada interrupção exata e é
desejável em uma CPU (Moudgill e assiliadis, 1996). A retirada fora de ordem torna as interrupções inexatas,
e é por isso que algumas máquinas requerem conclusão de instrução em ordem.
oltando a nosso exemplo, no final do ciclo 4, todas as três instruções pendentes podem ser retiradas,
portanto, 4 pode ser enfim emitida no ciclo 5, junto com a 5 recém-decodificada. Sempre que uma instrução é
retirada, a unidade de decodificação tem de verificar se há uma instrução protelada que agora possa ser emitida.
No ciclo 6, 6 é protelada por que ela precisa escrever para R1, mas R1 está ocupado. Por fim, ela é iniciada
no ciclo 9. A sequência inteira de oito instruções leva 18 ciclos para ser concluída devido a muitas dependências,
ainda que o hardware seja capaz de emitir duas instruções em cada ciclo. Entretanto, note que, ao ler a coluna
Emit. da Figura 4.43 de cima para baixo, todas as instruções foram emitidas em ordem. Da mesma forma, a
coluna Ret. mostra que elas também foram retiradas na ordem.
Agora, vamos considerar um projeto alternativo: execução fora de ordem. Nesse projeto, instruções podem
ser emitidas e também podem ser retiradas fora de ordem. A mesma sequência de oito instruções é mostrada na
Figura 4.44, só que agora são permitidas emissão fora de ordem e retirada fora de ordem.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 253
Figura 4.44 Operac
a
o de uma CPU superescalar com emissa
o de instruc
a
o fora de ordem e conclusa
o de instruc
a
o fora de ordem.
Registradores lidos Registradores escritos
Ciclo # Decodificado Emit. Ret. 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
1 R3=R0
*R1 1 1 1 1
2 R4=R0+R2 2 2 1 1 1 1
2 R5=R0+R1 3 3 2 1 1 1 1
4 R6=R1+R4 – 3 2 1 1 1 1
3
1
3
4
5
6
7
8
9
R7=R1*R2 5 3 3 2 1 1 1 1
6 4 3 3 1 1 1 1
2 3 3 2 1 1 1
4 3 4 2 1 1 1 1 1
– 3 4 2 1 1 1 1 1
8 3 4 2 3 1 1 1 1
1 2 3 2 3 1 1 1
3 1 2 2 3 1 1
6 2 1 3 1 1 1
7 2 1 1 3 1 1 1 1
4 1 1 1 2 1 1 1
5 1 2 1 1
8 1 1
1 1
1 1
7
5
6
7
8
S1=R0–R2
R3=R3 S1
S2=R4+R4
*
A primeira diferença ocorre no ciclo 3. Ainda que 4 tenha sido protelada, temos permissão para decodificar
e emitir 5, uma vez que ela não conflita com qualquer instrução pendente. Contudo, saltar instruções causa um
novo problema. Suponha que 5 tenha usado um operando calculado pela instrução que foi saltada, 4. Com a tabe-
la de pontuação corrente, não teríamos notado isso. Por conseguinte, temos de estender a tabela para monitorar
os armazenamentos feitos por instruções que foram saltadas. sso pode ser feito adicionando um segundo mapa de
bits, 1 bit por registrador, para monitorar armazenamentos feitos por instruções proteladas. (Esses contadores não
são mostrados na figura.) Agora, a regra de emissão tem de ser estendida para evitar a emissão de qualquer instru-
ção que tenha um operando escalonado para ser armazenado por uma instrução que veio antes, mas que foi saltada.
amos voltar e examinar 6, 7 e 8 na Figura 4.43. Nela, vemos que 6 calcula um valor em R1 que é usado
por 7. Contudo, vemos também que o valor nunca é usado de novo porque 8 sobrescreve R1. Não há nenhuma
razão real para usar R1 como o lugar para conter o resultado de 6. Pior ainda, R1 é uma péssima escolha de
registrador intermediário, embora seja perfeitamente razoável para um compilador ou programador acostumado
com a ideia de execução sequencial sem nenhuma sobreposição de instruções.
Na Figura 4.44, introduzimos uma nova técnica para resolver esse problema: registrador de renomeação.
A sábia unidade de decodificação transfere a utilização de R1 em 6 (ciclo 3) e 7 (ciclo 4) para um registrador
secreto, S1, que não é visível para o programador. Agora, 6 pode ser emitida ao mesmo tempo em que 5. CPUs
modernas costumam ter dezenas de registradores secretos para usar com renomeação de registrador. Essa técnica
muitas vezes pode eliminar dependências WAR e WAW.
Em 8, usamos outra vez a renomeação de registrador. Desta vez, R1 é renomeado para S2, de modo que
a adição pode ser iniciada antes que R1 esteja livre, no final do ciclo 6. Se acaso o resultado realmente tiver de
estar em R1 desta vez, o conteúdo de S2 sempre pode ser copiado de volta para lá a tempo. Melhor ainda, todas
as futuras instruções que precisem dele podem ter suas fontes renomeadas para o registrador onde elas de fato
estão armazenadas. Seja como for, desse modo a adição 8 conseguiu começar mais cedo.
Em muitas máquinas reais, a renomeação está profundamente embutida no modo como os registradores são
organizados. Há muitos registradores secretos e uma tabela que mapeia os registradores visíveis ao programador
para os registradores secretos. Assim, o registrador real que está sendo usado para, por exemplo, R0, é localizado
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
254
examinando-se a entrada 0 dessa tabela de mapeamento. Desse modo, não existe nenhum registrador real R0,
mas apenas uma vinculação entre o nome R0 e um dos registradores secretos. Essa vinculação muda muitas vezes
durante a execução, para evitar dependências.
Note que, na Figura 4.44, quando lemos a quarta coluna de cima para baixo, as instruções não foram emiti-
das em ordem. Tampouco foram retiradas em ordem. A conclusão desse exemplo é simples: usando a execução
fora de ordem e a renomeação de registrador, podemos acelerar o cálculo por um fator de dois.
4.5.4 Execuc
a
o especulativa
Na seção anterior, introduzimos o conceito de reordenação de instruções de modo a melhorar o desempe-
nho. Embora não o tenhamos mencionado explicitamente, o foco estava sobre a reordenação de instruções dentro
de um único bloco básico. Agora, está na hora de examinar essa questão mais de perto.
Programas de computador podem ser desmembrados em blocos básicos, em que cada um consiste em uma
sequência linear de código com um ponto de entrada no início e uma saída no final. Um bloco básico não con-
tém qualquer estrutura de controle (por exemplo, instruções if ou declarações while), de modo que sua tradução
para linguagem de máquina não contém nenhum desvio. Os blocos básicos são conectados por declarações de
controle.
Um programa nessa forma pode ser representado por um gráfico orientado, conforme mostra a Figura 4.45.
Nesse exemplo, calculamos as somas dos cubos dos inteiros pares e ímpares até algum limite e as acumulamos
em evensum e oddsum, respectivamente. Dentro de cada bloco básico, as técnicas de reordenação da seção anterior
funcionam bem.
Figura 4.45 (a) Fragmento de programa. (b) Gra
fico de blocos ba
sicos correspondente.
evensum = 0;
oddsum = 0;
i = 0;
while (i < limit) {
k = i * i * i;
k = i * i * i;
if (((i/2) * 2) == i)
evensum = evensum + k;
else
oddsum = oddsum + k;
}
(a) (b)
evensum = 0;
oddsum = 0;
i = 0;
while (i < limit)
if (((i/2) * 2) == i)
T F
evensum = evensum + k; oddsum = oddsum + k;
i = i + 1;
i = i + 1;
i >= limit
O problema é que a maioria dos blocos básicos é curta e não há paralelismo suficiente para explorá-los de
modo efetivo. Por conseguinte, a próxima etapa é permitir que a reordenação cruze as fronteiras de blocos básicos
na tentativa de preencher todas as posições de emissão. Os maiores ganhos ocorrem quando uma operação poten-
cialmente lenta pode ser passada para cima no gráfico para ser iniciada mais cedo. Essa instrução pode ser uma
instrução LOAD, uma operação de ponto flutuante ou até mesmo o início de uma longa cadeia de dependência.
A transferência de um código para cima através de um desvio é denominada elevação.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 255
magine que, na Figura 4.45, todas as variáveis fossem mantidas em registradores, exceto evensum e oddsum,
por falta de registradores. Portanto, talvez fizesse sentido passar suas instruções LOAD para o topo do laço antes
de calcular k, para iniciá-las cedo, de modo que os valores estarão disponíveis quando necessários. Claro que
somente uma delas será necessária em cada iteração, portanto, a outra LOAD será desperdiçada, mas se a cache e
a memória tiverem pipelining e houver posições de emissão disponíveis, talvez ainda valesse a pena fazer isso. A
execução de código antes mesmo de saber se ele será necessário é denominada execução especulativa. Usar essa
técnica requer suporte do compilador e do hardware, bem como algumas extensões na arquitetura. Em geral,
reordenar instruções atravessando fronteiras de blocos básicos está além da capacidade do hardware, portanto, o
compilador deve mover as instruções explicitamente.
A execução especulativa introduz alguns problemas interessantes. Um deles é que nenhuma das instruções
especulativas tem resultados irrevogáveis, porque mais tarde pode-se descobrir que elas não deveriam ter sido
executadas. Na Figura 4.45, é bom buscar evensum e oddsum, e também é bom efetuar a adição tão logo k esteja
disponível (mesmo antes da declaração if), mas não é bom armazenar os resultados de volta na memória. Em
sequências de código mais complicadas, um modo comum de evitar que o código especulativo sobrescreva regis-
tradores antes de se saber se isso é desejado é renomear todos os registradores de destino usados pelo código
especulativo. Desse modo, apenas registradores temporários são modificados, portanto, não há problema algum
se, afinal, o código não for necessário. Se o código for necessário, os registradores transitórios são copiados para
os verdadeiros registradores de destino. Como você pode imaginar, a tabela de pontuação para monitorar tudo
isso não é simples, mas, com hardware suficiente, pode ser feita.
Entretanto, há outro problema introduzido pelo código especulativo que não pode ser resolvido por reno-
meação de registrador. O que acontece se uma instrução executada por especulação causar uma exceção? Um
exemplo doloroso, mas não fatal, é uma instrução LOAD que causa uma ausência da cache em uma máquina cuja
linha de cache é de tamanho grande (por exemplo, 256 bytes) e a memória é muito mais lenta do que a CPU
e a cache. Se um LOAD que é realmente necessário fizer a máquina parar de vez durante muitos ciclos enquanto
a linha de cache está sendo carregada, bom, são coisas da vida, já que a palavra é necessária. Contudo, protelar a
máquina para buscar uma palavra que, afinal, não é necessária, é contraproducente. Muitas dessas “otimizações”
podem fazer a CPU ficar mais lenta do que se ela não as tivesse. Se a máquina tiver memória virtual, que é dis-
cutida no Capítulo 6, um LOAD especulativo pode até causar uma falta de página, o que requer uma operação de
disco para trazer a página necessária. Falsas faltas de página podem causar um efeito terrível sobre o desempenho,
portanto, é importante evitá-las.
Uma solução presente em várias máquinas modernas é inserir uma instrução SPECULATIVE-LOAD que tenta
buscar a palavra na cache, mas, se ela não estiver lá, desiste. Se o valor estiver na cache quando for mesmo neces-
sário, ele pode ser usado ou não; caso não esteja, o hardware tem de entrar em cena e obtê-lo imediatamente. Se
o valor se revelar não necessário, nada de ruim aconteceu pela ausência da cache.
Uma situação muito pior pode ser ilustrada com a seguinte declaração:
if (x > 0) z = y/x;
em que x, y e z são variáveis de ponto flutuante. Suponha que as variáveis são todas buscadas com antecedên-
cia para registradores e que a divisão com ponto flutuante (uma operação lenta) é elevada para cima do teste if.
nfelizmente, x é 0 e a exceção resultante, isto é, a divisão por zero, encerra o programa. O resultado líquido é
que a especulação causou a falha de um programa correto. Pior ainda, o programador inseriu um código explícito
para evitar essa situação e, mesmo assim, ela aconteceu. Provavelmente, o programador não ficará feliz com isso.
Uma solução possível é ter versões especiais e instruções que poderiam causar exceções. Além disso, um
bit denominado bit envenenado é adicionado a cada registrador. Quando uma instrução especulativa especial
falhar, em vez de causar uma exceção, ela ajusta o bit envenenado no registrador de resultado. Se mais adiante
uma instrução normal chegar a esse registrador, a armadilha ocorre nesse momento (como deveria). Contudo,
se o resultado nunca é usado, o bit envenenado mais cedo ou mais tarde é eliminado e não há prejuízo algum.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
256
4.6 Exemplos do n
vel de microarquitetura
Nesta seção, apresentaremos exemplos resumidos de três processadores de alta tecnologia, mostrando como
eles empregam os conceitos explorados neste capítulo. Os exemplos terão que ser breves porque máquinas reais
são de uma complexidade enorme, contendo milhões de portas. Os exemplos são os mesmos que usamos até
agora: Core i7, OMAP4430 e ATmega168.
4.6.1 A microarquitetura da CPU Core i7
Por fora, o Core i7 parece uma máquina CSC tradicional, com um conjunto de instruções imenso e desajeitado
que suporta operações com inteiros de 8, 16 e 32 bits, bem como operações de ponto flutuante de 32 bits e 64 bits.
Tem somente oito registradores visíveis por processador e não há dois deles que sejam exatamente iguais. Os com-
primentos de instruções variam de 1 a 17 bytes. Resumindo, é uma arquitetura herdada que parece fazer tudo errado.
Entretanto, por dentro, contém um núcleo RSC moderno, enxuto e de alto grau de pipelining, que trabalha a
uma taxa de clock de extrema rapidez e que provavelmente crescerá nos anos vindouros. É impressionante como
os engenheiros da ntel conseguiram construir um processador de última geração para implementar uma arquite-
tura antiga. Nesta seção, examinaremos a microarquitetura do Core i7 para ver como ela funciona.
Visa
o geral da microarquitetura Sandy Bridge do Core i7
A microarquitetura do Core i7, denominada microarquitetura Sandy Bridge, é uma ruptura total em relação
às microarquiteturas ntel anteriores, incluindo as antigas P4 e P6. Uma visão geral esquemática da microarqui-
tetura do Core i7 é dada na Figura 4.46.
Figura 4.46 Diagrama de blocos do Core i7.
Para cache L3 compartilhada
ULAs de inteiros, unidades
de ponto utuante, buffer
de armazenamento
Cache de
micro-operações
Renomeação,
escalonamento
Previsor
de desvio
Cache de
instrução nível 1
Unidade de execução
Unidade
de retirada
Controle de fora de ordem
Terminal frontal
Cache de
dados nível 1
Cache nível 2
(instruções e dados)
Interface do sistema
Subsistema de memória
Unidade de
busca/
decodicação
O Core i7 consiste em quatro subseções principais: o subsistema de memória, o terminal frontal, o controle
de fora de ordem e as unidades de execução. amos examiná-las uma por uma, começando na parte superior
esquerda e percorrendo o chip em sentido anti-horário.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 257
Cada processador no Core i7 contém um subsistema de memória com uma cache L2 (de nível 2) unificada,
bem como a lógica para acessar a cache L3 (nível 3). Uma única cache L3 grande é compartilhada por todos os
processadores, e essa é a última parada antes de sair do chip da CPU e fazer a longa jornada até a RAM externa
pelo barramento de memória. As caches L2 do Core i7 têm um tamanho de 256 KB, e cada uma é organizada
como uma cache associativa de 8 vias com linhas de 64 bytes. A cache L3 compartilhada varia em tamanho de 1
MB a 20 MB. Se você pagar mais à ntel, terá mais cache em retorno. ndependentemente do seu tamanho, a L3 é
organizada como uma cache associativa em 12 vias, com linhas de cache de 64 bytes. Caso haja uma ausência de
cache L3, o acesso é enviado à RAM externa por meio do barramento de RAM DDR3.
Associada à cache L1 estão duas unidades de busca antecipada (que não aparecem na figura) que tentam
buscar dados com antecedência de níveis inferiores do sistema de memória para a cache L1, antes de eles serem
necessários. Uma unidade de busca antecipada consulta o próximo bloco de memória quando detecta que um
“fluxo” de sequência da memória está sendo buscado para o processador. Um segundo buscador antecipado, mais
sofisticado, cuida da sequência de endereços dos loads e stores do programa específico. Se eles prosseguirem a um
passo regular (por exemplo, 0x1000... 0x1020... 0x1040...), ele buscará o próximo elemento que provavelmente
será acessado de modo antecipado ao programa. Essa pré-busca orientada a passo faz maravilhas para programas
que estão marchando pelas fileiras de variáveis estruturadas.
O subsistema de memória na Figura 4.46 está conectado tanto ao terminal frontal quanto à cache de dados
L1. O terminal frontal é responsável por buscar instruções do sistema de memória, decodificando-as para micro-
-operações parecidas com RSC e armazenando-as em duas caches de armazenamento de instrução. Todas as ins-
truções buscadas são colocadas na cache de instrução L1 (nível 1). Esta tem um tamanho de 32 KB e é organizada
como uma cache associativa de 8 vias com blocos de 64 bytes. À medida que as instruções são buscadas da cache
L1, elas entram nos decodificadores que determinam a sequência de micro-operações usada para implementar
a instrução no pipeline de execução. O mecanismo decodificador une a lacuna entre um conjunto de instruções
CSC antigo e um caminho de dados RSC moderno.
As micro-operações decodificadas são alimentadas na cache de micro-operações, que a ntel chama de cache
de instruções L0 (de nível 0). Ela é semelhante a uma cache de instruções tradicional, mas tem muito espaço
extra para armazenar as sequências de micro-operações produzidas pelas instruções individuais. Quando as
micro-operações decodificadas, em vez das instruções originais, são colocadas em cache, não é preciso deco-
dificar a instrução em execuções subsequentes. À primeira vista, você poderia pensar que a ntel fez isso para
acelerar o pipeline (e, na verdade, isso agiliza o processo de produção de uma instrução), mas a empresa afirma
que a cache de micro-operações foi incluída para reduzir o consumo de potência do terminal frontal. Com a
cache de micro-operações no lugar, o restante do terminal frontal dorme em um modo de baixa potência sem
clock durante 80% do tempo.
A previsão de desvio também é realizada no terminal frontal. O previsor de desvio é responsável por desco-
brir quando o fluxo do programa sai da busca de sequência pura, e deve ser capaz de fazer isso muito antes que
as instruções de desvio sejam executadas. O previsor de desvio no Core i7 é incrível. nfelizmente para nós, os
detalhes dos previsores de desvio do processador são segredos mantidos para a maior parte dos projetos. sso por-
que o desempenho do previsor geralmente é o componente mais crítico da velocidade geral do projeto. Quanto
mais exatidão na previsão os projetistas puderem espremer de cada micrômetro quadrado de silício, melhor o
desempenho do projeto inteiro. Assim, as empresas escondem esses segredos a sete chaves, e até mesmo ameaçam
os funcionários com processo criminal se qualquer um deles decidir compartilhar essas joias de conhecimento.
Basta dizer, no entanto, que todos eles acompanham de que modo os desvios anteriores seguiram e usam isso para
fazer previsões. Os detalhes de exatamente o que eles registram e como eles armazenam e consultam a informação
é um algoritmo altamente secreto. Afinal, se você tivesse um modo infalível de prever o futuro, é bem provável
que não o colocaria na Web para todo mundo ver.
nstruções são alimentadas da cache de micro-operações para o escalonador fora de ordem, na ordem ditada
pelo programa, porém, elas não são necessariamente emitidas na ordem do programa. Quando é encontrada uma
micro-operação que não pode ser executada, o escalonador a retém mas continua processando o fluxo de instru-
ções para emitir instruções subsequentes para as quais todos os recursos (registradores, unidades funcionais etc.)
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
258
estão disponíveis. A renomeação de registradores também é feita aqui, para permitir que instruções com uma
dependência WAR ou WAW prossigam sem atraso.
Embora instruções possam ser emitidas fora de ordem, o requisito de interrupções exatas da arquitetura do
Core i7 significa que as instruções SA devem ser retiradas (isto é, seus resultados devem ficar visíveis) na ordem
original do programa. A unidade de retirada executa essa tarefa.
No back end do processador, temos as unidades de execução que efetuam as instruções de inteiros, de ponto
flutuante e especializadas. Existem várias dessas unidades e elas funcionam em paralelo. Elas obtêm seus dados
do arquivo do registrador e da cache de dados L1.
O pipeline da Sandy Bridge do Core i7
A Figura 4.47 é uma versão simplificada da microarquitetura Sandy Bridge, mostrando o pipeline. Na parte
superior, está o terminal frontal, cuja tarefa é buscar instruções na memória e prepará-las para execução. O
terminal frontal recebe novas instruções x86 da cache de instruções L1. Ele as decodifica para micro-operações
para armazenamento na cache de micro-operações, que retém mais ou menos 1,5 K micro-operações. Uma cache
de micro-operações desse tamanho dá um desempenho comparável ao de uma cache L0 convencional de 6 KB.
A cache de micro-operações contém grupos de seis micro-operações em uma única linha de rastreamento. Para
sequências mais longas de micro-operações, várias linhas de rastreamento podem ser interligadas.
Figura 4.47 Visa
o simplificada do caminho de dados do Core i7.
Cache de
instrução nível 1
Unidade de
decodicação
Previsor
de desvio/
buffer de
destino
do desvio
Cache de
micro-operações
Para cache
compartilhada
nível 3
Unidade de alocação/renomeação
Cache
unicada
nível 2
Escalonador
sem memória
Controle
de fora
de ordem
Terminal
frontal
Escalonador
com memória
ULA 1 Store
ULA 2 ULA 3 Load 1 Load 2
Cache
de dados
nível 1
Unidade de retirada
Se a unidade de decodificação encontrar um desvio condicional, ela consulta sua direção prevista no Previsor
de esvio. O previsor de desvio contém o histórico dos desvios encontrados no passado e usa esse histórico para
descobrir se um desvio condicional será ou não tomado da próxima vez que for encontrado. É aí que é usado o
algoritmo altamente secreto.
Se a instrução de desvio não estiver na tabela, é usada previsão estática. Um desvio para trás é entendido
como parte de um laço e admite-se que deve ser tomado. A exatidão dessas previsões estáticas é extremamente
alta. Um desvio para frente é entendido como parte de uma declaração if e admite-se que não deve ser tomado. A
exatidão dessas previsões estáticas é bem mais baixa do que a de desvios para trás.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 259
Para um desvio tomado, o BB (Branch arget Buffer – buffer de alvo de desvio) é consultado para deter-
minar o endereço de destino. O BTB mantém o endereço de destino do desvio na última vez que ele foi tomado.
Quase sempre, esse endereço está correto (na verdade, ele está sempre correto para desvios com um deslocamento
constante). Os desvios indiretos, como os usados pelas chamadas de função virtual e comandos switch da C++,
vão para muitos endereços, e eles podem ser interpretados incorretamente pelo BTB.
A segunda parte do pipeline, a lógica de controle fora de ordem, é alimentada a partir da cache de micro-
-operações. À medida que cada micro-operação chega ao terminal frontal, até quatro por ciclo, a unidade de
alocação/renomeação a registra em uma tabela de 168 entradas denominada ROB (ReOrder Buffer  buffer
de reordenação). Essa entrada monitora o estado da micro-operação até ela ser retirada. Em seguida, a unidade de
alocação/renomeação verifica para ver se os recursos de que a micro-operação necessita estão disponíveis.
Se estiverem, ela é enfileirada para execução em uma das filas do escalonador. São mantidas filas separadas
para micro-operações da memória e para as que não são da memória. Se uma micro-operação não puder ser
executada, ela é retardada, mas as subsequentes são processadas, o que leva à execução fora de ordem das
micro-operações. Essa estratégia foi projetada para manter todas as unidades funcionais o mais ocupadas possí-
vel. Até 154 instruções podem estar no ar a qualquer instante e até 64 dessas podem ser carregadas da memória
e até 36 podem ser armazenamentos para a memória.
Às vezes, uma micro-operação é protelada porque precisa escrever para um registrador que está sendo lido
ou escrito por uma micro-operação anterior. Esses conflitos são denominados dependências WAR e WAW, res-
pectivamente, como vimos antes. Renomeando o alvo da nova micro-operação para permitir que ela escreva seu
resultado em um dos 160 registradores transitórios em vez de no alvo pretendido, mas ainda ocupado, pode ser
possível escalonar a micro-operação para execução imediatamente. Se não houver nenhum registrador transitório
disponível, ou se a micro-operação tiver uma dependência RAW (que nunca poderá ser ignorada), o alocador
observa a natureza do problema na entrada do ROB. Quando todos os recursos requisitados ficam disponíveis
mais tarde, a micro-operação é colocada em uma das filas do escalonador.
O escalonador envia as micro-operações para as seis unidades funcionais quando elas estiverem prontas para
executar. As unidades funcionais são as seguintes:
1. ULA 1 e a unidade de multiplicação de ponto flutuante.
2. ULA 2 e a unidade de adição/subtração de ponto flutuante.
3. ULA 3 e a unidade de processamento de desvio e comparações de ponto flutuante.
4. nstruções store.
5. nstruções load 1.
6. nstruções load 2.
Uma vez que os escalonadores e as ULAs podem processar uma operação por ciclo, um Core i7 de 3 GHz
tem o desempenho do escalonador para realizar 18 bilhões de operações por segundo; porém, o processador
na realidade nunca alcançará esse nível de vazão. isto que o terminal frontal fornece no máximo quatro
micro-operações por ciclo, seis micro-operações só podem ser emitidas em curtas rajadas, pois logo as filas do
escalonador se esvaziarão. Além disso, cada unidade de memória usa quatro ciclos para processar suas opera-
ções, de modo que elas poderiam contribuir para a vazão de execução máxima apenas em pequenas rajadas.
Apesar de serem capazes de saturar totalmente os recursos de execução, as unidades funcionais oferecem uma
capacidade de execução significativa, e é por isso que o controle de fora de ordem tem tanto trabalho para
encontrar trabalho para ela realizarem.
As três ULAs de inteiros não são idênticas. A ULA 1 pode executar todas as operações aritméticas, lógicas,
multiplicações e desvios. A ULA 2 pode efetuar apenas operações aritméticas e lógicas. A ULA 3 pode realizar
operações aritméticas e lógicas e resolver desvios. Da mesma forma, as duas unidades de ponto flutuante também
não são idênticas. A primeira pode realizar aritmética de ponto flutuante, incluindo multiplicações, enquanto a
segunda só pode realizar adições, subtrações e movimentações de ponto flutuante.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
260
As unidades de ULA e ponto flutuante são alimentadas por um par de arquivos de registradores de 128 entra-
das, um para inteiros e um para números de ponto flutuante. Eles fornecem todos os operandos para as instruções
a serem executadas e um repositório para resultados. Devido à renomeação de registradores, oito deles contêm os
registradores visíveis no nível SA (EAX, EBX, ECX, EDX etc.), porém, quais oito deles retêm os valores “reais”
varia ao longo do tempo à medida que o mapeamento muda durante a execução.
A arquitetura Sandy Bridge introduziu a Advanced ector Extensions (A), que admite operações de vetor
com dados paralelos de 128 bits. As operações de vetor incluem vetores de ponto flutuante e inteiros, e essa nova
extensão SA representa um aumento de duas vezes no tamanho dos vetores agora admitidos em comparação com
as extensões SA SSE e SSE2 anteriores. Como a arquitetura executa operações de 256 bits somente com caminhos
de dados e unidades funcionais de 128 bits? Ela coordena, de modo inteligente, duas portas de escalonador de
128 bits para produzir uma única unidade funcional de 256 bits.
A cache de dados L1 é firmemente acoplada ao back end da arquitetura paralela Sandy Bridge. Ela é uma cache
de 32 KB e mantém inteiros números de ponto flutuante e outros tipos de dados. Diferente da cache de micro-ope-
rações, ela não é decodificada de modo algum e apenas retém uma cópia dos bytes na memória. A cache de dados L1
é uma cache associativa de 8 vias com 64 bytes por linha. É uma cache de escrita direta, o que significa que, quando
uma linha de cache é modificada, é imediatamente copiada de volta para a cache L2 quando sai da cache de dados
L1. A cache pode manipular duas operações de leitura e uma de escrita por ciclo de clock. Esses múltiplos acessos
são executados usando banking, que divide a cache em subcaches separadas (8 no caso da Sandy Bridge). Desde que
todos os três acessos sejam para bancos separados, eles podem prosseguir em sequência; caso contrário, todos menos
um dos acessos conflitantes ao banco terão que ser protelados. Quando uma palavra necessária não estiver presente
na cache L1, uma requisição é enviada à L2 que, ou responde imediatamente, ou busca a linha de cache na L3 com-
partilhada e então responde. Até dez requisições da cache L1 à cache L2 podem estar em curso a qualquer instante.
Como micro-operações são executadas fora de uma ordem, não são permitidos armazenamentos (stores) na
cache L1 até que todas as instruções anteriores à que causou o armazenamento tenham sido retiradas. A tarefa
da unidade de retirada é retirar instruções, em ordem, e monitorar onde elas estão. Se ocorrer uma interrupção,
as instruções que ainda não foram retiradas são abortadas, portanto, o Core i7 tem “interrupções precisas”, de
modo que, na ocorrência de uma interrupção, todas as instruções foram concluídas até um determinado ponto,
e nenhuma instrução após essa interrupção tem qualquer efeito.
Se uma instrução de armazenamento foi retirada, mas instruções anteriores ainda estiverem em curso, a
cache L1 não pode ser atualizada, portanto, os resultados são colocados em um buffer especial de armazenamento
pendente. Esse buffer tem 36 entradas, correspondentes aos 36 armazenamentos que podem estar em execução
ao mesmo tempo. Se uma carga subsequente tentar ler os dados armazenados, ela pode ser passada do buffer de
armazenamento pendente para a instrução, mesmo que ainda não esteja na cache de dados L1. Esse processo é
denominado repasse de armazenamento para carga. Embora tal mecanismo de encaminhamento possa parecer
simples, na prática é muito complicado de se realizar, pois os armazenamentos intervenientes podem ainda não
ter calculado seus endereços. Nesse caso, a microarquitetura pode não saber definitivamente qual armazenamento
no buffer produzirá o valor necessário. O processo de determinação de qual armazenamento oferece o valor para
uma carga é chamado de desambiguação.
A essa altura, deve estar claro que o Core i7 tem uma microarquitetura de alta complexidade cujo projeto foi
dirigido pela necessidade de executar o antigo conjunto de instruções Pentium em um núcleo RSC moderno, de
alto grau de pipelining. Ele cumpre esse objetivo desmembrando instruções Pentium em micro-operações, colo-
cando-as em cache e alimentando-as no pipeline quatro por vez para execução em um conjunto de ULAs capaz de
executar até seis micro-operações por ciclo em condições ideais. Micro-operações são executadas fora de ordem,
mas retiradas em ordem e os resultados são armazenados nas caches L1 e L2 em ordem.
4.6.2 A microarquitetura da CPU OMAP4430
No núcleo do sistema-em-um-chip OMAP4430 estão dois processadores ARM Cortex A9. O Cortex A9 é
uma microarquitetura de alto desempenho, que executa o conjunto de instruções ARM (versão 7). O processador
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 261
foi projetado pela ARM Ltd. e está incluído com pequenas variações em uma grande variedade de dispositivos
embutidos. A ARM não fabrica o processador, mas apenas fornece o projeto para os fabricantes de silício que
desejam incorporá-lo em seu projeto de sistema-em-um-chip (Texas nstruments, neste caso).
O processador Cortex A9 é uma máquina de 32 bits, com registradores de 32 bits e um caminho de dados de
32 bits. Assim como a arquitetura interna, o barramento de memória tem 32 bits de largura. Diferente do Core i7,
o Cortex A9 é uma arquitetura RSC verdadeira, o que significa que ela não precisa de um mecanismo complexo
para converter antigas instruções CSC em micro-operações para execução. Na verdade, as instruções do núcleo
já são instruções ARM do tipo das micro-operações. Contudo, nos últimos anos foram adicionadas instruções
gráficas e de multimídia, que requerem hardware especial para sua execução.
Visa
o geral da microarquitetura Cortex A9 do OMAP4430
O diagrama de blocos da microarquitetura Cortex A9 é dado na Figura 4.48. No todo, ele é muito mais
simples do que a microarquitetura Sandy Bridge do Core i7 porque tem uma arquitetura SA mais simples para
implementar. Ainda assim, alguns dos componentes básicos são semelhantes aos usados no Core i7. As seme-
lhanças são, em sua maioria, comandadas pela tecnologia, restrições de energia ou por razões econômicas. Por
exemplo, os dois projetos empregam uma hierarquia de cache multinível para atender as rigorosas restrições de
custo das aplicações embutidas típicas; porém, o último nível do sistema de memória cache do Cortex A9 (L2)
tem apenas 1 MB de tamanho, muito menor do que no Core i7, que admite caches de último nível (L3) de até 20
MB. As diferenças, ao contrário, se devem principalmente à diferença entre ter ou não ter de preencher a lacuna
entre um conjunto de instrução CSC antigo e um núcleo RSC moderno.
Figura 4.48 Diagrama de blocos da microarquitetura Cortex A9 da CPU OMAP4430.
À memória
LPDDR2
Cache de inst.
nível 1
Look-aside
de laço rápido
Previsor de
desvio/cache
de endereço
de destino
do desvio
Interface
do sistema
Controlador
de memória
Unidade de emissão de instrução/
decodicador/renomeador
Cache
unicada
nível 2
Fila de
instruções
Cache de
dados nível 1
ULAs FPUs
Unidade de load-store/
buffer de store
Retirada
Na parte superior da Figura 4.48 está a cache de instruções associativa de 4 vias e 32 KB, que usa linhas de
cache de 32 bytes. Já que a maioria das instruções ARM é de 4 bytes, há espaço para cerca de 8 K instruções
nessa cache, bem maior que a de micro-operações do Core i7.
A unidade de emissão de instrução prepara até quatro instruções para execução por ciclo de clock. Se hou-
ver uma ausência na cache L1, menos instruções serão emitidas. Quando é encontrado um desvio condicional,
um previsor de desvio com 4 K entradas é consultado para prever se busca a próxima instrução ou a que está
no endereço de destino. Se for previsto o caminho tomado, a cache de endereço de destino do desvio com 1 K
entrada é consultada em busca do endereço de destino previsto. Além disso, se o terminal frontal detectar que o
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
262
programa está executando um laço estreito (ou seja, um pequeno laço não aninhado), ele o carregará na cache
look-aside de laço rápido. Essa otimização acelera a busca de instruções e reduz o consumo de energia, pois as
caches e os previsores de desvio podem estar em um modo de baixo consumo de energia enquanto o laço estreito
está sendo executado.
A saída da unidade de missão de instrução flui para os decodificadores, que determinam quais recursos e
entradas são necessários pelas instruções. Assim como o Core i7, as instruções são renomeadas após a decodifi-
cação, para eliminar dependências WAR que podem atrasar a execução fora de ordem. Depois da renomeação, as
instruções são colocadas na fila de despacho de instruções, que as emitirá quando as entradas estiverem prontas
para as unidades funcionais, potencialmente fora de ordem.
A fila de despacho de instruções envia instruções para as unidades funcionais, como mostra a Figura 4.48. A
unidade de execução de inteiros contém duas ULAs, bem como um pequeno pipeline para instruções de desvio.
O arquivo de registradores físicos, que mantém registradores SA e alguns temporários, também estão contidos lá.
O pipeline do Cortex A9 opcionalmente pode conter um ou mais mecanismos de computação, que atuam como
unidades funcionais extras. O ARM admite um mecanismo para cálculo de ponto flutuante, chamado VFP, e um
mecanismo de cálculo de vetor SMD, chamado NEON.
A unidade de load/store manipula várias instruções de carga e armazenamento, e tem caminhos para a cache
de dados e o buffer de armazenamento. A cache de dados é uma tradicional cache de dados L1 associativa de
quatro vias e 32 KB que usa uma linha de 32 bytes de tamanho. O buffer de armazenamento mantém os armaze-
namentos que ainda não gravaram seu valor na cache de dados (na retirada). Uma carga que é executada tentará
primeiro buscar seu valor do buffer de armazenamento, usando o encaminhamento store-to-load, como o do Core
i7. Se o valor não estiver disponível no buffer de armazenamento, ele o buscará da cache de dados. Um resultado
possível de uma execução de carga é uma indicação, do buffer de armazenamento, que ele deve esperar, pois um
armazenamento anterior com um endereço desconhecido está bloqueando sua execução. No evento de ausência
de dados na cache de dados L1, o bloco de memória será buscado da cache unificada L2. Em certas circunstâncias,
o Cortex A9 também realiza a busca antecipada em hardware da cache L2 para a cache de dados L1, de modo a
melhorar o desempenho de cargas e armazenamentos.
O chip OMAP 4430 também contém lógica para controlar o acesso à memória. Essa lógica é subdividida
em duas partes: a interface de sistema e o controlador de memória. A interface de sistema faz a ligação com a
memória por um barramento LPDDR2 de 32 bits de largura. Todas as requisições de memória para o mundo
exterior passam por essa interface. O barramento LPDDR2 admite um endereço de 26 bits (palavra, não byte)
para 8 bancos por canal LPDDR2. O OMAP4430 tem dois deles, de modo que pode endereçar até 4 GB de
RAM externa.
O controlador de memória mapeia endereços virtuais de 32 bits para endereços físicos de 32 bits. O Cortex
A9 suporta memória virtual (discutida no Capítulo 6), com um tamanho de página de 4 KB. Para acelerar o
mapeamento, são fornecidas tabelas especiais denominadas LBs (ranslation Lookaside Buffers  buffers de
tradução lateral), para comparar o endereço virtual corrente que está sendo referenciado com os endereços
referenciados no passado recente. Duas dessas tabelas são fornecidas para o mapeamento de endereços de ins-
truções e dados.
Pipeline no Cortex A9 da CPU OMAP4430
O Cortex A9 tem um pipeline de 11 estágios, ilustrado em forma simplificada na Figura 4.49. Os 11 estágios
são designados por nomes de estágios curtos, mostrados no lado esquerdo da figura. amos agora examinar rapi-
damente cada um. O estágio Fe1 (Fetch #1) está no início do pipeline. É nele que o endereço da próxima instrução
a ser buscada é usado para indexar a cache de instruções e iniciar uma previsão de desvio. Em geral, esse endereço
é um a mais que o da instrução anterior. Porém, essa ordem sequencial pode ser quebrada por diversos motivos,
como quando uma instrução anterior é um desvio que foi previsto para ser tomado, ou quando uma interrupção
precisa ser atendida. Como a busca de instrução e previsão de desvio ocupam mais de um ciclo, o estágio Fe2
(Fetch #2) oferece tempo extra para executar essas operações. No estágio Fe3 (Fetch #3), as instruções buscadas
(até quatro) são colocadas na fila de instruções.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 263
Figura 4.49 Uma representac
a
o simplificada do pipeline do Cortex A9 da CPU OMAP4430.
Cache de
inst. nível 1
Look-aside
de laço rápido
Estágio
Fe1
Previsor
de desvio
Fila de
instruções
Fe2
Fe3
Decodicação
de instrução
Id1
Id2
Renomeação de instrução
Re
Iss
ULA 1
Fila de emissão de instrução
ULA 2 Unidade de load-store
Ex1
Cache de
dados nível 1
Cache
unicada
nível 2
FPU/
NEON
Multi-
plica-
ção
Ex2
Ex3
Retirada
…
WB
Unidade de
emissão de instrução
Os estágios De1 e De2 (Decodificação) decodificam as instruções. Essa etapa determina de quais entradas as
instruções precisarão (registradores e memória) e quais recursos elas exigirão para serem executadas (unidades
funcionais). Quando a decodificação estiver concluída, as instruções entram no estágio Re (Renomeação), onde
os registradores acessados são renomeados para eliminar dependências WAR e WAW durante a execução fora de
ordem. Esse estágio contém a tabela de renomeação que registra qual registrador físico mantém todos os regis-
tradores arquitetônicos. Usando essa tabela, qualquer registrador de entrada pode ser facilmente renomeado. O
registrador de saída deverá receber um novo registrador físico, que é retirado de um conjunto de registradores
físicos não usados. O registrador físico designado estará em uso pela instrução até que ela seja retirada.
Em seguida, as instruções entram no estágio Iss (nstruction ssue – emissão de instrução), em que elas
são lançadas para a fila de emissão de instrução. A fila de emissão observa instruções cujas entradas estão todas
prontas. Quando prontas, suas entradas de registrador são adquiridas (do arquivo de registrador físico ou do
barramento de contorno) e então a instrução é enviada aos estágios de execução. Assim como o Core i7, o Cortex
A9 potencialmente emite instruções fora da ordem do programa. Até quatro instruções podem ser emitidas a cada
ciclo. A escolha das instruções é restringida pelas unidades funcionais disponíveis.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
264
Os estágios Ex (Execução) são onde as instruções são de fato executadas. Quase todas as instruções aritméti-
cas, booleanas e de deslocamento utilizam as ULAs de inteiros e são concluídas em um ciclo. Cargas e armazena-
mentos utilizam dois ciclos (se estiverem presentes na cache L1), e multiplicações utilizam três ciclos. Os estágios
Ex contêm várias unidades funcionais, que são:
1. ULA 1 de inteiros.
2. ULA 2 de inteiros.
3. Unidade de multiplicação.
4. ULA de ponto flutuante e vetor de SMD (opcional com suporte a FP e NEON).
5. Unidade de carga e armazenamento (load/store).
nstruções de desvio condicional também são processadas no primeiro estágio Ex e sua direção (desvio/sem
desvio) é determinada. No caso de um erro de previsão, um sinal é enviado de volta ao estágio Fe1 e o pipeline
é anulado.
Depois de concluir sua execução, as instruções entram no estágio WB (WriteBack), onde cada uma atualiza
de imediato o arquivo de registrador físico. Depois, quando a instrução é a mais antiga em andamento, ela gravará
o resultado do seu registrador no arquivo arquitetônico de registradores. Se houver uma interrupção, são esses
valores, e não os dos registradores físicos, que se tornam visíveis. O ato de armazenar o registrador no arquivo
arquitetônico é equivalente à retirada no Core i7. Além disso, no estágio WB, quaisquer instruções de armazena-
mento agora completam a escrita de seus resultados na cache de dados L1.
Essa descrição do Cortex A9 está longe de ser completa, mas deve dar uma ideia razoável de como ele fun-
ciona e de quais são as diferenças entre sua microarquitetura e a do Core i7.
4.6.3 A microarquitetura do microcontrolador ATmega168
Nosso último exemplo de uma microarquitetura é a da Atmel ATmega168, mostrada na Figura 4.50. Essa
microarquitetura é bem mais simples do que as do Core i7 e do OMAP4430. A razão para essa simplicidade é
que o chip é muito pequeno e barato para atender ao mercado de projetos embutidos. Dessa forma, o objetivo
principal era fazer um chip barato, não rápido. Barato e simples são bons amigos; barato e rápido, não.
O coração do ATmega168 é o barramento principal de 8 bits. Ligado a ele estão vários registradores e bits de
estado, ULA, memória e dispositivos de E/S. amos descrevê-los brevemente agora. O arquivo de registradores
contém 32 registradores de 8 bits, que são usados para armazenar valores temporários do programa. O registrador
de estado e controle mantém os códigos de condição da última operação da ULA (ou seja, sinal, excesso, negati-
vo, zero e vai-um), mais um bit que indica se uma interrupção está pendente. O contador de programa mantém
o endereço da instrução em execução. Para realizar uma operação na ULA, primeiro os operandos são lidos do
registrador e enviados à ULA. A saída da ULA pode ser escrita em qualquer um dos registradores passíveis de
escrita por meio do barramento principal.
O ATmega168 tem diversas memórias para dados e instruções. A SRAM de dados tem 1 KB, muito grande
para ser totalmente endereçada com um endereço de 8 bits no barramento principal. Assim, a arquitetura AR
permite que os endereços sejam construídos com um par sequencial de registradores de 8 bits, produzindo assim
um endereço de 16 bits que admite até 64 KB de memória de dados. A EEPROM oferece até 1 KB de armazena-
mento não volátil, onde os programas podem escrever variáveis que precisam sobreviver a uma falta de energia.
Existe um mecanismo semelhante para endereçar a memória do programa, mas 64 KB de código é muito
pouco, até mesmo para sistemas embutidos, de baixo custo. Para permitir que mais memória de instruções seja
endereçada, a arquitetura AR define três registradores de página de RAM (RAMP, RAMPY e RAMPZ), cada
um com 8 bits de largura. O registrador de página de RAM é concatenado com um par de registradores de 16 bits
para produzir um endereço de programa de 24 bits, permitindo assim 16 MB de espaço de endereço de instruções.
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 265
Figura 4.50 Microarquitetura do ATmega168.
Barramento principal de 8 bits
Estado e
controle
Registradores
de uso geral
32 × 8
ULA
SRAM
de dados
EEPROM
Módulo
de E/S 1
Módulo
de E/S 2
Módulo
de E/S 3
Comparador
analógico
Temporizador
watchdog
Unidade
de SPI
Unidade de
interrupção
Contador
de programa
Memória de
programa
ash
Registrador
de instrução
Decodicador
de instrução
Linhas de controle
Endereçamento
direto
Endereçamento
indireto
Para e pense nisso por um instante. 64 KB de código é muito pouco para um microcontrolador que poderia
controlar um brinquedo ou um pequeno aparelho. Em 1964, a BM lançou o System 360 Model 30, que tinha
64 KB de memória total (sem truques para aumentá-la). Ele era vendido por US$ 250 mil, que é cerca de US$
2 milhões em dólares de hoje. O ATmega168 custa cerca de US$ 1, ou menos se você comprar em quantidade.
Se você verificar, digamos, o custo de venda de um Boeing, verá que os preços de aeronaves não caíram por um
fator de 250.000 nos últimos 50 anos ou mais. E nem os valores de carros ou televisores, ou qualquer outra coisa,
exceto computadores.
Além disso, o ATmega168 tem um controlador de interrupção no chip, interface de porta serial (SP) e tem-
porizadores, que são essenciais para aplicações de tempo real. Há também três portas de E/S digitais de 8 bits,
que lhe permitem controlar até 24 botões externos, luzes, sensores, acionadores e assim por diante. É a presença
dos temporizadores e portas de E/S, mais do que qualquer outra coisa, que possibilita o uso do ATmega168 para
aplicações embutidas sem quaisquer chips adicionais.
O ATmega168 é um processador síncrono, com a maior parte das instruções usando apenas um ciclo de
clock, embora algumas usem mais. O processador é paralelo, de modo que, enquanto uma instrução está sendo
buscada, a anterior está sendo executada. Entretanto, o pipeline tem apenas dois estágios, busca e execução. Para
executar instruções em um ciclo, o ciclo de clock deve acomodar a leitura do registrador do arquivo de regis-
tradores, seguida pela execução da instrução na ULA, seguida pela escrita do registrador de volta ao arquivo de
registradores. Como todas essas operações ocorrem em um ciclo de clock, não é preciso de lógica de contorno
(bypass) ou detecção de protelação (stall). As instruções do programa são executadas em ordem, em um ciclo, e
sem sobreposição com outras instruções.
Embora pudéssemos entrar em mais detalhes sobre o ATmega168, a descrição que demos e a Figura 4.50
oferecem uma ideia básica. O ATmega168 tem um único barramento principal (para reduzir a área do chip),
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
266
um conjunto heterogêneo de registradores e uma série de memórias e dispositivos de E/S pendurados no bar-
ramento principal. A cada ciclo do caminho de dados, dois operandos são lidos do arquivo de registradores e
passam pela ULA, com os resultados enviados de volta a um registrador, assim como nos computadores mais
modernos.
4.7 Comparac
a
o entre i7, OMAP4430 e ATmega168
Nossos três exemplos são muito diferentes, porém, ainda assim exibem certa dose de características em
comum. O Core i7 tem um conjunto de instruções CSC antigo que os engenheiros da ntel adorariam jogar na
Baía de São Francisco, caso isso não violasse as leis antipoluição das águas da Califórnia. O OMAP4430 é um
projeto RSC puro, com um conjunto de instruções enxuto e esperto. O ATmega168 é um processador simples de
8 bits para aplicações embutidas. Ainda assim, o coração de cada um deles é um conjunto de registradores e uma
ou mais ULAs que efetuam operações aritméticas e booleanas simples em operandos de registradores.
A despeito de suas óbvias diferenças externas, o Core i7 e o OMAP4430 têm unidades de execução bastante
semelhantes. Ambas as unidades de execução aceitam micro-operações que contêm um opcode, dois registradores
de origem e um registrador de destino. Ambos podem executar uma micro-operação em um ciclo. Ambos têm alto
grau de pipelining, previsão de desvio e caches de instruções () e de dados (D) divididas.
Essa semelhança interna não é um acidente ou nem mesmo causada pela eterna rotatividade de empregos
dos engenheiros do ale do Silício. Como vimos em nossos exemplos de Mic-3 e Mic-4, é fácil e natural construir
um caminho de dados com pipeline que pega dois registradores de origem, passa-os por uma ULA e armazena os
resultados em um registrador. A Figura 4.34 mostra esse pipeline graficamente. Com a tecnologia atual, esse é o
projeto mais eficaz.
A principal diferença entre as CPUs Core i7 e OMAP4430 é o modo como elas vão de seu conjunto de
instrução SA até a unidade de execução. O Core i7 tem de fragmentar suas instruções CSC para colocá-las no
formato de três registradores de que a unidade de execução necessita. É isso que faz o terminal frontal na Figura
4.47 – desmembra instruções grandes em micro-operações caprichadas e jeitosas. O OMAP4430 não tem de fazer
nada porque suas instruções nativas já são micro-operações caprichadas e jeitosas. É por isso que grande parte
das novas SAs são do tipo RSC – para oferecer melhor compatibilidade entre o conjunto de instruções SA e o
mecanismo interno de execução.
É instrutivo comparar nosso projeto final, a Mic-4, com esses dois exemplos do mundo real. A Mic-4 é muito
parecida com o Core i7. A tarefa de ambos é interpretar um conjunto de instrução SA que não é RSC. Ambos
fazem isso desmembrando as instruções SA em micro-operações com um opcode, dois registradores de origem e
um de destino. Em ambos os casos, as micro-operações são depositadas em uma fila para execução mais tarde. A
política estrita do projeto da Mic-4 prevê emissão, execução, retirada em ordem, ao passo que o Core i7 tem uma
política de emissão em ordem, execução fora de ordem, retirada em ordem.
Na realidade, Mic-4 e OMAP4430 não podem ser comparados, porque o conjunto de instruções SA do
OMAP4430 é composto de instruções RSC (isto é, micro-operações de três registradores). Essas instruções não têm
de ser desmembradas e podem ser executadas como se apresentam, cada uma em um único ciclo de caminho de dados.
Em comparação com Core i7 e OMAP4430, o ATmega168 é realmente uma máquina simples. Tende mais
para RSC do que para CSC porque grande parte de suas instruções simples pode ser executada em um ciclo de
clock e não precisa ser desmembrada. Ele não tem pipelining, nem cache, e tem emissão, execução e retirada em
ordem. Em sua simplicidade, é muito mais semelhante à Mic-1.
4.8 Resumo
O coração de todo computador é o caminho de dados. Ele contém alguns registradores, um, dois ou três bar-
ramentos e uma ou mais unidades funcionais, como ULAs e deslocadores. O laço de execução principal consiste
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 267
em buscar alguns operandos em registradores e enviá-los pelos barramentos à ULA e a outras unidades funcionais
para execução. Então, os resultados são armazenados de volta nos registradores.
O caminho de dados pode ser controlado por um sequenciador que busca microinstruções em um armazena-
mento de controle. Cada microinstrução contém bits que controlam o caminho de dados por um ciclo. Esses bits
especificam quais operandos selecionar, qual operação executar e o que fazer com os resultados. Além disso, cada
microinstrução especifica sua sucessora, em geral explicitamente por conter seu endereço. Algumas microinstru-
ções modificam esse endereço de base efetuando operações OR com bits no endereço antes de usá-lo.
A máquina JM é uma máquina de pilha com opcodes de 1 byte que passam palavras para a pilha, retiram-
-nas da pilha e combinam palavras (por exemplo, somando-as) na pilha. Uma execução microprogramada foi
dada à microarquitetura Mic-1. Adicionando uma unidade de busca de instrução para carregar os bytes antecipa-
damente no fluxo de instruções, foi possível eliminar muitas referências ao contador de programa e a máquina
ficou muito mais veloz.
Há muitas maneiras de projetar o nível de microarquitetura. Existem muitos compromissos, incluindo proje-
tos com dois barramentos e três barramentos, campos de microinstrução codificados e não codificados, presença
ou ausência de busca antecipada, alto grau ou baixo grau de pipelining e muito mais. A Mic-1 é uma máquina
simples, controlada por software, com execução sequencial e nenhum paralelismo. Por comparação, a Mic-4 é
uma microarquitetura de alto grau de paralelismo com sete estágios de pipeline.
O desempenho pode ser melhorado de várias maneiras, sendo que a memória cache é uma das principais.
Caches de mapeamento direto e caches associativas de conjunto costumam ser usadas para acelerar referências à
memória. Previsão de desvio – estática e dinâmica – é importante, assim como execução fora de ordem e execução
especulativa.
Nossas três máquinas de exemplo – Core i7, OMAP4430 e ATmega168 – têm, todas, microarquiteturas que
não são visíveis aos programadores de linguagem de montagem SA. O Core i7 tem um esquema complexo para
converter instruções SA em micro-operações, colocá-las em cache e alimentá-las em um núcleo RSC superescalar
para execução fora de ordem, renomeação de registradores e todos os truques do repertório para extrair a última
gota possível de velocidade do hardware. O OMAP4430 tem alto grau de pipelining, porém, no mais, é relativamente
simples, com emissão em ordem, execução em ordem e retirada em ordem. O ATmega168 é muito simples, com um
único barramento principal direto, ao qual estão ligados um punhado de registradores e uma ULA.
Problemas
1. Quais são as quatro etapas que as CPUs utilizam para
executar instruções?
2. Na Figura 4.6, o registrador do barramento B está
codificado em um campo de 4 bits, mas o barramento
C é representado com um mapa de bits. Por quê?
3. Na Figura 4.6, há um retângulo denominado “bit
alto”. Apresente um diagrama de circuito para ele.
4. Quando o campo JMPC em uma microinstrução
é desabilitado, é efetuada uma operação OR entre
MBR e NEXT_ADDRESS para formar o endereço da
próxima microinstrução. Há alguma circunstância na
qual faz sentido que NEXT_ADDRESS seja 0x1FF e
use JMPC?
5. Suponha que no exemplo da Figura 4.14(a) a decla-
ração
k = 5;
é adicionada após a declaração if. Qual seria o novo
código de montagem? Considere que o compilador é
um compilador otimizador.
6. Dê duas traduções JM diferentes para a seguinte
declaração Java:
i = k + n + 5;
7. Dê a declaração Java que produziu o seguinte código
JM:
ILOAD j
ILOAD n
ISUB
BIPUSH 7
ISUB
DUP
IADD
ISTORE i
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
268
8. No texto, mencionamos que, quando traduzimos a
declaração
if (Z) goto L1; else goto L2
para binário, L2 tem de estar nas últimas 256 pala-
vras do armazenamento de controle. Não seria igual-
mente possível que L1 estivesse em, por exemplo,
0x40 e L2, em 0x140? Explique sua resposta.
9. No microprograma para Mic-1, em if_icmpeq3, MDR
é copiado para H. Algumas linhas mais adiante ele é
subtraído de TOS para verificar a igualdade. Com
certeza seria melhor ter aqui uma declaração:
if_icmpeq3 Z = TOS − MDR; rd
Por que isso não é feito?
10. Quanto tempo leva uma Mic-1 de 2,5 GHz para exe-
cutar a seguinte declaração Java:
i = j + k;
Dê sua resposta em nanossegundos.
11. Repita a pergunta anterior, agora para uma Mic-2
de 2,5 GHz. Com base nesse cálculo, quanto tempo
um programa que executa durante 100 s na Mic-1
demoraria na Mic-2?
12. Escreva um microcódigo para a Mic-1 a fim de
executar a instrução JM POPTWO. Essa instrução
retira duas palavras do topo da pilha.
13. Na máquina JM completa, há opcodes especiais de
1 byte para armazenar de 0 até 3 locais na pilha em
vez de usar a instrução geral ILOAD. Como a JM
deve ser modificada para fazer o melhor uso dessas
instruções?
14. A instrução ISHR (deslocamento aritmético de intei-
ro para a direita) existe em JM, mas não em JM.
Ela usa os dois valores do topo da pilha, substituin-
do-os por um valor único, o resultado. A segunda
palavra a partir do topo de uma pilha é o operando a
ser deslocado. Seu conteúdo é deslocado para a direi-
ta por um valor entre 0 e 31, inclusive, dependendo
do valor dos 5 bits menos significativos da palavra que
está no topo da pilha (os outros 27 da palavra do
topo são ignorados). O bit de sinal é duplicado para
a direita por tantos bits quanto for o inteiro de deslo-
camento. O opcode para ISHR é 122 (0x7A).
a. Qual é a operação aritmética equivalente ao deslo-
camento para a esquerda por uma contagem de 2?
b. Estenda o microcódigo para incluir essa instrução
como uma parte da JM.
15. A instrução ISHL (deslocamento de inteiro para a
esquerda) existe em JM, mas não em JM. Ela usa os
dois valores do topo da pilha, substituindo-os por um
valor único, o resultado. A segunda palavra a partir do
topo da pilha é o operando a ser deslocado. Seu conteúdo
é deslocado para a esquerda por um valor entre 0 e 31,
inclusive, dependendo do valor dos 5 bits menos signifi-
cativos da palavra que está no topo da pilha (os outros 27
da palavra do topo são ignorados). Zeros são deslocados
para a direita por tantos bits quanto for o inteiro de des-
locamento. O opcode para ISHL é 120 (0x78).
a. Qual é a operação aritmética equivalente ao deslo-
camento para a esquerda por uma contagem de 2?
b. Estenda o microcódigo para incluir essa instrução
como uma parte da JM.
16. A instrução JM INVOKEVIRTUAL precisa saber
quantos parâmetros ela tem. Por quê?
17. Execute a instrução JVM DLOAD para a Mic-2. Ela
tem um índice de 1 byte e passa a variável local que
está nessa posição para a pilha. Então, ela também
passa para a pilha a próxima palavra mais alta.
18. Desenhe uma máquina de estado finito para a conta-
gem de pontos no jogo de tênis. As regras do tênis são
as seguintes. Para ganhar, você precisa de um mínimo
de quatro pontos e deve ter no mínimo dois pontos a
mais do que seu adversário. Comece com um estado
(0, 0) que indica que nenhum ponto foi marcado
ainda. Depois, adicione um estado (1, 0), que signi-
fica que A marcou um ponto. Denomine A o arco de
(0, 0) a (1, 0). Agora, adicione um estado (0, 1) que
indica que B marcou um ponto e denomine B o arco
de (0, 0). Continue adicionando estados e arcos até
que todos os estados possíveis tenham sido incluídos.
19. Reconsidere o problema anterior. Há quaisquer esta-
dos que poderiam ser agrupados sem mudar o resul-
tado de qualquer jogo? Caso a resposta seja positiva,
quais são equivalentes?
20. Desenhe uma máquina de estado finito para previsão
de desvio que seja mais persistente do que a Figura
4.42. Ela deve alterar previsões somente após três
previsões erradas consecutivas.
21. O registrador de deslocamento da Figura 4.27 tem
uma capacidade máxima de 6 bytes. Uma versão mais
barata da FU poderia ser construída com um regis-
trador de deslocamento de 5 bytes? E de 4 bytes?
22. Agora que já estudamos FUs mais baratas na per-
gunta anterior, vamos examinar FUs mais caras.
Haveria alguma razão para termos nas FUs mais
caras um registrador de deslocamento muito maior,
por exemplo, de 12 bytes? Justifique sua resposta.
23. No microprograma para a Mic-2, o código para
if_icmpeq6 vai para T quando Z é ajustado para 1.
Contudo, o código em T é o mesmo que goto1. Seria
possível ir para goto1 diretamente? Fazer isso deixa-
ria a máquina mais rápida?
24. Na Mic-4, a unidade de decodificação mapeia o opco-
de JM para o índice da ROM onde as micro-ope-
rações correspondentes estão armazenadas. Parece
C a p 
t u l o 4 O n 
v e l d e m i c r o a r q u i t e t u r a 269
mais simples apenas omitir o estágio de decodifica-
ção e alimentar o opcode JM diretamente no enfi-
leiramento. Ela poderia usar o opcode JM como um
índice para a ROM, do mesmo modo que faz a Mic-1.
O que está errado nesse plano?
25. Por que os computadores são equipados com vários
níveis de cache? Não seria melhor apenas ter uma
grande cache?
26. Um computador tem uma cache de dois níveis.
Suponha que 60% das referências à memória obtêm
presença na cache de primeiro nível, 35% na de
segundo nível, e 5% encontram ausência da cache.
Os tempos de acesso são 5 ns, 15 ns e 60 ns, respec-
tivamente, e os tempos para a cache de nível 2 e para
a memória começam a ser contados no momento em
que elas sabem que são necessários (por exemplo,
o acesso à cache de nível 2 nem mesmo inicia até
ocorrer uma ausência da de nível 1). Qual é o tempo
médio de acesso?
27. No final da Seção 4.5.1, dissemos que uma alocação de
escrita vence somente se houver possibilidade de várias
escritas sequenciais para a mesma linha de cache. E o
caso de uma escrita seguida por várias leituras – tam-
bém não seria um grande vencedor?
28. No primeiro rascunho deste livro, a Figura 4.39
mostrava uma cache associativa de três vias em
vez de uma de quatro vias. Um dos revisores teve
um ataque de nervos dizendo que isso provocaria
uma terrível confusão para os estudantes porque 3
não é uma potência de 2 e os computadores fazem
tudo em binário. Uma vez que o cliente sempre tem
razão, a figura foi alterada para uma cache associa-
tiva de quatro vias. O revisor tinha razão? Discuta
sua resposta.
29. Muitos arquitetos de computador gastam muito tempo
tornando seu pipeline mais profundo. Por quê?
30. Um computador com pipeline de cinco estágios trata
dos desvios condicionais protelando durante os três
ciclos seguintes após chegar a um desses desvios.
Qual seria o prejuízo causado por essa protelação se
20% de todas as instruções forem desvios condicio-
nais? gnore todas as fontes de protelação, exceto os
desvios condicionais.
31. Suponha que um computador faz busca antecipada
de até 20 instruções. Todavia, na média, quatro delas
são desvios condicionais, cada um com probabilidade
de 90% de previsão correta. Qual é a probabilidade de
a busca antecipada estar no caminho certo?
32. Suponha que temos de alterar o projeto da máquina
usada na Figura 4.43 para ter 16 registradores em vez
de 8. Então, trocamos 6 para usar R8 como seu des-
tino. O que acontece nos ciclos a partir do ciclo 6?
33. Dependências em geral causam problemas em CPUs
com pipeline. Há alguma otimização que possa ser
feita com dependências WAW que poderia realmente
melhorar a situação? Qual?
34. Reescreva o interpretador Mic-1 mas agora com LV
apontando para a primeira variável local em vez de
para o ponteiro de ligação.
35. Escreva um simulador para uma cache de mapeamen-
to direto de uma via. Considere o número de entradas
e o tamanho da linha como parâmetros da simulação.
Faça alguns experimentos e escreva um relatório sobre
o que constatou.
E
ste capítulo discute em detalhes o nível da arquitetura do conjunto de instrução (SA – nstruction Set
Architecture). Esse nível está posicionado entre o da microarquitetura e o do sistema operacional, como
vimos na Figura 1.2. Historicamente, ele foi desenvolvido antes de quaisquer outros níveis e, na verdade,
na origem era o único. Até hoje, não é raro ouvir esse nível ser chamado de “a arquitetura” de uma máquina ou,
às vezes (incorretamente), como a “linguagem de montagem”.
O nível SA tem um significado especial que o torna importante para arquitetos de sistemas: é a interface
entre o software e o hardware. Embora seja possível o hardware executar diretamente programas escritos em C,
C++, Java ou alguma outra linguagem de alto nível, isso não seria uma boa ideia. A vantagem em desempenho
da compilação em relação à interpretação seria perdida. Além do mais, para ter muita utilidade prática, a maioria
dos computadores deve ser capaz de executar programas escritos em várias linguagens, e não apenas em uma.
A abordagem de base adotada por todos os projetistas de sistemas é traduzir programas escritos em várias lingua-
gens de alto nível para uma forma intermediária comum – nível SA – e construir hardware que possa executar pro-
gramas diretamente no nível SA. O nível SA define a interface entre os compiladores e o hardware. É a linguagem
que ambos têm de entender. A relação entre os compiladores, o nível SA e o hardware pode ser vista na Figura 5.1.
O ideal é que, ao projetar uma nova máquina, os arquitetos conversem com os escritores de compiladores e
também com os engenheiros de hardware para descobrir quais características cada um deles quer no nível SA. Se os
escritores de compiladores quiserem alguma característica que os engenheiros não podem realizar de modo eficiente
em custo (por exemplo, uma instrução desvie-e-processe-folha-de-pagamento), ela não entra no hardware. Da mesma
forma, se a turma do hardware tiver alguma nova característica elegante que quer acrescentar (por exemplo, uma
memória na qual as palavras cujos endereços são números primos sejam super-rápidas), mas a turma do software não
consegue imaginar como gerar código para usá-la, ela não passará da prancheta. Após muita negociação e simulação,
surgirá uma SA perfeitamente otimizada para as linguagens de programação pretendidas, que será implementada.
O n
vel de arquitetura do conjunto
de instruc
a
o
5
Cap
tulo
C a p 
t u l o 5 O n 
v e l d e a r q u i t e t u r a d o c o n j u n t o d e i n s t r u c
 a
 o 271
Figura 5.1 O n
vel ISA e
 a interface entre os compiladores e o hardware.
Software
Hardware
Hardware
Programa em C
Nível ISA
Programa ISA executado
pelo microprograma ou hardware
programa em
FORTRAN
Programa em
FORTRAN compilado
para programa ISA
Programa em C
compilado para
programa ISA
sso é a teoria. Agora, vamos à triste realidade. Quando surge uma nova máquina, a primeira pergunta que
todos os clientes potenciais fazem é: “Ela é compatível com sua antecessora?”. A segunda é: “Ela pode executar meu
sistema operacional antigo?”. A terceira é: “Ela executará todos os meus programas de aplicação existentes sem
modificação?”. Se qualquer uma das respostas a essas perguntas for “não”, os projetistas terão muitas explicações
a dar. É raro que os clientes se disponham a jogar fora todos os seus programas antigos e começar tudo de novo.
Essa atitude pressiona muito os arquitetos de computadores a manter a mesma SA entre modelos, ou ao
menos torná-la compatível com os modelos anteriores. Com isso, queremos dizer que a nova máquina deve ser
capaz de executar programas antigos sem alteração. Contudo, é totalmente aceitável que a nova máquina tenha
novas instruções e outras características que só possam ser exploradas por novo software. Em termos da Figura
5.1, contanto que os projetistas garantam que a SA seja compatível com os modelos anteriores, eles têm toda
a liberdade para fazer o que quiserem com o hardware porque, na verdade, quase ninguém se importa muito com
o hardware real (ou nem mesmo sabe o que ele faz). Eles podem passar de um projeto microprogramado para exe-
cução direta, ou adicionar paralelismo ou facilidades superescalares ou qualquer outra coisa que queiram, contanto
que mantenham a compatibilidade com a SA anterior. A meta é garantir que velhos programas sejam executados
na nova máquina. Então, o desafio se torna construir máquinas melhores sujeitas às restrições de compatibilidade.
O que acabamos de dizer não tem a intenção de dar a entender que o projeto da SA não importa. Uma boa
SA tem vantagens significativas em relação a uma ruim, em particular quando se trata de comparar capacidade
computacional bruta com custo. Se quanto ao mais os projetos forem equivalentes, as SAs podem ser responsáveis
por uma diferença de até 25% em desempenho. O que queremos deixar claro é que as forças do mercado dificultam
(mas não impossibilitam) descartar uma SA antiga e introduzir uma nova. Não obstante, de vez em quando surge
uma nova SA de uso geral e, em mercados especializados (por exemplo, sistemas embutidos ou processadores
multimídia), elas ocorrem com muito mais frequência. Por conseguinte, é importante entender o projeto da SA.
O que faz uma SA ser boa? Há dois fatores primordiais. Primeiro, ela deve definir um conjunto de instruções
que pode ser executado com eficiência em tecnologias atuais e futuras, resultando em projetos efetivos em custo
por várias gerações. Um mau projeto é mais difícil de realizar e pode exigir um número muito maior de portas
para implementar um processador e mais memória para executar programas. Além disso, a execução pode ser
mais lenta porque a SA encobre oportunidades de sobrepor operações, exigindo projetos muito mais sofisticados
para obter desempenho equivalente. Um projeto que aproveita as peculiaridades de determinada tecnologia pode
ter um êxito fugaz e produzir uma única geração de implementações com custo eficaz e então ser ultrapassado
por SAs mais avançadas.
Segundo, uma boa SA deve fornecer um alvo claro para o código compilado. Regularidade e completude de
uma faixa de opções são aspectos importantes que nem sempre estão presentes em uma SA. Essas propriedades
são importantes para um compilador, que pode ter problemas para escolher a melhor opção entre alternativas
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
272
limitadas, em particular quando algumas alternativas que parecem óbvias não são permitidas pela SA. Em resu-
mo, uma vez que a SA é a interface entre hardware e software, ela tem de contentar os projetistas de hardware
(fácil de implementar com eficiência) e satisfazer os projetistas de software (fácil de gerar bom código para ela).
5.1 Visa
o geral do n
vel ISA
amos começar nosso estudo do nível SA perguntando o que ele é. Essa pergunta pode parecer simples, mas
é mais complicada do que poderíamos imaginar à primeira vista. Na seção seguinte, abordaremos algumas dessas
questões. Em seguida, vamos examinar modelos de memória, registradores e instruções.
5.1.1 Propriedades do n
vel ISA
Em princípio, o nível SA é definido pelo modo como a máquina se apresenta a um programador de lingua-
gem de máquina. Já que mais ninguém (normal) faz muita programação em linguagem de máquina, vamos rede-
finir isso dizendo que código de nível SA é o que um compilador produz (ignorando, por enquanto, chamadas
ao sistema operacional e a linguagem de montagem simbólica). Para produzir código de nível SA, o escritor de
compilador tem de saber qual é o modelo de memória, quais e quantos são os registradores, quais tipos de dados
e instruções estão disponíveis, e assim por diante. O conjunto de todas essas informações define o nível SA.
De acordo com essa definição, questões como se a microarquitetura é microprogramada ou não, se ela tem
paralelismo ou não, se ela é superescalar ou não, e assim por diante, não fazem parte do nível SA, porque não
são visíveis para o escritor de compilador. Todavia, essa observação não é de todo verdadeira, porque algumas
dessas propriedades afetam o desempenho e isso é visível para o escritor do compilador. Considere, por exem-
plo, um projeto superescalar que pode emitir instruções uma atrás da outra no mesmo ciclo, contanto que uma
seja uma instrução de número inteiro e outra de ponto flutuante. Se o compilador alternar instruções de número
inteiro e instruções de número de ponto flutuante, obterá desempenho visivelmente melhor do que se não fizer
isso. Assim, os detalhes da operação superescalar são visíveis no nível SA, portanto, a separação entre as cama-
das não é tão clara como poderia parecer de início.
Para algumas arquiteturas, o nível SA é especificado por um documento formal de definição, muitas vezes pro-
duzido por um consórcio do setor. Para outras, não. Por exemplo, a ARM v7 (SA ARM versão 7) tem uma definição
oficial publicada pela ARM Ltd. A finalidade de um documento de definição é possibilitar que diferentes realizadores
construam a máquina e todas elas executem exatamente o mesmo software e obtenham resultados idênticos.
No caso da SA ARM, a ideia é permitir que vários fabricantes de chips produzam chips ARM idênticos em
termos funcionais, e diferentes apenas em desempenho e preço. Para essa ideia dar certo, os fabricantes têm de
saber o que um chip ARM deve fazer (no nível SA). Por conseguinte, o documento de definição informa qual é
o modelo da memória, quais registradores estão presentes, o que as instruções fazem e assim por diante, mas não
qual é o aspecto da microarquitetura.
Esses documentos de definição contêm seções normativas, que impõem requisitos, e seções informativas,
cuja intenção é ajudar o leitor, mas não fazem parte da definição formal. As seções normativas usam com fre-
quência palavras como deve, não pode e deveria para requerer, proibir e sugerir aspectos da arquitetura, respecti-
vamente. Por exemplo, uma sentença como
Executar um opcode reservado deverá causar uma exceção.
informa que, se um programa executar um opcode que não é definido, ele deve causar uma exceção e não pode
ser apenas ignorado. Uma técnica alternativa poderia ser deixar essa questão em aberto, quando então a sentença
poderia ser
O efeito da execução de um opcode reservado é definido pela implementação.
sso significa que o escritor do compilador não pode contar com qualquer comportamento particular, o que dá a dife-
rentes implementadores a liberdade de opções diferentes. A maioria das especificações de arquitetura é acompanhada
de conjuntos de testes para verificar se uma execução que se afirma compatível com a especificação realmente o é.
C a p 
t u l o 5 O n 
v e l d e a r q u i t e t u r a d o c o n j u n t o d e i n s t r u c
 a
 o 273
O motivo por que a ARM v7 tem um documento que define seu nível SA é claro: todos os chips ARM exe-
cutarão o mesmo software. Por muitos anos, não houve um documento de definição formal para a SA A-32 (às
vezes, denominada SA x86), pois a ntel não queria abrir a guarda para que outros fabricantes produzissem chips
compatíveis com a ntel. Na verdade, a ntel já apelou para a justiça para tentar impedir que outros fabricantes
clonassem seus chips, mas perdeu a causa. Porém, no final da década de 1990, a empresa lançou uma especi-
ficação completa do conjunto de instruções A-32. Talvez isso tenha acontecido porque eles sentiram o erro e
quiseram ajudar os companheiros arquitetos e programadores, ou talvez porque os Estados Unidos, o Japão e a
Europa estivessem investigando a ntel por suposta violação das leis antitruste. Essa SA bem documentada ainda
está sendo atualizada no site para desenvolvedores (http://developer.intel.com). A versão lançada com o Core i7
da ntel possui 4.161 páginas, o que nos faz lembrar novamente que o Core i7 é um computador com conjunto
complexo de instruções.
Outra propriedade importante do nível SA é que, na maioria das máquinas, há no mínimo dois modos.
O modo núcleo (kernel) deve executar o sistema operacional e permite que todas as instruções sejam exe-
cutadas. O modo usuário (user) deve executar programas de aplicação e não permite que certas instruções
sensíveis (como as que manipulam a cache diretamente) sejam executadas. Neste capítulo, focalizaremos
principalmente instruções e propriedades do modo usuário.
5.1.2 Modelos de memo
ria
Todos os computadores dividem a memória em células que têm endereços consecutivos. O tamanho de célula
mais comum no momento é 8 bits, mas células de 1 bit a 60 bits já foram usadas no passado (veja a Figura 2.10).
Uma célula de 8 bits é denominada byte (ou octeto). A razão para usar bytes de 8 bits é que os caracteres ASC
têm 7 bits, de modo que um caractere ASC (mais um bit de paridade muito pouco utilizado) se encaixa em um
byte. Outros códigos, como Unicode e UTF-8, utilizam múltiplos de 8 bits para representar caracteres.
Em geral, os bytes são agrupados em palavras de 4 bytes (32 bits) ou 8 bytes (64 bits) com instruções
disponíveis para manipular palavras inteiras. Muitas arquiteturas precisam que as palavras sejam alinhadas em
seus limites naturais; assim, por exemplo, uma palavra de 4 bytes pode começar no endereço 0, 4, 8 etc., mas
não no endereço 1 ou 2. De modo semelhante, uma palavra de 8 bytes pode começar no endereço 0, 8 ou 16,
mas não no endereço 4 ou 6. O alinhamento de palavras de 8 bytes é ilustrado na Figura 5.2.
Figura 5.2 Palavra de 8 bytes em uma memo
ria little-endian. (a) Alinhada. (b) Na
o alinhada. Algumas ma
quinas requerem que palavras
na memo
ria sejam alinhadas.
24
Endereço
Palavra de 8 bytes
alinhada no endereço 8
16
8
15 14 13 12 11
(a)
10 9 8
0
8 bytes
24
Endereço
Palavra de 8 bytes
não alinhada no endereço 12
16
8
15 14 13 12
19
(b)
18 17 16
0
8 bytes
O alinhamento costuma ser exigido porque memórias funcionam com mais eficiência desse modo. O Core
i7, por exemplo, que busca 8 bytes por vez na memória, usa uma interface DDR3, que admite apenas acessos ali-
nhados em 64 bits. Assim, o Core i7 não poderia fazer uma referência desalinhada à memória nem que quisesse,
porque a interface de memória exige endereços que sejam múltiplos de 8.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
274
Contudo, esse requisito de alinhamento às vezes causa problemas. O Core i7 permite que programas SA
referenciem palavras que começam em qualquer endereço, uma propriedade que remonta ao 8088, que tinha um
barramento de dados de 1 byte de largura (e, assim, nenhum requisito de alinhamento de referências à memória
em limites de 8 bytes). Se um programa Core i7 ler uma palavra de 4 bytes no endereço 7, o hardware tem de
fazer uma referência à memória para obter os bytes de 0 a 7 e uma segunda referência à memória para obter os
bytes de 8 a 15. Então, a CPU tem de extrair os 4 bytes requisitados dos 16 bytes lidos da memória e montá-los na
ordem correta para formar uma palavra de 4 bytes. Fazer isso regularmente não leva a uma velocidade fantástica.
Ter a capacidade de ler palavras em endereços arbitrários requer lógica extra no chip, o que o torna maior
e mais caro. Os engenheiros projetistas adorariam livrar-se dela e apenas exigir que todos os programas fizessem
referências à memória alinhadas por palavra. O problema é que, sempre que os engenheiros dizem “E quem se
importa com executar programas 8088 antigos e bolorentos que referenciam a memória de modo errado?”, o
pessoal de marketing tem uma resposta curta e rápida: “Nossos clientes”.
A maioria das máquinas tem um único espaço de endereço linear no nível SA, que se estende do endereço 0 até
algum máximo, geralmente 232
– 1 bytes ou 264
– 1 bytes. Contudo, algumas têm espaços de endereços separados
para instruções e dados, de modo que uma busca de instrução no endereço 8 vai para um espaço de endereço
diferente de uma busca de dados no endereço 8. Esse esquema é mais complexo do que ter um único espaço
de endereço, mas tem duas vantagens. Primeiro, torna-se possível ter 232
bytes de programa e 232
bytes adicio-
nais de dados usando apenas endereços de 32 bits. Segundo, como todas as escritas vão automaticamente para
o espaço de dados, fica impossível sobrescrever por acidente o programa, eliminando assim uma fonte de bugs
de programas. Separar espaços de instrução e dados também torna os ataques por malware muito mais difíceis de
serem bem-sucedidos, pois ele não pode alterar o programa – não consegue sequer endereçá-lo.
Observe que ter um espaço de endereços separado para instruções e dados não é o mesmo que ter uma cache
de nível 1 dividida. No primeiro caso, a quantidade total de espaço de endereço é duplicada e leituras de qualquer
endereço dão resultados diferentes, dependendo de a leitura ser de uma instrução ou de uma palavra de dados.
Com uma cache dividida, ainda há apenas um espaço de endereço, só que caches diferentes armazenam partes
diferentes desse espaço.
Ainda outro aspecto do modelo de memória de nível SA é a semântica da memória. É muito natural esperar
que uma instrução LOAD que ocorre após uma instrução STORE, e que referencia o mesmo endereço, retornará o
valor que acabou de ser armazenado. Todavia, como vimos no Capítulo 4, em muitos projetos, as microinstruções
são reordenadas. Assim, há um perigo real de que a memória não terá o comportamento esperado. O problema
fica ainda pior em um multiprocessador, no qual cada uma das várias CPUs envia uma sequência de requisições
de escrita e leitura (talvez reordenadas) a uma memória compartilhada.
Projetistas de sistemas podem adotar qualquer uma de diversas técnicas para resolver esse problema. Em
um extremo, todas as requisições de memória podem ser serializadas, portanto, cada uma é concluída antes de a
próxima ser emitida. Essa estratégia prejudica o desempenho, mas resulta na semântica de memória mais simples
(todas as operações são executadas estritamente na ordem do programa).
No outro extremo, não são dadas garantias de espécie alguma. Para forçar uma ordenação na memória, o
programa deve executar uma instrução SYNC, que bloqueia a emissão de todas as novas operações de memória
até que todas as anteriores tenham sido concluídas. Esse esquema atribui uma grande carga aos compiladores,
porque eles têm de entender, com detalhes, como a microarquitetura subjacente funciona, embora dê aos proje-
tistas de hardware a máxima liberdade para otimizar a utilização da memória.
Também são possíveis modelos de memória intermediários, nos quais o hardware bloqueia automaticamente
a emissão de certas referências à memória (por exemplo, as que envolvem uma dependência RAW ou WAR),
mas não bloqueia outras. Embora seja um aborrecimento ter todas essas peculiaridades causadas pela micro-
arquitetura expostas no nível SA (ao menos para os escritores de compiladores e programadores em linguagem
assembly), essa é a tendência. Ela é causada pelas execuções subjacentes, como reordenação de microinstruções,
paralelismo profundo, vários níveis de cache e assim por diante. eremos outros exemplos desses efeitos não
naturais adiante neste capítulo.
C a p 
t u l o 5 O n 
v e l d e a r q u i t e t u r a d o c o n j u n t o d e i n s t r u c
 a
 o 275
5.1.3 Registradores
Todos os computadores têm alguns registradores visíveis no nível SA. Eles estão lá para controlar a execução
do programa, reter resultados temporários e para outras finalidades. Em geral, os registradores visíveis no nível de
microarquitetura, como TOS e MAR na Figura 4.1, não o são no nível SA. Contudo, alguns deles, como o contador
de programa e o ponteiro de pilha, são visiveis em ambos os níveis. Por outro lado, registradores visíveis no nível
SA são sempre visíveis no nível da microarquitetura, já que é ali que são implementados.
Registradores de nível SA podem ser divididos em duas categorias: de uso especial e de uso geral. Os de uso
especial incluem coisas como o contador de programa e o ponteiro de pilha, bem como outros registradores com
uma função específica. Ao contrário, os registradores de uso geral estão ali para conter as variáveis locais funda-
mentais e resultados intermediários de cálculos. Sua função principal é prover acesso rápido a dados muito usados
(basicamente evitando acessos à memória). Máquinas RSC, com suas CPUs velozes e memórias (relativamente) len-
tas, costumam ter ao menos 32 registradores de uso geral, e a tendência em novos projetos de CPU é ter ainda mais.
Em algumas máquinas, os registradores de uso geral são completamente simétricos e intercambiáveis. Se os
registradores forem todos equivalentes, um compilador pode usar R1 para reter um resultado temporário, mas
também pode usar R25 da mesma forma. A escolha de registrador não importa.
Todavia, em outras máquinas, alguns dos registradores de uso geral podem ser um tanto especiais. Por exemplo,
no Core i7 há um registrador denominado EDX, que pode ser usado como registrador geral, mas que também recebe
metade do produto em uma multiplicação e retém metade do dividendo em uma divisão.
Mesmo quando os registradores de uso geral são completamente intercambiáveis, é comum que o sistema ope-
racional ou compiladores adotem convenções sobre como eles são usados. Por exemplo, alguns registradores podem
conter parâmetros para procedimentos chamados e outros podem ser usados como transitórios. Se um compilador
colocar uma variável local importante em R1 e depois chamar um procedimento de biblioteca que pensa que R1
é um registrador transitório disponível para ele, quando o procedimento de biblioteca retornar, R1 poderá conter
lixo. Se houver convenções em nível de sistema sobre como os registradores devem ser usados, aconselhamos os
compiladores e programadores em linguagem assembly a adotá-las para evitar problemas.
Além dos registradores de nível SA visíveis aos programas do usuário, há sempre uma grande quantidade
de registradores de uso especial, disponíveis somente em modo núcleo. Eles controlam as várias caches, memória,
dispositivos de E/S e outros recursos de hardware da máquina. São usados apenas pelo sistema operacional, de
modo que compiladores e usuários não precisam conhecê-los.
Um registrador de controle, que é algo como um híbrido de núcleo/usuário, é o registrador de flags ou PSW
(Program Status Word  palavra de estado do programa). Esse registrador contém vários bits diversos, necessá-
rios pela CPU. Os mais importantes são os códigos de condição. Esses bits são ajustados a cada ciclo da ULA e
refletem o estado do resultado da operação mais recente. Entre os bits de condição típicos estão:
N – Marcado quando o resultado foi Negativo.
Z – Marcado quando o resultado foi Zero.
 – Marcado quando o resultado causou um transbordo (overflow)
C – Marcado quando o resultado causou um vai-um (Carry) do bit da extrema esquerda.
A – Marcado quando houve um vai-um do bit 3 (vai-um Auxiliar – veja a seguir).
P – Marcado quando o resultado teve Paridade par.
Os códigos de condição são importantes porque as instruções de comparação e desvio condicional (também
denominadas instruções de salto condicional) os utilizam. Por exemplo, a instrução CMP normalmente subtrai
dois operandos e ajusta os códigos de condição com base na diferença. Se os operandos forem iguais, então a dife-
rença será zero, e o bit de código de condição Z no registrador PSW será marcado. Uma instrução BEQ (Branch
EQual) subsequente testa o bit Z e desvia se ele estiver marcado.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
276
O PSW contém mais do que apenas códigos de condição, mas o conteúdo total varia de uma máquina para
outra. Campos adicionais típicos são o modo da máquina (por exemplo, usuário ou núcleo), o bit de rastreamento
(usado para depuração), o nível de prioridade da CPU e o estado de habilitação de interrupção. Muitas vezes, o
PSW pode ser lido em modo usuário, mas alguns dos campos só podem ser escritos em modo núcleo (por exemplo,
o bit de modo usuário/núcleo).
5.1.4 Instruc
o
es
A principal característica do nível SA é o seu conjunto de instruções de máquina, que controlam o que
a máquina pode fazer. Há sempre instruções LOAD e STORE (de uma forma ou de outra) para mover dados entre
a memória e registradores e instruções MOVE para copiar dados entre os registradores. nstruções aritméticas estão
sempre presentes, assim como instruções booleanas e aquelas para comparar itens de dados e desviar conforme os
resultados. Já vimos algumas instruções SA típicas (veja a Figura 4.11) e estudaremos muitas mais neste capítulo.
5.1.5 Visa
o geral do n
vel ISA do Core i7
Neste capítulo, discutiremos três SAs muito diferentes: a A-32 da ntel, incorporada no Core i7; a arquitetura
ARM v7, executada no sistema-em-um-chip OMAP4430; e a arquitetura de 8 bits AR, usada pelo microcontrolador
ATmega168. A intenção não é dar uma descrição exaustiva de quaisquer delas, mas demonstrar aspectos importan-
tes de uma SA e mostrar como esses aspectos podem variar de uma SA para outra. amos começar com o Core i7.
O processador Core i7 evoluiu por muitas gerações, e sua linhagem pode ser rastreada até alguns dos mais
antigos microprocessadores que já foram construídos, como discutimos no Capítulo 1. Embora a SA básica
mantenha total suporte para execução de programas escritos para os processadores 8086 e 8088 (que tinham a
mesma SA), também contém sobras do 8080, um processador de 8 bits popular na década de 1970. O 8080, por
sua vez, sofreu forte influência das restrições de compatibilidade com o processador 8008, mais antigo ainda, que
era baseado no 4004, um chip de 4 bits usado na época em que os dinossauros vagavam pela Terra.
Do ponto de vista estrito do software, o 8086 e o 8088 eram máquinas normais de 16 bits (embora o 8088
tivesse um barramento de dados de 8 bits). O sucessor deles, o 80286, também era uma máquina de 16 bits. Sua
principal vantagem era um espaço de endereço maior, embora poucos programas o usassem, já que ele consistia
em 16.384 segmentos de 64 KB, em vez de uma memória linear de 230
bytes.
O 80386 foi a primeira máquina de 32 bits da família ntel. Todas as que vieram depois dela (80486, Pentium,
Pentium Pro, Pentium , Pentium , Pentium 4, Celeron, eon, Pentium M, Centrino, Core 2 duo, Core i7 etc.)
têm na essência a mesma arquitetura de 32 bits do 80386, denominada I-32, e portanto é essa que focalizaremos
aqui. A única alteração importante na arquitetura desde o 80386 foi a introdução das instruções MM, SSE e SSE2
em versões mais recentes da série x86. Essas instruções têm alto grau de especialização e foram projetadas para
melhorar o desempenho em aplicações multimídia. Outra extensão importante foi o x86 de 64 bits (normalmente
denominado x86-64), que aumentou os cálculos de inteiros e o tamanho do endereço virtual para 64 bits. Embora
quase todas as extensões fossem introduzidas pela ntel e, mais tarde, executadas pelos concorrentes, esse foi um
caso em que a AMD introduziu uma extensão que a ntel teve de adotar.
O Core i7 tem três modos de operação, dois dos quais o fazem agir como um 8088. No modo real, todas as
características que foram acrescentadas desde o 8088 são desligadas e o Core i7 se comporta como um simples
8088. Se algum programa fizer algo errado, a máquina inteira falha. Se a ntel tivesse projetado seres humanos,
ela teria inserido um bit que os faria voltar ao modo chimpanzé – grande parte do cérebro desativada, não falaria,
dormiria em árvores, comeria principalmente bananas etc.
Um degrau acima é o modo virtual 8086, que possibilita executar antigos programas 8088 de modo prote-
gido. Nesse modo, um sistema operacional real está no controle de toda a máquina. Para executar um programa
8088 antigo, o sistema operacional cria um ambiente isolado especial que age como um 8088, exceto que, se seu
programa falhar, o sistema operacional é avisado, em vez de a máquina falhar. Quando um usuário do Windows
inicia uma janela MS-DOS, o programa ali executado é iniciado em modo virtual 8086 para proteger o próprio
Windows contra o mau comportamento de programas MS-DOS.
C a p 
t u l o 5 O n 
v e l d e a r q u i t e t u r a d o c o n j u n t o d e i n s t r u c
 a
 o 277
O modo final é o modo protegido, no qual o Core i7 age de fato como um Core i7 em vez de um 8088 muito
caro. Há quatro níveis de privilégio disponíveis, controlados por bits no PSW. O nível 0 corresponde ao modo
núcleo em outros computadores e tem acesso total à máquina. É usado pelo sistema operacional. O nível 3 é para
programas do usuário. Ele bloqueia o acesso a certas instruções críticas e controla registradores para impedir que
um programa do usuário trapaceiro faça a máquina inteira falhar. Os níveis 1 e 2 pouco são usados.
O Core i7 tem um espaço de endereço enorme, com memória dividida em 16.384 segmentos, cada um indo do
endereço 0 ao endereço 232
– 1. Contudo, a maioria dos sistemas operacionais (incluindo o UN e todas as versões
do Windows) aceita apenas um segmento; portanto, o que a maioria dos programas de aplicação vê, na verdade,
é um espaço de endereço linear de 232
bytes e, às vezes, parte desse espaço está ocupado pelo sistema operacional.
Todos os bytes no espaço de endereço têm seu próprio endereço, sendo que as palavras têm 32 bits de comprimento.
Palavras são armazenadas em formato little-endian (o byte menos significativo tem o endereço mais baixo).
Os registradores do Core i7 são mostrados na Figura 5.3. Os quatro primeiros, EAX, EBX, ECX e EDX, são
registradores de 32 bits, mais ou menos de uso geral, embora cada um tenha suas próprias peculiaridades. O
EAX é o principal registrador aritmético; o EBX é bom para conter ponteiros (endereços de memória); o ECX tem
uma função na execução de laços; o EDX é necessário para multiplicação e divisão e, junto com o EAX, retém
produtos e dividendos de 64 bits. Cada um deles contém um registrador de 16 bits nos 16 bits de ordem baixa
e um de 8 bits nos 8 bits de ordem baixa. Esses registradores facilitam a manipulação de quantidades de 16 e 8
bits, respectivamente. O 8088 e o 80286 tinham só os registradores de 8 e 16 bits. Os registradores de 32 bits
foram adicionados com o 80386, junto com o prefixo E, que representa Extended (estendido).
Figura 5.3 Principais registradores do Core i7.
EAX
AL
AH
A X
EBX
BL
BH
B X
ECX
CL
CH
C X
EDX
ESI
EDI
EBP
ESP
DL
CS
EIP
EFLAGS
SS
DS
ES
FS
GS
DH
D X
8
8
16
Bits
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
278
Os quatro seguintes são, de certa forma, de uso geral, porém, com mais peculiaridades. A tarefa dos regis-
tradores ESI e EDI é conter ponteiros para a memória, em especial para as instruções de manipulação de cadeias
por hardware, nas quais o ESI aponta para a cadeia de fonte e EDI aponta para a cadeia de destino. O registrador
EBP também é um registrador de ponteiro. Ele é usado para apontar para a base do quadro de pilha corrente, o
mesmo que LV na JM. Quando um registrador como EBP é usado para apontar para a base do quadro de pilha
local, costuma ser denominado ponteiro de quadro. Por fim, ESP é o ponteiro de pilha.
O próximo grupo de registradores, de CS até GS, são registradores de segmento. Até certo ponto, eles são trilo-
bitas eletrônicos, fósseis antigos que restaram de uma época em que o 8088 tentava endereçar 220
bytes de memória
usando endereços de 16 bits. Basta dizer que, quando o Core i7 é ajustado para usar um único espaço de endereços
linear de 32 bits, eles podem ser ignorados sem problema algum. O seguinte é o EIP, que é o contador de programa
(Extended nstruction Pointer – ponteiro de instrução estendido). Por fim, chegamos ao EFLAGS, que é o PSW.
5.1.6 Visa
o geral do n
vel da ISA ARM do OMAP4430
A arquitetura ARM foi apresentada pela primeira vez em 1985 pela Acorn Computer. Era inspirada nas
pesquisas realizadas em Berkeley na década de 1980 (Patterson, 1985; Patterson e Séquin, 1982). A arquitetura
ARM original (denominada ARM2) era uma arquitetura de 32 bits que aceitava um espaço de endereço de 26
bits. O OMAP4430 utiliza a microarquitetura ARM Cortex A9, que executa a versão 7 da ARM, e essa é a SA que
descreveremos neste capítulo. Para manter a coerência com o resto do livro, aqui vamos nos referir à OMAP4430
mas, no nível SA, todos os projetos baseados na ARM Cortex A9 implementam a mesma SA.
A estrutura de memória do OMAP4430 é limpa e simples: a memória endereçável é um arranjo linear de
232
bytes. Processadores ARM são bi-endian, de modo que acessam a memória com a ordem big-endian ou little-
-endian. A escolha é feita com base em um bloco de memória do sistema que é lido logo após a inicialização do
processador. Para garantir que o bloco de memória seja lido corretamente, ele deve estar no formato little-endian,
mesmo que a máquina deva ser configurada para operação em big-endian.
É importante que a SA tenha um limite maior do que as execuções necessitam, porque é quase certo que
futuras implementações precisarão aumentar o tamanho da memória que o processador pode acessar. O espaço de
endereços de 32 bits da SA ARM está dando muito trabalho a diversos projetistas, pois muitos sistemas baseados
na ARM, como smartphones, já têm mais de 232
bytes de memória. Até agora, os projetistas têm trabalhado em
torno desses problemas tornando a maior parte da memória um armazenamento de drive flash, que é acessado
com uma interface de disco com suporte para um espaço de endereços maior, orientado a bloco. Para resolver
essa limitação com potencial para matar o mercado, a ARM (a empresa) publicou recentemente a definição da
SA ARM versão 8, que aceita espaços de endereços de 64 bits.
Um dos problemas mais sérios encontrados por arquiteturas bem-sucedidas é que suas SAs limitavam a
quantidade de memória endereçável. Na ciência da computação, o único erro que não pode ser contornado é não
ter bits suficientes. Um dia nossos netos nos perguntarão como, antigamente, os computadores conseguiam fazer
algo tendo somente endereços de 32 bits e apenas 4 GB de memória real, quando um joguinho médio precisa de
1 TB só para ser iniciado.
A SA ARM é limpa, embora a organização dos registradores seja um tanto complexa, em uma tentativa
de simplificar algumas codificações de instrução. A arquitetura mapeia o contador de programa para o arquivo de
registradores de inteiros (como o registrador R15), pois isso permite que sejam criados desvios com operações
da ULA que tenham R15 como registrador de destino. A experiência tem mostrado que a organização de registra-
dores não vale o trabalho que dá, mas aquela antiga regra de compatibilidade não permite que nos livremos dela.
A SA ARM tem dois grupos de registradores: 16 de uso geral de 32 bits e 32 de ponto flutuante de 32
bits (se houver suporte para o coprocessador FP). Os registradores de uso geral são denominados R0 até R15,
embora outros nomes sejam usados em certos contextos. Os nomes alternativos e as funções dos registradores
são mostrados na Figura 5.4.
C a p 
t u l o 5 O n 
v e l d e a r q u i t e t u r a d o c o n j u n t o d e i n s t r u c
 a
 o 279
Figura 5.4 Registradores gerais da ARM versa
o 7.
Registrador Nome alternativo Função
R0–R3 A1–A4 Mantém parâmetros para o procedimento que está sendo chamado
R4–R11 V1–V8 Mantém variáveis locais para o procedimento atual
R12 IP Registrador de chamada dentro do procedimento (para chamadas de 32 bits)
R13 SP Ponteiro de pilha
R14 LR Registrador de ligação (endereço de retorno para função atual)
R15 PC Contador de programa
Todos os registradores gerais têm 32 bits de largura e podem ser lidos e escritos por diversas instruções de
carga e armazenamento. Os usos atribuídos na Figura 5.4 são baseados, em parte, na convenção, mas também, em
parte, no modo como o hardware os trata. Em geral, não é sensato nos desviarmos das utilizações relacionadas na
figura, a menos que sejamos faixa preta em ARM e que realmente, mas realmente, saibamos o que estamos fazen-
do. Cabe ao compilador ou programador a responsabilidade de garantir que o programa acesse os registradores
de modo correto e efetue neles o tipo certo de aritmética. Por exemplo, é muito fácil carregar números de ponto
flutuante nos registradores gerais e então efetuar adição de inteiros neles, uma operação que produzirá total e
absoluto absurdo, mas que a CPU realizará com alegria se assim for instruída.
Os registrados Vx são usados para reter constantes, variáveis e ponteiros que são necessários em procedi-
mentos, embora possam ser armazenados e recarregados em entradas e saídas de procedimento, se for preciso. Os
registradores Ax são usados para passar parâmetros a procedimentos a fim de evitar referências à memória. Mais
adiante, explicaremos como isso funciona.
Quatro registradores dedicados são usados para finalidades especiais. O registrador IP contorna as limitações
da instrução de chamada funcional da ARM (BL), que não pode endereçar totalmente todos os seus 232
bytes de
espaço de endereços. Se o destino de uma chamada estiver muito distante para que seja expresso pela instrução,
esta chamará um trecho de código “embutido”, que usa o endereço no registrador IP como destino da chamada
de função. O registrador SP indica o topo da pilha atual e flutua à medida que as palavras são colocadas na pilha
ou retiradas dela. O terceiro registrador de uso especial é LR. Ele é usado para manter o endereço de retorno nas
chamadas de procedimento. O quarto, como já dissemos, é o contador de programa PC. Guardar um valor nesse
registrador redireciona a busca de instruções para aquele endereço recém-depositado no PC. Outro registrador
importante na arquitetura ARM é o de estado do programa (PSR), que mantém o estado dos cálculos anteriores
da ULA, incluindo Zero, Negativo e Transbordo, entre outros bits.
A SA ARM (quando configurada com o coprocessador FP) também tem 32 registradores de ponto flutu-
ante de 32 bits. Esses registradores podem ser acessados diretamente, como 32 valores de ponto flutuante com
precisão simples, ou como 16 valores de ponto flutuante de 64 bits com precisão dupla. O tamanho do registrador
de ponto flutuante acessado é determinado pela instrução; em geral, todas as instruções ARM de ponto flutuante
vêm com variantes de precisão simples e dupla.
A arquitetura ARM é uma arquitetura carregar/armazenar. sto é, as únicas operações que acessam a memó-
ria diretamente são as instruções LOAD e STORE, para mover dados entre os registradores e a memória. Todos
os operandos para instruções aritméticas e lógicas devem vir de registradores, ou ser fornecidos pela instrução (e
não pela memória), e todos os resultados devem ser salvos em um registrador (e não na memória).
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
280
5.1.7 Visa
o geral do n
vel ISA AVR do ATmega168
Nosso terceiro exemplo é o ATmega168. Diferente do Core i7 (que é mais usado em máquinas de uso geral e
conjuntos de servidores) e do OMAP4430 (que é usado principalmente em telefones, tablets e outros dispositivos
móveis), o ATmega168 é usado em sistemas embutidos de classe mais baixa, como sinais de trânsito e rádios-
-relógio, para controlar o dispositivo e gerenciar botões ou teclas, luzes e outras partes da interface de usuário.
Nesta seção, faremos uma breve introdução técnica à SA AR do ATmega168.
O ATmega168 tem um único modo e nenhuma proteção de hardware, já que nunca executa programas
múltiplos que pertencem a usuários potencialmente hostis. O modelo de memória é de extrema simplicidade. Há
16 KB de memória para programas e um segundo 1 KB de memória para dados. Cada um tem seu próprio espaço
de endereços, de modo que um endereço irá referenciar uma memória diferente, dependendo se o acesso é para
a memória de programas ou dados. Os espaços de programa e dados são separados, para possibilitar a execução
do espaço de programa em memória flash e o de dados em SRAM.
árias implementações diferentes de memória são possíveis, dependendo do quanto o projetista quer pagar
pelo processador. Na mais simples, o ATmega48, há uma memória flash de 4 KB para o programa e uma SRAM
de 512 bytes para dados. Ambas, flash e RAM, estão dentro do chip. Essa quantidade de memória costuma ser
suficiente para pequenas aplicações, e ter toda a memória no chip da CPU representa uma grande vantagem. O
ATmega88 tem duas vezes mais memória em chip: 8 KB de ROM e 1 KB de SRAM.
O ATmega168 usa uma organização de memória em duas camadas, oferecendo mais segurança ao programa.
A memória flash para programas é dividida em uma seção de carregador de inicialização e uma seção de aplicação,
com o tamanho de cada uma sendo determinado pelos bits de “fusível”, que são programados uma vez quando o
microcontrolador é ligado inicialmente. Por motivos de segurança, somente o código executado pela seção de car-
regador de inicialização pode atualizar a memória flash. Com esse recurso, qualquer código pode ser colocado na
área de aplicação (incluindo aplicações baixadas de terceiros), com a certeza de que ela nunca sujará outro código
no sistema (pois o código da aplicação estará rodando pelo espaço da aplicação, que não pode escrever na memória
flash). Para amarrar de verdade um sistema, um fornecedor pode assinar o código digitalmente. Com código assina-
do, o carregador de inicialização carrega o código na memória flash apenas se ele estiver assinado digitalmente por
um fornecedor de software aprovado. Dessa forma, o sistema só rodará código que tenha sido “abençoado” por um
fornecedor de software confiável. A técnica é bastante flexível, pois até mesmo o carregador de inicialização pode
ser substituído, se o novo código tiver sido assinado digitalmente de forma apropriada. sso é semelhante ao modo
como Apple e Tio garantem que o código rodando em seus dispositivos é seguro contra danos.
O ATmega168 contém 32 registradores de uso geral de 8 bits, que são acessados por instruções por meio de
um campo de 5 bits, especificando qual deles usar. Os registradores são denominados R0 até R31. Uma proprie-
dade peculiar dos registradores do ATmega168 é que eles também estão presentes no espaço de memória. O byte
0 do espaço de dados é equivalente a R0 do conjunto de registradores 0. Quando uma instrução muda R0 e mais
tarde lê o byte de memória 0, ele encontra lá o novo valor de R0. De modo semelhante, o byte 1 da memória é
R1, e assim por diante, até o byte 31. O arranjo pode ser visto na Figura 5.5.
Diretamente acima dos 32 registradores de uso geral, nos endereços de memória 32 a 95, existem 64 bytes
de memória reservados para acessar registradores de dispositivo de E/S, incluindo os dispositivos internos do
sistema-em-um-chip.
Além dos quatro conjuntos de oito registradores, o ATmega168 tem uma pequena quantidade de registrado-
res de uso especial, cujos mais importantes aparecem na Figura 5.5. O registrador de estado (SREG) contém, da
esquerda para a direita, o bit de habilitação de interrupção, o de carga/armazenamento, o bit auxiliar de vai-um,
o bit de sinal, o de transbordo, o flag de negativo, o flag de zero e o bit de vai-um. Todos esses bits de estado, exceto
o de habilitação de interrupção, são marcados como resultado de operações aritméticas.
O bit I do registrador de estado permite que as interrupções sejam habilitadas ou desabilitadas de modo glo-
bal. Se o bit I for 0, todas as interrupções são desabilitadas. Limpar esse bit permite desabilitar quaisquer outras
interrupções em uma única instrução. Marcar o bit permite que quaisquer interrupções atualmente pendentes
sejam executadas, bem como as futuras. Cada dispositivo tem, associado a ele, um bit de habilitação de interrup-
ção. Se o bit de habilitação do dispositivo estiver marcado e o bit I de habilitação global de interrupção estiver
marcado, o dispositivo pode interromper o processador.
C a p 
t u l o 5 O n 
v e l d e a r q u i t e t u r a d o c o n j u n t o d e i n s t r u c
 a
 o 281
Figura 5.5 Registrador no chip e organizac
a
o de memo
ria do ATmega168.
Memória do programa
Memória
da aplicação
Carregador
de inicialização
Registrador de estado (SREG)
Ponteiro de pilha (SP)
Endereço 80
Registradores
Memória de dados
Dados temporários
Memória de E/S
1023
95
32
31
0
Endereço 81
Alto
Baixo
7
I T H S V N Z C
0
0
16383
O ponteiro de pilha SP mantém o endereço atual na memória de dados onde as instruções PUSH e POP
acessarão seus dados, semelhante à instrução de mesmo nome na JM da Java, do Capítulo 4. O ponteiro de pilha
está localizado na memória de E/S, no endereço 80. Um único byte de memória com 8 bits é muito pequeno para
endereçar 1.024 bytes da memória de dados, de modo que o ponteiro de pilha é composto de dois locais conse-
cutivos na memória, formando um endereço de 16 bits.
5.2 Tipos de dados
Todos os computadores precisam de dados. Na verdade, há muitos sistemas de computação cujo único
propósito é processar dados financeiros, comerciais, científicos, de engenharia ou outros. Os dados têm de ser
representados de alguma forma específica no interior do computador. No nível SA, são usados vários tipos de
dados diferentes, que serão explicados a seguir.
Uma questão fundamental é se há ou não suporte de hardware para um tipo particular de dados. Suporte
de hardware significa que uma ou mais instruções esperam dados em um formato particular e o usuário não
tem liberdade de escolher um diferente. Por exemplo, os contadores têm o hábito peculiar de escrever números
negativos com um sinal de menos à direita do número em vez de à esquerda, onde os cientistas da computação o
colocam. Suponha que, em um esforço de impressionar o patrão, o chefe do centro de computação de um escri-
tório de contabilidade altere todos os números, em todos os computadores, para usar o bit da extrema direita (e
não o da extrema esquerda) como o bit de sinal. Sem dúvida, isso impressionaria muito o patrão – porque, de
pronto, todo o software deixaria de funcionar corretamente. O hardware espera certo formato para inteiros e não
funciona direito quando recebe qualquer outra coisa.
Agora, considere outro escritório de contabilidade, que acabou de firmar um contrato para verificar a dívida
federal (quanto o governo dos Estados Unidos deve a todos os cidadãos). Usar aritmética de 32 bits não funcio-
naria nesse caso, porque os números envolvidos são maiores do que 232
(cerca de 4 bilhões). Uma solução é usar
dois inteiros de 32 bits para representar cada número, o que dá 64 bits no total. Se a máquina não suportar esse
tipo de número de dupla precisão, toda a aritmética efetuada com eles teria de ser executada em software, mas
as duas partes podem estar em qualquer ordem, já que o hardware não se importa. Esse é um exemplo de tipo
de dados sem suporte de hardware e, por isso, sem uma determinada representação requerida em hardware. Nas
seções seguintes, examinaremos tipos de dados suportados pelo hardware e, por conseguinte, dados para os quais
são exigidos formatos específicos.
O r g a n i z a c
 a
 o e s t r u t u r a d a d e c o m p u t a d o r e s
282
5.2.1 Tipos de dados nume
ricos
Os tipos de dados podem ser divididos em duas categorias: numéricos e não numéricos. O principal entre
os tipos de dados numéricos são os inteiros. Eles podem ter muitos comprimentos, em geral 8, 16, 32 e 64 bits.
nteiros contam coisas (por exemplo, o número de chaves de fenda que uma loja de ferragens tem em estoque),
identificam coisas (por exemplo, números de contas correntes) e muito mais. A maioria dos computadores
modernos armazena inteiros em notação binária de complemento de dois, embora outros sistemas já tenham sido
usados no passado. Números binários serão discutidos no Apêndice A.
Alguns computadores suportam inteiros sem sinal, bem como inteiros com sinal. No caso de um inteiro
sem sinal, não há bit de sinal e todos os bits contêm dados. Esse tipo de dado tem a vantagem de um bit extra,
portanto, por exemplo, uma palavra de 32 bits pode conter um único inteiro sem sinal na faixa de 0 a 232
– 1,
inclusive. Ao contrário, um inteiro de 32 bits com sinal, representado por complemento de dois, só pode mani-
pular números até 231
– 1, mas, é claro, também pode manipular números negativos.
Para números que não podem ser expressos como um inteiro, como 3,5, são usados números de ponto flu-
tuante. Esses números serão discutidos no Apêndice B. Eles têm comprimentos de 32, 64 ou, às vezes, 128 bits.
A maioria dos computadores tem instruções para efetuar aritmética de ponto flutuante. Muitos deles têm regis-
tradores separados para conter operandos inteiros e para conter operandos de ponto flutuante.
Algumas linguagens de programação, em especial COBOL, permitem números decimais como um tipo de
dado. Máquinas que querem ser amigáveis à linguagem COBOL costumam suportar números decimais em hard-
ware, normalmente codificando um dígito decimal em 4 bits e então empacotando dois dígitos decimais por byte
(formato decimal em código binário). Todavia, a aritmética binária não funciona direito em números decimais
empacotados, portanto, são necessárias instruções especiais de correção de aritmética decimal. Essas instruções
precisam conhecer o vai-um do bit 3. É por essa razão que o código de condição muitas vezes contém um bit
auxiliar de vai-um. A propósito, o problema do Y2K (bug do ano 2000), tão comentado, foi causado por progra-
madores COBOL que decidiram que poderiam representar o ano com dois dígitos decimais (8 bits) em vez de
quatro dígitos decimais (ou um número binário de 8 bits), que podem manter ainda mais valores (256) do que
dois dígitos decimais (100). Grande otimização!
5.2.2 Tipos de dados na
o nume
ricos
Embora quase todos os primeiros computadores ganhassem suas vidas triturando números, computadores
modernos são usados com frequência para aplicações não numéricas, como e-mail, navegar pela Web, fotografia
digital e criação e reprodução de multimídia. Para essas aplicações, são necessários outros tipos de dados, que
muitas vezes são suportados por instruções de nível SA. Nesse caso, é clara a importância dos caracteres, embo-
ra nem todos os computadores ofereçam suporte de hardware para eles. Os códigos mais comuns são ASC e
Unicode. Eles suportam caracteres de 7 bits e de 16 bits, respectivamente. Ambos foram discutidos no Capítulo 2.
Não é incomum que o nível SA tenha instruções especiais destinadas a manipular cadeias de caracteres,
isto é, carreiras consecutivas de caracteres. Essas cadeias às vezes são delimitadas por um caractere especial na
extremidade. Como alternativa, um campo de comprimento de cadeia pode ser usado para monitorar essa extre-
midade
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf
Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf

Mais conteúdo relacionado

PDF
VoLTE Service Monitoring - VoLTE Voice Call
PDF
3.oeo000020 lte call drop diagnosis issue 1
DOC
Carrier aggregation LTE
PDF
Organização estruturada de computadores - Tanenbaum.pdf
PDF
Organização estruturada de computadores 6th Edition Andrew S. Tanenbaum
DOC
Pcs2031 projeto01 introducao_pic_v4
PPTX
SDAC 12º - M9 TGEI
PDF
Apostila de montagem e manutenção de computadores emi mario gurgel
VoLTE Service Monitoring - VoLTE Voice Call
3.oeo000020 lte call drop diagnosis issue 1
Carrier aggregation LTE
Organização estruturada de computadores - Tanenbaum.pdf
Organização estruturada de computadores 6th Edition Andrew S. Tanenbaum
Pcs2031 projeto01 introducao_pic_v4
SDAC 12º - M9 TGEI
Apostila de montagem e manutenção de computadores emi mario gurgel

Semelhante a Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf (20)

PDF
William Criptografia para Redes 3 Edicao.pdf
PPT
CPU.ppt
PDF
Apostila hardware-introducao-a-arquitetura-de-computadores
PPSX
MIPS Pipeline
PDF
Curso informtica manuten o - inicial
PDF
eBook - GUIA DE CONSULTA RAPIDA EM ROTEADORES E SWITCHES CISCO - VOL I.pdf
PDF
Instalação e Manutenção de Computadores
PDF
Laboratório -configuração_de_um_endereço_de_gerenciamento_do_switch-1
PDF
07_-_Microcomputadores e microcontroladores
PDF
Processadores
PPTX
Arquitetura de computadores Módulo 4
PDF
Arquitetura de Computadores: Barramentos e instruções
PDF
Computador de Bordo, Linux
PDF
1 história e características dos microcontroladores pic
PDF
Mdulo 1 Parte 5
PPTX
Arquiteturas_risc_e_cisc
PPTX
Projetos com microcontroladores
PDF
Trabalho sobre processadores
PDF
EL66J_Slides_arduino.pdf
PDF
Geração Automática de Autómatos Celulares para FPGA
William Criptografia para Redes 3 Edicao.pdf
CPU.ppt
Apostila hardware-introducao-a-arquitetura-de-computadores
MIPS Pipeline
Curso informtica manuten o - inicial
eBook - GUIA DE CONSULTA RAPIDA EM ROTEADORES E SWITCHES CISCO - VOL I.pdf
Instalação e Manutenção de Computadores
Laboratório -configuração_de_um_endereço_de_gerenciamento_do_switch-1
07_-_Microcomputadores e microcontroladores
Processadores
Arquitetura de computadores Módulo 4
Arquitetura de Computadores: Barramentos e instruções
Computador de Bordo, Linux
1 história e características dos microcontroladores pic
Mdulo 1 Parte 5
Arquiteturas_risc_e_cisc
Projetos com microcontroladores
Trabalho sobre processadores
EL66J_Slides_arduino.pdf
Geração Automática de Autómatos Celulares para FPGA
Anúncio

Último (20)

PDF
Gestão contínua de exposição a ameaças petrobras
PPTX
Panorama da aviação civil brasileira ANAC
PDF
pdfcoffee.com_metalografia-25-pdf-free.pdf
PPTX
Formação aaaaaaaaadsdsfg er rsgrsgesf efsfsefsf e LEEI.pptx
PPT
Padrões de Beleza I - Estética Corporal e Saúde
PPTX
Legislação aeronautica na aviação civil Brasileira
PPTX
Modelo para Qualificação de Mestrado - Tecnologia da Informação
PPTX
Importacao_Ordem_Customizacao_SAP_S4HANA.pptx
PDF
POO - Aula 05 - Herança - Generalização e Especialização.pdf
PPTX
Politicas-de-Seguranca-Privacidade-e-Cookies.pptx
DOCX
Laboratório de cyber security, apresentação simples.
PPTX
Introdução a Computação em Nuvem-parte2-T2
PDF
POO - Aula 05 - Herança - Generalização e Especialização.pdf
PDF
instalacoes eletricas para industria apressentacao basicas
PPTX
RCSOFTdfsdfrvadfvdfvargfvevevrervevqer.pptx
PPTX
AULA 1.pptx GESTÃO DE OPERAÇÕES INDUSTRIAIS
PDF
T-pico 1.pdfnsjabdkaksbbsuendnijsbshajanzk
PDF
Arquitetura de Software slides sommerville
PDF
wp-sn-advanced-high-availability-architecture (pt-br).pdf
PDF
POO - Aula 03 - Membros Estáticos e Construtores.pdf
Gestão contínua de exposição a ameaças petrobras
Panorama da aviação civil brasileira ANAC
pdfcoffee.com_metalografia-25-pdf-free.pdf
Formação aaaaaaaaadsdsfg er rsgrsgesf efsfsefsf e LEEI.pptx
Padrões de Beleza I - Estética Corporal e Saúde
Legislação aeronautica na aviação civil Brasileira
Modelo para Qualificação de Mestrado - Tecnologia da Informação
Importacao_Ordem_Customizacao_SAP_S4HANA.pptx
POO - Aula 05 - Herança - Generalização e Especialização.pdf
Politicas-de-Seguranca-Privacidade-e-Cookies.pptx
Laboratório de cyber security, apresentação simples.
Introdução a Computação em Nuvem-parte2-T2
POO - Aula 05 - Herança - Generalização e Especialização.pdf
instalacoes eletricas para industria apressentacao basicas
RCSOFTdfsdfrvadfvdfvargfvevevrervevqer.pptx
AULA 1.pptx GESTÃO DE OPERAÇÕES INDUSTRIAIS
T-pico 1.pdfnsjabdkaksbbsuendnijsbshajanzk
Arquitetura de Software slides sommerville
wp-sn-advanced-high-availability-architecture (pt-br).pdf
POO - Aula 03 - Membros Estáticos e Construtores.pdf
Anúncio

Andrew S. Tanenbaum - Organização Estruturada de Computadores - 6 Edição.pdf

  • 4. Organização estruturada de computadores Tanenbaum • Austin 6a EDIÇÃO Tradução DANIEL VIEIRA Revisão técnica PROF. DR. WAGNER LUIZ ZUCCHI rofessor do Departamento de Sistemas Eletrônicos da Escola olitécnica da Universidade de São aulo, do programa de ós-Graduação do Instituto de esquisas Tecnológicas (IT) e da Universidade Nove de Julho. Colaborador da revista RTI  Redes, Telecomunicações e Infraestrutura  e consultor de diversas empresas na área de redes e telecomunicação digital
  • 5. 2013 Direitos exclusivos para a língua portuguesa cedidos à Pearson Education do Brasil Ltda., uma empresa do grupo Pearson Education Rua Nelson Francisco, 26 CEP 02712-100  São Paulo  SP  Brasil Fone: 11 2178-8686  Fax: 11 2178-8688 [email protected] Dados Internacionais de Catalogação na Publicação (CIP) (Câmara Brasileira do Livro, SP, Brasil) Tanenbaum, Andrew S. Organização estruturada de computadores / Andrew S. Tanenbaum, Todd Austin; tradução Daniel Vieira; revisão técnica Wagner Luiz Zucchi. -- São Paulo : Pearson Prentice Hall, 2013. Título original: Structured computer organization. 6 ed. norte-americana. Bibliografia. ISBN 978-85-4301-379-4 1. Organização de computador 2. Programação (Computadores) I. Austin, Todd. II. Título. 13-04217 CDD-005.1 Índice para catálogo sistemático: 1. Organização estruturada de computadores: Ciências da computação 005.1 ©2013 by Andrew S. Tanenbaum e Todd Austin Todos os direitos reservados. Nenhuma parte desta publicação poderá ser reproduzida ou transmitida de qualquer modo ou por qualquer outro meio, eletrônico ou mecânico, incluindo fotocópia, gravação ou qualquer outro tipo de sistema de armazenamento e transmissão de informação, sem prévia autorização, por escrito, da Pearson Education do Brasil. D    ú Roger Trimer G  Kelly Tavares S    Silvana Afonso C   Danielle Sales C    Sérgio Nascimento C    Tatiane Romano E  õ Vinícius Souza E   Daniela Braz E  Luiz Salla P Christiane Colas T Daniel Vieira R  Wagner Luiz Zucchi R Guilherme Summa C Solange Rennó (adaptação do projeto original) P    Casa de Ideias
  • 6. Suma rio PREFÁCIO  EICRI  1 INROUÇÃO 1 1.1 ORGANIZAÇÃO ESTRUTURADA DE COMPUTADOR 2 1.1.1 Linguagens, níveis e máquinas virtuais 2 1.1.2 Máquinas multiníveis contemporâneas 4 1.1.3 Evolução de máquinas multiníveis 6 1.2 MARCOS DA ARQUITETURA DE COMPUTADORES 10 1.2.1 A geração zero — computadores mecânicos (1642–1945) 10 1.2.2 A primeira geração — válvulas (1945–1955) 13 1.2.3 A segunda geração — transistores (1955–1965) 15 1.2.4 A terceira geração — circuitos integrados (1965–1980) 17 1.2.5 A quarta geração — integração em escala muito grande (1980–?) 18 1.2.6 A quinta geração — computadores de baixa potência e invisíveis 20 1.3 O ZOOLÓGICO DOS COMPUTADORES 22 1.3.1 Forças tecnológicas e econômicas 22 1.3.2 Tipos de computadores 23 1.3.3 Computadores descartáveis 24 1.3.4 Microcontroladores 26 1.3.5 Computadores móveis e de jogos 27 1.3.6 Computadores pessoais 28 1.3.7 Servidores 29 1.3.8 Mainframes 30 1.4 EXEMPLOS DE FAMÍLIAS DE COMPUTADORES 30 1.4.1 Introdução à arquitetura x86 31 1.4.2 Introdução à arquitetura ARM 35 1.4.3 Introdução à arquitetura AVR 37 1.5 UNIDADES MÉTRICAS 38 1.6 ESQUEMA DESTE LIVRO 39 2 ORGNIZÇÃO E SISEMS E COMPUORES 42 2.1 PROCESSADORES 42 2.1.1 Organização da CPU 43 2.1.2 Execução de instrução 44
  • 7. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s VI 2.1.3 RISC versus CISC 47 2.1.4 Princípios de projeto para computadores modernos 49 2.1.5 Paralelismo no nível de instrução 50 2.1.6 Paralelismo no nível do processador 53 2.2 MEMÓRIA PRIMÁRIA 57 2.2.1 Bits 57 2.2.2 Endereços de memória 58 2.2.3 Ordenação de bytes 59 2.2.4 Códigos de correção de erro 60 2.2.5 Memória cache 64 2.2.6 Empacotamento e tipos de memória 66 2.3 MEMÓRIA SECUNDÁRIA 67 2.3.1 Hierarquias de memória 67 2.3.2 Discos magnéticos 68 2.3.3 Discos IDE 71 2.3.4 Discos SCSI 72 2.3.5 RAID 73 2.3.6 Discos em estado sólido 76 2.3.7 CD-ROMs 78 2.3.8 CDs graváveis 81 2.3.9 CDs regraváveis 83 2.3.10 DVD 83 2.3.11 Blu-ray 85 2.4 ENTRADA/SAÍDA 85 2.4.1 Barramentos 85 2.4.2 Terminais 88 2.4.3 Mouses 93 2.4.4 Controladores de jogos 94 2.4.5 Impressoras 96 2.4.6 Equipamento de telecomunicações 100 2.4.7 Câmeras digitais 106 2.4.8 Códigos de caracteres 108 2.5 RESUMO 111 3 O NÍVEL LGICO IGIL 115 3.1 PORTAS E ÁLGEBRA BOOLEANA 115 3.1.1 Portas 116 3.1.2 Álgebra booleana 117 3.1.3 Execução de funções booleanas 119 3.1.4 Equivalência de circuito 120 3.2 CIRCUITOS LÓGICOS DIGITAIS BÁSICOS 123 3.2.1 Circuitos integrados 124
  • 8. S u m a  r i o VII 3.2.2 Circuitos combinatórios 125 3.2.3 Circuitos aritméticos 127 3.2.4 Clocks 132 3.3 MEMÓRIA 133 3.3.1 Memórias de 1 bit 133 3.3.2 Flip-Flops 135 3.3.3 Registradores 137 3.3.4 Organização da memória 138 3.3.5 Chips de memória 140 3.3.6 RAMs e ROMs 142 3.4 CHIPS DE CPU E BARRAMENTOS 146 3.4.1 Chips de CPU 146 3.4.2 Barramentos de computador 147 3.4.3 Largura do barramento 149 3.4.4 Clock do barramento 151 3.4.5 Arbitragem de barramento 154 3.4.6 Operações de barramento 156 3.5 EXEMPLO DE CHIPS DE CPUs 158 3.5.1 O Intel Core i7 158 3.5.2 O sistema-em-um-chip Texas Instruments OMAP4430 164 3.5.3 O microcontrolador Atmel ATmega168 167 3.6 EXEMPLOS DE BARRAMENTOS 169 3.6.1 O barramento PCI 169 3.6.2 PCI Express 176 3.6.3 Barramento serial universal (USB) 180 3.7 INTERFACE 183 3.7.1 Interfaces de E/S 183 3.7.2 Decodificação de endereço 184 3.8 RESUMO 186 4 O NÍVEL E MICRORQUIEUR 190 4.1 UM EXEMPLO DE MICROARQUITETURA 190 4.1.1 O caminho de dados 191 4.1.2 Microinstruções 196 4.1.3 Controle de microinstrução: a Mic-1 198 4.2 EXEMPLO DE ISA: IJVM 201 4.2.1 Pilhas 201 4.2.2 O modelo de memória IJVM 203 4.2.3 Conjunto de instruções da IJVM 204 4.2.4 Compilando Java para a IJVM 208 4.3 EXEMPLO DE IMPLEMENTAÇÃO 209
  • 9. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s VIII 4.3.1 Microinstruções e notação 209 4.3.2 Implementação de IJVM que usa a Mic-1 212 4.4 PROJETO DO NÍVEL DE MICROARQUITETURA 222 4.4.1 Velocidade versus custo 223 4.4.2 Redução do comprimento do caminho de execução 224 4.4.3 Projeto com busca antecipada: a Mic-2 229 4.4.4 Projeto com pipeline: a Mic-3 233 4.4.5 ipeline de sete estágios: a Mic-4 238 4.5 MELHORIA DE DESEMPENHO 241 4.5.1 Memória cache 241 4.5.2 Previsão de desvio 246 4.5.3 Execução fora de ordem e renomeação de registrador 250 4.5.4 Execução especulativa 254 4.6 EXEMPLOS DO NÍVEL DE MICROARQUITETURA 256 4.6.1 A microarquitetura da CPU Core i7 256 4.6.2 A microarquitetura da CPU OMAP4430 260 4.6.3 A microarquitetura do microcontrolador ATmega168 264 4.7 COMPARAÇÃO ENTRE i7, OMAP4430 E ATmega168 266 4.8 RESUMO 266 5 O NÍVEL E RQUIEUR O CONJUNO E INSRUÇÃO 270 5.1 VISÃO GERAL DO NÍVEL ISA 272 5.1.1 Propriedades do nível ISA 272 5.1.2 Modelos de memória 273 5.1.3 Registradores 275 5.1.4 Instruções 276 5.1.5 Visão geral do nível ISA do Core i7 276 5.1.6 Visão geral do nível ISA ARM do OMAP4430 278 5.1.7 Visão geral do nível ISA AVR do ATmega168 280 5.2 TIPOS DE DADOS 281 5.2.1 Tipos de dados numéricos 282 5.2.2 Tipos de dados não numéricos 282 5.2.3 Tipos de dados no Core i7 283 5.2.4 Tipos de dados na CPU ARM do OMAP4430 283 5.2.5 Tipos de dados na CPU AVR do ATmega168 284 5.3 FORMATOS DE INSTRUÇÃO 284 5.3.1 Critérios de projeto para formatos de instrução 285 5.3.2 Expansão de opcodes 287 5.3.3 Formatos de instruções do Core i7 289 5.3.4 Formatos de instruções da CPU ARM do OMAP4430 290 5.3.5 Formatos de instruções da CPU AVR do ATmega168 291
  • 10. S u m a  r i o IX 5.4 ENDEREÇAMENTO 292 5.4.1 Modos de endereçamento 292 5.4.2 Endereçamento imediato 292 5.4.3 Endereçamento direto 293 5.4.4 Endereçamento de registrador 293 5.4.5 Endereçamento indireto de registrador 293 5.4.6 Endereçamento indexado 294 5.4.7 Endereçamento de base indexado 296 5.4.8 Endereçamento de pilha 296 5.4.9 Modos de endereçamento para instruções de desvio 299 5.4.10 Ortogonalidade de opcodes e modos de endereçamento 300 5.4.11 Modos de endereçamento do Core i7 301 5.4.12 Modos de endereçamento da CPU ARM do OMAP4430 303 5.4.13 Modos de endereçamento da AVR do ATmega168 303 5.4.14 Discussão de modos de endereçamento 303 5.5 TIPOS DE INSTRUÇÃO 304 5.5.1 Instruções para movimento de dados 304 5.5.2 Operações diádicas 305 5.5.3 Operações monádicas 306 5.5.4 Comparações e desvios condicionais 307 5.5.5 Instruções de chamada de procedimento 309 5.5.6 Controle de laço 309 5.5.7 Entrada/Saída 310 5.5.8 Instruções do Core i7 313 5.5.9 Instruções da CPU ARM do OMAP4430 315 5.5.10 Instruções da CPU AVR do ATmega168 317 5.5.11 Comparação de conjuntos de instruções 319 5.6 FLUXO DE CONTROLE 319 5.6.1 Fluxo de controle sequencial e desvios 320 5.6.2 Procedimentos 320 5.6.3 Corrotinas 324 5.6.4 Exceções 326 5.6.5 Interrupções 327 5.7 UM EXEMPLO DETALHADO: AS TORRES DE HANÓI 330 5.7.1 As Torres de Hanói em linguagem de montagem do Core i7 330 5.7.2 As Torres de Hanói em linguagem de montagem da CPU ARM do OMAP4430 332 5.8 A ARQUITETURA IA-64 E O ITANIUM 2 333 5.8.1 O problema da ISA IA-32 333 5.8.2 O modelo IA-64: computação por instrução explicitamente paralela 334 5.8.3 Redução de referências à memória 335 5.8.4 Escalonamento de instruções 336
  • 11. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s X 5.8.5 Redução de desvios condicionais: predicação 337 5.8.6 Cargas especulativas 339 5.9 RESUMO 340 6 O SISEM OPERCIONL 344 6.1 MEMÓRIA VIRTUAL 345 6.1.1 Paginação 346 6.1.2 Implementação de paginação 347 6.1.3 Paginação por demanda e o modelo de conjunto de trabalho 351 6.1.4 Política de substituição de página 351 6.1.5 Tamanho de página e fragmentação 353 6.1.6 Segmentação 354 6.1.7 Implementação de segmentação 357 6.1.8 Memória virtual no Core i7 359 6.1.9 Memória virtual na CPU ARM do OMAP4430 363 6.1.10 Memória virtual e caching 365 6.2 VIRTUALIZAÇÃO DO HARDWARE 365 6.2.1 Virtualização do hardware no Core i7 366 6.3 INSTRUÇÕES DE E/S DE NÍVEL OSM 367 6.3.1 Arquivos 367 6.3.2 Implementação de instruções de E/S de nível OSM 369 6.3.3 Instruções de gerenciamento de diretório 371 6.4 INSTRUÇÕES DE NÍVEL OSM PARA PROCESSAMENTO PARALELO 372 6.4.1 Criação de processo 373 6.4.2 Condições de disputa 374 6.4.3 Sincronização de processos usando semáforos 377 6.5 EXEMPLOS DE SISTEMAS OPERACIONAIS 380 6.5.1 Introdução 380 6.5.2 Exemplos de memória virtual 385 6.5.3 Exemplos de E/S virtual em nível de sistema operacional 388 6.5.4 Exemplos de gerenciamento de processos 397 6.6 RESUMO 402 7 O NÍVEL E LINGUGEM E MONGEM 407 7.1 INTRODUÇÃO À LINGUAGEM DE MONTAGEM 408 7.1.1 O que é uma linguagem de montagem? 408 7.1.2 Por que usar linguagem de montagem? 409 7.1.3 Formato de uma declaração em linguagem de montagem 409 7.1.4 Pseudoinstruções 411 7.2 MACROS 413 7.2.1 Definição, chamada e expansão de macro 413
  • 12. S u m a  r i o XI 7.2.2 Macros com parâmetros 415 7.2.3 Características avançadas 415 7.2.4 Implementação de um processador de macros em um assembler 416 7.3 O PROCESSO DE MONTAGEM 417 7.3.1 Assemblers de duas etapas 417 7.3.2 Passagem um 417 7.3.3 Passagem dois 421 7.3.4 Tabela de símbolos 422 7.4 LIGAÇÃO E CARREGAMENTO 423 7.4.1 Tarefas realizadas pelo ligador 424 7.4.2 Estrutura de um módulo-objeto 427 7.4.3 Tempo de vinculação e relocação dinâmica 428 7.4.4 Ligação dinâmica 430 7.5 RESUMO 433 8 RQUIEURS E COMPUORES PRLELOS 436 8.1 PARALELISMO NO CHIP 438 8.1.1 Paralelismo no nível da instrução 438 8.1.2 Multithreading no chip 443 8.1.3 Multiprocessadores com um único chip 448 8.2 COPROCESSADORES 453 8.2.1 Processadores de rede 453 8.2.2 Processadores de gráficos 459 8.2.3 Criptoprocessadores 461 8.3 MULTIPROCESSADORES DE MEMÓRIA COMPARTILHADA 462 8.3.1 Multiprocessadores versus multicomputadores 462 8.3.2 Semântica da memória 468 8.3.3 Arquiteturas de multiprocessadores simétricos UMA 471 8.3.4 Multiprocessadores NUMA 478 8.3.5 Multiprocessadores COMA 485 8.4 MULTICOMPUTADORES DE TROCA DE MENSAGENS 486 8.4.1 Redes de interconexão 487 8.4.2 MPPs — processadores maciçamente paralelos 490 8.4.3 Computação de cluster 497 8.4.4 Software de comunicação para multicomputadores 502 8.4.5 Escalonamento 503 8.4.6 Memória compartilhada no nível de aplicação 504 8.4.7 Desempenho 510 8.5 COMPUTAÇÃO EM GRADE 514 8.6 RESUMO 516
  • 13. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s XII 9 BIBLIOGRFI 519  NÚMEROS BINÁRIOS 525 A.1 NÚMEROS DE PRECISÃO FINITA 525 A.2 SISTEMAS DE NÚMEROS RAIZ, OU NÚMEROS DE BASE 527 A.3 CONVERSÃO DE UMA BASE PARA OUTRA 529 A.4 NÚMEROS BINÁRIOS NEGATIVOS 531 A.5 ARITMÉTICA BINÁRIA 532 B NÚMEROS E PONO FLUUNE 534 B.1 PRINCÍPIOS DE PONTO FLUTUANTE 534 B.2 PADRÃO DE PONTO FLUTUANTE IEEE 754 537 C PROGRMÇÃO EM LINGUGEM E MONGEM 542 C.1 VISÃO GERAL 543 C.1.1 Linguagem de montagem 543 C.1.2 Um pequeno programa em linguagem de montagem 543 C.2 O PROCESSADOR 8088 544 C.2.1 O ciclo do processador 545 C.2.2 Os registradores gerais 546 C.2.3 Registradores de ponteiros 547 C.3 MEMÓRIA E ENDEREÇAMENTO 548 C.3.1 Organização da memória e segmentos 548 C.3.2 Endereçamento 549 C.4 O CONJUNTO DE INSTRUÇÕES DO 8088 552 C.4.1 Mover, copiar, efetuar aritmética 552 C.4.2 Operações lógicas, de bit e de deslocamento 555 C.4.3 Operações de laço e cadeias repetitivas 555 C.4.4 Instruções Jump e Call 556 C.4.5 Chamadas de sub-rotina 557 C.4.6 Chamadas de sistema e sub-rotinas de sistema 558 C.4.7 Observações finais sobre o conjunto de instruções 560 C.5 O ASSEMBLER 561 C.5.1 Introdução 561 C.5.2 O assembler as88, baseado em ACK 561 C.5.3 Algumas diferenças com outros assemblers 8088 564 C.6 O RASTREADOR 565 C.6.1 Comandos do rastreador 566 C.7 COMO ACESSAR 568 C.8 EXEMPLOS 568 C.8.1 Exemplo de Hello World 568
  • 14. S u m a  r i o XIII C.8.2 Exemplo de registradores gerais 570 C.8.3 Comando de chamada e registradores de ponteiros 571 C.8.4 Depuração de um programa de impressão de vetores 574 C.8.5 Manipulação de cadeia e instruções de cadeia 576 C.8.6 Tabelas de despacho 579 C.8.7 Acesso a arquivo com buffer e aleatório 580 ÍNICE 584
  • 16. Prefa cio A s cinco primeiras edições deste livro foram baseadas na ideia de que um computador pode ser considerado uma hierarquia de níveis, cada um realizando alguma função bem definida. Esse conceito fundamental é válido tanto hoje quanto na época da primeira edição, de modo que foi mantido como base para a sexta edição. Assim como nas cinco primeiras edições, o nível lógico digital, o nível de microarquitetura, o nível de arqui- tetura do conjunto de instruções, o nível de máquina do sistema operacional e o nível da linguagem de montagem são todos discutidos com detalhes. Embora a estrutura básica tenha sido mantida, esta edição contém muitas mudanças, pequenas e grandes, que a mantém atualizada na área da computação, que muda tão rapidamente. Por exemplo, os modelos de máquinas usados foram atualizados. Os exemplos atuais são ntel Core i7, Texas nstrument OMAP4430 e Atmel ATmega168. O Core i7 é um exemplo de CPU popular usada em laptops, desktops e servidores. O OMAP4430 é um tipo de CPU popular baseada em ARM, muito usada em smartphones e tablets. Mesmo que você talvez nunca tenha ouvido falar do microcontrolador ATmega168, provavelmente já terá interagido muitas vezes com um deles. O microcontrolador ATmega168 baseado no AR é encontrado em diversos sistemas embutidos, variando desde rádios-relógios até fornos de micro-ondas. O interesse em sistemas embutidos é cada vez maior, e o ATmega168 é muito usado poo seu custo baixíssimo (centavos), sua grande quantidade de software e periféricos para ele e o grande número de programadores disponíveis. A quantidade de ATmega168s no mundo decerto é maior que a de CPUs Pentium e Core i3, i5 e i7 por algumas ordens de grandeza. O ATmega168s também é o processador encontrado no computador embutido Arduino de placa única, um sistema popular pro- jetado em uma universidade italiana para custar menos que um jantar em uma pizzaria. Ao longo dos anos, muitos professores que adotaram este livro solicitaram repetidas vezes material sobre programação em linguagem de montagem (assembly). Com a sexta edição, esse material agora está disponível na Sala irtual (veja adiante), onde pode ser expandido com facilidade e mantido de modo perene. A linguagem de montagem escolhida é a do 8088, pois é uma versão reduzida do conjunto de instruções iA32 extremamente popular, usado no processador Core i7. Poderíamos ter usado os conjuntos de instruções ARM ou AR, ou alguma outra SA da qual quase ninguém ouviu falar, mas, como uma ferramenta de motivação, o 8088 é uma escolha melhor, pois muitos alunos possuem uma CPU compatível com o 8088 em casa. O Core i7 completo é muito complexo para os alunos entenderem com detalhes. O 8088 é semelhante, porém muito mais simples. Além disso, o Core i7, que é abordado com detalhes nesta edição do livro, é capaz de executar programas 8088. Porém, como a depuração do código de montagem é muito difícil, oferecemos um conjunto de ferramentas para aprendizado da programação em linguagem de montagem, incluindo um assembler 8088, um simulador e um rastreador. Essas ferramentas estão disponíveis para Windows, Solaris UN, e Linux, na Sala irtual. O livro tornou-se mais extenso com o passar dos anos (a primeira edição tinha 443 páginas; esta tem 624 páginas). Essa expansão foi inevitável, tendo em vista que um assunto se desenvolve e há mais a saber sobre ele. Como resultado, quando se resolve adotá-lo em um curso, nem sempre é possível terminá-lo em um único curso (por exemplo, quando o curso é trimestral). Uma alternativa possível seria estudar, como um mínimo essencial, os Capítulos 1, 2 e 3, a primeira parte do Capítulo 4 (até, e inclusive, a Seção 4.4) e o Capítulo 5. O tempo que sobrar poderia ser utilizado com o restante do Capítulo 4 e partes dos Capítulos 6, 7 e 8, dependendo do interesse do professor e dos alunos. Em seguida apresentamos, capítulo por capítulo, uma resenha das principais mudanças desde a quinta edi- ção. O Capítulo 1 ainda contém uma revisão histórica da arquitetura de computador, que mostra como chegamos
  • 17. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s XVI onde estamos hoje e quais foram os marcos ao longo do percurso. Muitos alunos ficarão surpresos ao descobrir que os computadores mais poderosos do mundo na década de 1960, que custavam milhões de dólares america- nos, tinham muito menos de 1% do poder de computação de seus smartphones. Discutimos também o espectro ampliado dos computadores atuais, incluindo FGPAs, smartphones, tablets e consoles de jogos. Discutimos tam- bém nossas três novas arquiteturas de exemplo (Core i7, OMAP4430 e ATmega168). No Capítulo 2, o material sobre estilos de processamento foi expandido para incluir processadores paralelos de dados, incluindo unidades de processamento gráfico (GPUs). O panorama do armazenamento foi expandido para incluir os dispositivos de armazenamento baseados em memória flash, cada vez mais populares. Um material novo foi acrescentado à seção de entrada/saída, que detalha os controladores de jogos modernos, incluindo o Wiimote e o Kinect, além de telas sensíveis ao toque, usadas em smartphones e tablets. O Capítulo 3 passou por uma revisão em diversas partes. Ele ainda começa no básico, explicando como funcionam os transistores, e parte disso para que até mesmo os alunos sem qualquer base em hardware possam entender, em princípio, como funciona um computador moderno. Oferecemos material novo sobre FPGAs (Field- -Programmable Gate Arrays), fábricas de hardware programáveis, que levam os verdadeiros custos do projeto no nível de porta em grande escala para onde eles são muito usados hoje, a sala de aula. Os três novos exemplos de arquiteturas são descritos aqui em um nível mais alto. O Capítulo 4 sempre foi benquisto por explicar como um computador realmente funciona, portanto a maior parte dele não sofreu alterações desde a quinta edição. Contudo, há novas seções que discutem o nível de micro- arquitetura do Core i7, do OMAP4430 e do ATmega168. Os Capítulos 5 e 6 foram atualizados com base nos novos exemplos de arquitetura, particularmente com novas seções descrevendo os conjuntos de instruções ARM e AR. O Capítulo 6 utiliza Windows 7 em vez do Windows P como exemplo. O Capítulo 7, sobre programação em linguagem de montagem, não teve muita alteração desde a quinta edição. O Capítulo 8 sofreu muitas revisões, para refletir novos desenvolvimentos na área de computação paralela. Foram incluídos mais detalhes sobre a arquitetura do multiprocessador Core i7, e a arquitetura GPU de uso geral NDA Fermi é descrita com detalhes. Por fim, as seções sobre os supercomputadores BlueGene e Red Storm foram atualizadas para refletir as atualizações recentes nessas enormes máquinas. O Capítulo 9 mudou. As leituras sugeridas passaram para a Sala irtual, de modo que o novo texto contém apenas as referências citadas no livro, muitas delas novas. A organização do computador é um campo dinâmico. Os Apêndices A e B não foram atualizados desde a última vez. Números binários e números de ponto flutuante não mudaram muito nos últimos anos. O Apêndice C, sobre programação em linguagem de montagem, foi escrito pelo dr. Evert Wattel da rije Universiteit, Amsterdã. O dr. Wattel leciona há muitos anos e tem ensinado seus alunos a usar essas ferramentas. Agradecemos a ele por ter escrito esse apêndice. Ele não mudou muito desde a quinta edição, mas as ferramentas agora estão na Sala irtual. Além das ferramentas para linguagem de montagem, a Sala irtual também contém um simulador grá- fico a ser usado junto com o Capítulo 4. Esse simulador foi escrito pelo professor Richard Salter, do Oberlin College, e pode ser usado pelos estudantes para ajudá-los a compreender os princípios discutidos nesse capítulo. Agradecemos muito a ele por ter fornecido esse software. Muitas pessoas leram partes do original e contribuíram com sugestões úteis ou ajudaram de diversas manei- ras. Gostaríamos de agradecer, em particular, a ajuda prestada por Anna Austin, Mark Austin, Livio Bertacco, aleria Bertacco, Debapriya Chatterjee, Jason Clemons, Andrew DeOrio, Joseph Greathouse e Andrea Pellegrini. As pessoas citadas a seguir revisaram o original e sugeriram mudanças: Jason D. Bakos (University of South Carolina), Bob Brown (Southern Polytechnic State University), Andrew Chen (Minnesota State University, Moorhead), J. Archer Harris (James Madison University), Susan Krucke (James Madison University), A. Yavuz Oruc (University of Maryland), Frances Marsh (Jamestown Community College) e Kris Schindler (University at Buffalo). Somos muito gratos a eles.
  • 18. P r e f a  c i o XVII árias pessoas ajudaram a criar novos exercícios. São elas: Byron A. Jeff (Clayton University), Laura W. McFall (DePaul University), Taghi M. Mostafavi (University of North Carolina at Charlotte) e James Nystrom (Ferris State University). Novamente, somos muito gratos por sua ajuda. Nossa editora, Tracy Johnson, foi muito útil de diversas maneiras, grandes e pequenas, além de ser muito paciente conosco. Somos muito gratos pelo auxílio de Carole Snyder na coordenação de várias pessoas envolvidas no projeto. Bob Englehardt realizou um ótimo trabalho de produção. Eu (AST) gostaria de agradecer mais uma vez a Suzanne por seu amor e paciência, que nunca se esgotaram, nem mesmo após 21 livros. Barbara e Marvin são sempre uma alegria e agora sabem o que os professores fazem para ganhar a vida. Aron pertence à próxima geração: crianças que são usuários intensos do computador, antes mesmo de entrarem no jardim de infância. Nathan ainda não chegou a esse ponto, mas, depois que descobrir como andar, o iPad será o próximo. Por fim, eu (TA) gostaria de usar esta oportunidade para agradecer à minha sogra Roberta, que me ajudou a reservar algum tempo para trabalhar neste livro. Sua mesa da sala de jantar em Bassano Del Grappa, tália, provi- denciou a dose certa de isolamento, abrigo e vinho para realizar essa importante tarefa. ANDREW S. TANENBAUM TODD AUSTIN Agradecimentos  Edic a o brasileira Agradecemos a todos os profissionais envolvidos na produção deste livro, em especial ao Prof. Dr. Wagner Luiz Zucchi (Escola Politécnica da USP , nstituto de Pesquisas Tecnológicas – PT – e Universidade Nove de Julho), pela dedicação e empenho na revisão técnica do conteúdo. Material adicional A Sala irtual do livro (<sv.pearson.com.br>) oferece recursos adicionais que auxiliarão professores e alunos na exposição das aulas e no processo de aprendizagem. Para o professor: • Manual de soluções (em inglês) • Apresentações em Power Point Para o aluno: • Download de aplicativos (assembler e tracer) • Simulador gráfico para aplicações do Capítulo 4 • Sugestões de leitura para aprofundamento O material dos professores é protegido por senha. Para ter acesso a eles, os professores que adotam o livro devem entrar em contato com o seu representante Pearson ou enviar e-mail para [email protected].
  • 19. AST: Para Suzanne, Barbara, Marvin, Aron e Nathan. TA: Para Roberta, que criou espaço (e tempo) para eu terminar este projeto.
  • 20. Introduc a o capítulo 1 U m computador digital é uma máquina que pode resolver problemas para as pessoas, executando ins- truções que lhe são dadas. Uma sequência de instruções descrevendo como realizar determinada tarefa é chamada de programa. Os circuitos eletrônicos de cada computador podem reconhecer e executar diretamente um conjunto limitado de instruções simples, para o qual todos os programas devem ser converti- dos antes que possam ser executados. Essas instruções básicas raramente são muito mais complicadas do que Some dois números. erifique se um número é zero. Copie dados de uma parte da memória do computador para outra. Juntas, as instruções primitivas de um computador formam uma linguagem com a qual as pessoas podem se comunicar com ele. Essa linguagem é denominada linguagem de máquina. Quem projeta um novo computador deve decidir quais instruções incluir em sua linguagem de máquina. De modo geral, os projetistas tentam tor- nar as instruções primitivas as mais simples possíveis, coerentes com os requisitos de utilização e desempenho idealizados para o computador e seus requisitos de desempenho, a fim de reduzir a complexidade e o custo dos circuitos eletrônicos necessários. Como a maioria das linguagens de máquina é muito simples, sua utilização direta pelas pessoas é difícil e tediosa. Com o passar do tempo, essa observação simples tem levado a uma forma de estruturar os computadores como uma sequência de abstrações, cada uma baseada naquela abaixo dela. Desse modo, a complexidade pode ser dominada e os sistemas de computação podem ser projetados de forma sistemática e organizada. Denominamos essa abordagem organização estruturada de computadores – foi esse o nome dado a este livro. Na seção seguin- te, descreveremos o que significa esse termo. Logo após, comentaremos alguns desenvolvimentos históricos, o estado atual da tecnologia e exemplos importantes. Introduc a o 1 Cap tulo
  • 21. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 2 1.1 Organizac a o estruturada de computadores Como já mencionamos, existe uma grande lacuna entre o que é conveniente para as pessoas e o que é conve- niente para computadores. As pessoas querem fazer X, mas os computadores só podem fazer Y, o que dá origem a um problema. O objetivo deste livro é explicar como esse problema pode ser resolvido. 1.1.1 Linguagens, n veis e ma quinas virtuais O problema pode ser abordado de duas maneiras, e ambas envolvem projetar um novo conjunto de ins- truções que é mais conveniente para as pessoas usarem do que o conjunto embutido de instruções de máquina. Juntas, essas novas instruções também formam uma linguagem, que chamaremos de L1, assim como as instru- ções de máquina embutidas formam uma linguagem, que chamaremos de L0. As duas técnicas diferem no modo como os programas escritos em L1 são executados pelo computador que, afinal, só pode executar programas escritos em sua linguagem de máquina, L0. Um método de execução de um programa escrito em L1 é primeiro substituir cada instrução nele por uma sequência equivalente de instruções em L0. O programa resultante consiste totalmente em instruções L0. O com- putador, então, executa o novo programa L0 em vez do antigo programa L1. Essa técnica é chamada de tradução. A outra técnica é escrever um programa em L0 que considere os programas em L1 como dados de entrada e os execute, examinando cada instrução por sua vez, executando diretamente a sequência equivalente de ins- truções L0. Essa técnica não requer que se gere um novo programa em L0. Ela é chamada de interpretação, e o programa que a executa é chamado de interpretador. Tradução e interpretação são semelhantes. Nos dois métodos, o computador executa instruções em L1 executando sequências de instruções equivalentes em L0. A diferença é que, na tradução, o programa L1 inteiro primeiro é convertido para um L0, o programa L1 é desconsiderado e depois o novo L0 é carregado na memória do computador e executado. Durante a execução, o programa L0 recém-gerado está sendo executado e está no controle do computador. Na interpretação, depois que cada instrução L1 é examinada e decodificada, ela é executada de imediato. Nenhum programa traduzido é gerado. Aqui, o interpretador está no controle do computador. Para ele, o progra- ma L1 é apenas dados. Ambos os métodos e, cada vez mais, uma combinação dos dois, são bastante utilizados. Em vez de pensar em termos de tradução ou interpretação, muitas vezes é mais simples imaginar a existência de um computador hipotético ou máquina virtual cuja linguagem seja L1. amos chamar essa máquina virtual de M1 (e de M0 aquela correspondente a L0). Se essa máquina pudesse ser construída de forma barata o suficiente, não seria preciso de forma alguma ter a linguagem L0 ou uma máquina que executou os programas em L0. As pessoas poderiam simplesmente escrever seus programas em L1 e fazer com que o computador os executasse diretamente. Mesmo que a máquina virtual cuja linguagem é L1 seja muito cara ou complicada de construir com circuitos ele- trônicos, as pessoas ainda podem escrever programas para ela. Esses programas podem ser ou interpretados ou tra- duzidos por um programa escrito em L0 que, por si só, consegue ser executado diretamente pelo computador real. Em outras palavras, as pessoas podem escrever programas para máquinas virtuais, como se realmente existissem. Para tornar prática a tradução ou a interpretação, as linguagens L0 e L1 não deverão ser “muito” diferentes. Tal restrição significa quase sempre que L1, embora melhor que L0, ainda estará longe do ideal para a maioria das aplicações. Esse resultado talvez seja desanimador à luz do propósito original da criação de L1 – aliviar o trabalho do programador de ter que expressar algoritmos em uma linguagem mais adequada a máquinas do que a pessoas. Porém, a situação não é desesperadora. A abordagem óbvia é inventar outro conjunto de instruções que seja mais orientado a pessoas e menos orientado a máquinas que a L1. Esse terceiro conjunto também forma uma linguagem, que chamaremos de L2 (e com a máquina virtual M2). As pessoas podem escrever programas em L2 exatamente como se de fato existisse uma máquina real com linguagem de máquina L2. Esses programas podem ser traduzidos para L1 ou executados por um interpretador escrito em L1.
  • 22. C a p  t u l o 1 I n t r o d u c  a  o 3 A invenção de toda uma série de linguagens, cada uma mais conveniente que suas antecessoras, pode pros- seguir indefinidamente, até que, por fim, se chegue a uma adequada. Cada linguagem usa sua antecessora como base, portanto, podemos considerar um computador que use essa técnica como uma série de camadas ou níveis, um sobre o outro, conforme mostra a Figura 1.1. A linguagem ou nível mais embaixo é a mais simples, e a lin- guagem ou nível mais em cima é a mais sofisticada. Figura 1.1 Ma quina multin vel. Nível n Nível 3 Nível 2 Nível 1 Nível 0 Máquina virtual Mn, com linguagem de máquina Ln Máquina virtual M3, com linguagem de máquina L3 Máquina virtual M2, com linguagem de máquina L2 Máquina virtual M1, com linguagem de máquina L1 Computador real M0, com linguagem de máquina L0 Programas em Ln são interpretados por um interpretador rodando em uma máquina de nível inferior ou são traduzidos para a linguagem de máquina de uma máquina de nível inferior Programas em L2 são interpretados por interpretadores rodando em M1 ou M0, ou são traduzidos para L1 ou L0 Programas em L1 são interpretados por um interpretador rodando em M0, ou são traduzidos para L0 Programas em L0 podem ser executados diretamente pelos circuitos eletrônicos Há uma relação importante entre uma linguagem e uma máquina virtual. Cada máquina tem uma linguagem de máquina, consistindo em todas as instruções que esta pode executar. Com efeito, uma máquina define uma linguagem. De modo semelhante, uma linguagem define uma máquina – a saber, aquela que pode executar todos os programas escritos na linguagem. Claro, pode ser muito complicado e caro construir a máquina definida por determinada linguagem diretamente pelos circuitos eletrônicos, mas, apesar disso, podemos imaginá-la. Uma máquina que tivesse C ou C++ ou Java como sua linguagem seria de fato complexa, mas poderia ser construída usando a tecnologia de hoje. Porém, há um bom motivo para não construir tal computador: ele não seria econô- mico em comparação com outras técnicas. O mero fato de ser factível não é bom o suficiente: um projeto prático também precisa ser econômico. De certa forma, um computador com n níveis pode ser visto como n diferentes máquinas virtuais, cada uma com uma linguagem de máquina diferente. Usaremos os termos “nível” e “máquina virtual” para indicar a mesma coisa. Apenas programas escritos na linguagem L0 podem ser executados diretamente pelos circuitos eletrônicos, sem a necessidade de uma tradução ou interpretação intervenientes. Os programas escritos em L1, L2, ..., Ln devem ser interpretados por um interpretador rodando em um nível mais baixo ou traduzidos para outra lingua- gem correspondente a um nível mais baixo. Uma pessoa que escreve programas para a máquina virtual de nível n não precisa conhecer os interpretadores e tradutores subjacentes. A estrutura de máquina garante que esses programas, de alguma forma, serão execu- tados. Não há interesse real em saber se eles são executados passo a passo por um interpretador que, por sua vez, também é executado por outro interpretador, ou se o são diretamente pelos circuitos eletrônicos. O mesmo resultado aparece nos dois casos: os programas são executados. Quase todos os programadores que usam uma máquina de nível n estão interessados apenas no nível superior, aquele que menos se parece com a linguagem de máquina do nível mais inferior. Porém, as pessoas
  • 23. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 4 interessadas em entender como um computador realmente funciona deverão estudar todos os níveis. Quem pro- jeta novos computadores ou novos níveis também deve estar familiarizado com outros níveis além do mais alto. Os conceitos e técnicas de construção de máquinas como uma série de níveis e os detalhes dos próprios níveis formam o assunto principal deste livro. 1.1.2 Ma quinas multin veis contempora neas A maioria dos computadores modernos consiste de dois ou mais níveis. Existem máquinas com até seis níveis, conforme mostra a Figura 1.2. O nível 0, na parte inferior, é o hardware verdadeiro da máquina. Seus circuitos executam os programas em linguagem de máquina do nível 1. Por razões de precisão, temos que men- cionar a existência de outro nível abaixo do nosso nível 0. Esse nível, que não aparece na Figura 1.2 por entrar no domínio da engenharia elétrica (e, portanto, estar fora do escopo deste livro), é chamado de nível de dispo- sitivo. Nele, o projetista vê transistores individuais, que são os primitivos de mais baixo nível para projetistas de computador. Se alguém quiser saber como os transistores funcionam no interior, isso nos levará para o campo da física no estado sólido. Figura 1.2 Um computador com seis n veis. O me todo de suporte para cada n vel e  indicado abaixo dele (junto com o nome do programa que o suporta). Nível 5 Nível 4 Nível 3 Nível 2 Nível 1 Nível 0 Nível de linguagem orientada a problema Tradução (compilador) Nível de linguagem Assembly Tradução (assembler) Nível de máquina do sistema operacional Interpretação parcial (sistema operacional) Nível de arquitetura do conjunto de instrução Interpretação (microprograma) ou execução direta Nível de microarquitetura Hardware Nível lógico digital No nível mais baixo que estudaremos, o nível lógico digital, os objetos interessantes são chamados de por- tas (ou gates). Embora montadas a partir de componentes analógicos, como transistores, podem ser modeladas com precisão como dispositivos digitais. Cada porta tem uma ou mais entradas digitais (sinais representando 0 ou 1) e calcula como saída alguma função simples dessas entradas, como AND (E) ou OR (OU). Cada porta é composta de no máximo alguns transistores. Um pequeno número de portas podem ser combinadas para formar uma memória de 1 bit, que consegue armazenar um 0 ou um 1. As memórias de 1 bit podem ser combinadas em grupos de (por exemplo) 16, 32 ou 64 para formar registradores. Cada registrador pode manter um único número binário até algum máximo. As portas também podem ser combinadas para formar o próprio mecanismo de computação principal. Examinaremos as portas e o nível lógico digital com detalhes no Capítulo 3.
  • 24. C a p  t u l o 1 I n t r o d u c  a  o 5 O próximo nível acima é o nível de microarquitetura. Aqui, vemos uma coleção de (em geral) 8 a 32 regis- tradores que formam uma memória local e um circuito chamado UL  Unidade Lógica e rtitmética (em inglês rithmetic Logic Unit), que é capaz de realizar operações aritméticas simples. Os registradores estão conectados à ULA para formar um caminho de dados, sobre o qual estes fluem. A operação básica do caminho de dados con- siste em selecionar um ou dois registradores, fazendo com que a ULA opere sobre eles (por exemplo, somando- -os) e armazenando o resultado de volta para algum registrador. Em algumas máquinas, a operação do caminho de dados é controlada por um programa chamado micro- programa. Em outras, o caminho de dados é controlado diretamente pelo hardware. Nas três primeiras edições deste livro, chamamos esse nível de “nível de microprogramação”, pois no passado ele quase sempre era um interpretador de software. Como o caminho de dados agora quase sempre é (em parte) controlado diretamente pelo hardware, mudamos o nome na quarta edição. Em máquinas com controle do caminho de dados por software, o microprograma é um interpretador para as instruções no nível 2. Ele busca, examina e executa instruções uma por vez, usando o caminho de dados. Por exemplo, para uma instrução ADD, a instrução seria buscada, seus operandos localizados e trazidos para registra- dores, a soma calculada pela ULA e, por fim, o resultado retornado para o local a que pertence. Em uma máquina com controle do caminho de dados por hardware, haveria etapas semelhantes, mas sem um programa armazenado explícito para controlar a interpretação das instruções desse nível. Chamaremos o nível 2 de nível de arquitetura do conjunto de instrução, ou nível IS (Instruction Set rchitecture). Os fabricantes publicam um manual para cada computador que vendem, intitulado “Manual de Referência da Linguagem de Máquina”, ou “Princípios de Operação do Computador Western Wombat Modelo 100”, ou algo semelhante. Esses manuais, na realidade, referem-se ao nível SA, e não aos subjacen- tes. Quando eles explicam o conjunto de instruções da máquina, na verdade estão descrevendo as instruções executadas de modo interpretativo pelo microprograma ou circuitos de execução do hardware. Se um fabri- cante oferecer dois interpretadores para uma de suas máquinas, interpretando dois níveis SA diferentes, ele precisará oferecer dois manuais de referência da “linguagem de máquina”, um para cada interpretador. O próximo nível costuma ser híbrido. A maior parte das instruções em sua linguagem também está no nível SA. (Não há motivo pelo qual uma instrução que aparece em um nível não possa estar presente também em outros.) Além disso, há um conjunto de novas instruções, uma organização de memória diferente, a capacidade de executar dois ou mais programas simultaneamente e diversos outros recursos. Existe mais variação entre os projetos de nível 3 do que entre aqueles no nível 1 ou no nível 2. As novas facilidades acrescentadas no nível 3 são executadas por um interpretador rodando no nível 2, o qual, historicamente, tem sido chamado de sistema operacional. Aquelas instruções de nível 3 que são idênticas às do nível 2 são executadas direto pelo microprograma (ou controle do hardware), e não pelo sistema operacional. Em outras palavras, algumas das instruções de nível 3 são interpretadas pelo sistema operacional e algumas o são diretamente pelo microprograma. É a isso que chamamos de nível “híbrido”. No decorrer deste livro, nós o chamaremos de nível de máquina do sistema operacional. Há uma quebra fundamental entre os níveis 3 e 4. Os três níveis mais baixos não servem para uso do progra- mador do tipo mais comum. Em vez disso, eles são voltados principalmente para a execução dos interpretadores e tradutores necessários para dar suporte aos níveis mais altos. Esses interpretadores e tradutores são escritos pelos programadores de sistemas, profissionais que se especializam no projeto e execução de novas máquinas virtuais. Os níveis 4 e acima são voltados para o programador de aplicações, que tem um problema para solucionar. Outra mudança que ocorre no nível 4 é o método de suporte dos níveis mais altos. Os níveis 2 e 3 são sempre interpretados. Em geral, mas nem sempre, os níveis 4, 5 e acima são apoiados por tradução. Outra diferença entre níveis 1, 2 e 3, por um lado, e 4, 5 e acima, por outro, é a natureza da linguagem for- necida. As linguagens de máquina dos níveis 1, 2 e 3 são numéricas. Os programas nessas linguagens consistem em uma longa série de números, muito boa para máquinas, mas ruim para as pessoas. A partir do nível 4, as linguagens contêm palavras e abreviações cujo significado as pessoas entendem.
  • 25. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 6 O nível 4, o da linguagem de montagem (assembly), na realidade é uma forma simbólica para uma das lin- guagens subjacentes. Esse nível fornece um método para as pessoas escreverem programas para os níveis 1, 2 e 3 em uma forma que não seja tão desagradável quanto às linguagens de máquina virtual em si. Programas em linguagem de montagem são primeiro traduzidos para linguagem de nível 1, 2 ou 3, e em seguida interpretados pela máquina virtual ou real adequada. O programa que realiza a tradução é denominado assembler. O nível 5 normalmente consiste em linguagens projetadas para ser usadas por programadores de aplica- ções que tenham um problema a resolver. Essas linguagens costumam ser denominadas linguagens de alto nível. Existem literalmente centenas delas. Algumas das mais conhecidas são C, C++, Java, Perl, Python e PHP. Programas escritos nessas linguagens em geral são traduzidos para nível 3 ou nível 4 por tradutores conhecidos como compiladores, embora às vezes sejam interpretados, em vez de traduzidos. Programas em Java, por exem- plo, costumam ser primeiro traduzidos para uma linguagem semelhante à SA denominada código de bytes Java, ou bytecode Java, que é então interpretada. Em alguns casos, o nível 5 consiste em um interpretador para o domínio de uma aplicação específica, como matemática simbólica. Ele fornece dados e operações para resolver problemas nesse domínio em termos que pes- soas versadas nele possam entendê-lo com facilidade. Resumindo, o aspecto fundamental a lembrar é que computadores são projetados como uma série de níveis, cada um construído sobre seus antecessores. Cada nível representa uma abstração distinta na qual estão presen- tes diferentes objetos e operações. Projetando e analisando computadores desse modo, por enquanto podemos dispensar detalhes irrelevantes e assim reduzir um assunto complexo a algo mais fácil de entender. O conjunto de tipos de dados, operações e características de cada nível é denominado arquitetura. Ela trata dos aspectos que são visíveis ao usuário daquele nível. Características que o programador vê, como a quantidade de memória disponível, são parte da arquitetura. Aspectos de implementação, como o tipo da tecnologia usada para executar a memória, não são parte da arquitetura. O estudo sobre como projetar as partes de um sistema de computador que sejam visíveis para os programadores é denominado arquitetura de computadores. Na prática, contudo, arquitetura de computadores e organização de computadores significam basicamente a mesma coisa. 1.1.3 Evoluc a o de ma quinas multin veis Para colocar as máquinas multiníveis em certa perspectiva, examinaremos rapidamente seu desenvolvimento histórico, mostrando como o número e a natureza dos níveis evoluíram com o passar dos anos. Programas escri- tos em uma verdadeira linguagem de máquina (nível 1) de um computador podem ser executados diretamente pelos circuitos eletrônicos (nível 0) do computador, sem qualquer interpretador ou tradutor interveniente. Esses circuitos eletrônicos, junto com a memória e dispositivos de entrada/saída, formam o hardware do computador. Este consiste em objetos tangíveis – circuitos integrados, placas de circuito impresso, cabos, fontes de alimenta- ção, memórias e impressoras – em vez de ideias abstratas, algoritmos ou instruções. Por outro lado, o software consiste em algoritmos (instruções detalhadas que dizem como fazer algo) e suas representações no computador – isto é, programas. Eles podem ser armazenados em disco rígido, CD-ROM, ou outros meios, mas a essência do software é o conjunto de instruções que compõe os programas, e não o meio físico no qual estão gravados. Nos primeiros computadores, a fronteira entre hardware e software era nítida. Com o tempo, no entanto, essa fronteira ficou bastante indistinta, principalmente por causa da adição, remoção e fusão de níveis à medida que os computadores evoluíam. Hoje, muitas vezes é difícil distingui-la (ahid, 2003). Na verdade, um tema central deste livro é Hardware e software são logicamente equivalentes. Qualquer operação executada por software também pode ser embutida diretamente no hardware, de preferên- cia após ela ter sido suficientemente bem entendida. Como observou Karen Panetta: “Hardware é apenas software petrificado”. Claro que o contrário é verdadeiro: qualquer instrução executada em hardware também pode ser simulada em software. A decisão de colocar certas funções em hardware e outras em software é baseada em fatores
  • 26. C a p  t u l o 1 I n t r o d u c  a  o 7 como custo, velocidade, confiabilidade e frequência de mudanças esperadas. Existem poucas regras rigorosas e imutáveis para determinar que  deva ser instalado no hardware e Y deva ser programado explicitamente. Essas decisões mudam com as tendências econômicas, com a demanda e com a utilização de computadores. A invenc a o da microprogramac a o Os primeiros computadores digitais, na década de 1940, tinham apenas dois níveis: o nível SA, no qual era feita toda a programação, e o nível lógico digital, que executava esses programas. Os circuitos do nível lógico digital eram complicados, difíceis de entender e montar, e não confiáveis. Em 1951, Maurice Wilkes, pesquisador da Universidade de Cambridge, sugeriu projetar um computador de três níveis para simplificar de maneira drástica o hardware e assim reduzir o número de válvulas (pouco confiá- veis) necessárias (Wilkes, 1951). Essa máquina deveria ter um interpretador embutido, imutável (o micropro- grama), cuja função fosse executar programas de nível SA por interpretação. Como agora o hardware só teria de executar microprogramas, que tinham um conjunto limitado de instruções, em vez de programas de nível SA, cujos conjuntos de instruções eram muito maiores, seria necessário um número menor de circuitos eletrônicos. Uma vez que, na época, os circuitos eletrônicos eram compostos de válvulas eletrônicas, tal simplificação pro- metia reduzir o número de válvulas e, portanto, aumentar a confiabilidade (isto é, o número de falhas por dia). Poucas dessas máquinas de três níveis foram construídas durante a década de 1950. Outras tantas foram construídas durante a década de 1960. Em torno de 1970, a ideia de interpretar o nível SA por um micropro- grama, em vez de diretamente por meios eletrônicos, era dominante. Todas as principais máquinas da época a usavam. A invenc a o do sistema operacional Naqueles primeiros anos, grande parte dos computadores era “acessível a todos”, o que significava que o programador tinha de operar a máquina pessoalmente. Ao lado de cada máquina havia uma planilha de utiliza- ção. Um programador que quisesse executar um programa assinava a planilha e reservava um período de tempo, digamos, quarta-feira, das 3 às 5 da manhã (muitos programadores gostavam de trabalhar quando a sala onde a máquina estava instalada ficava tranquila). Quando chegava seu horário, o programador se dirigia à sala da máquina com um pacote de cartões perfurados de 80 colunas (um meio primitivo de entrada de dados) em uma das mãos e um lápis bem apontado na outra. Ao chegar à sala do computador, ele gentilmente levava até a porta o programador que lá estava antes dele e tomava posse da máquina. Se quisesse executar um programa em FORTRAN, o programador devia seguir estas etapas: 1. Ele1 se dirigia ao armário onde era mantida a biblioteca de programas, retirava o grande maço verde rotulado “compilador FORTRAN”, colocava-o na leitora de cartões e apertava o botão START. 2. Então, colocava seu programa FORTRAN na leitora de cartões e apertava o botão CONTNUE. O pro- grama era lido pela máquina. 3. Quando o computador parava, ele lia seu programa FORTRAN em um segundo momento. Embora alguns compiladores exigissem apenas uma passagem pela entrada, muitos demandavam duas ou mais. Para cada passagem, era preciso ler um grande maço de cartões. 4. Por fim, a tradução se aproximava da conclusão. Era comum o programador ficar nervoso perto do fim porque, se o compilador encontrasse um erro no programa, ele teria de corrigi-lo e começar todo o processo novamente. Se não houvesse erro, o compilador perfurava em cartões o programa traduzido para linguagem de máquina. 5. Então, o programador colocava o programa em linguagem de máquina na leitora de cartões, junto com o maço da biblioteca de sub-rotina, e lia ambos. 1 “Ele” deve ser entendido como “ele ou ela” em todo este livro.
  • 27. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 8 6. O programa começava a executar. Quase sempre não funcionava e parava de repente no meio. Em geral, o programador mexia um pouco nas chaves de controle e observava as luzes do console durante alguns instantes. Se tivesse sorte, conseguiria descobrir qual era o problema e corrigir o erro. Em seguida, voltava ao armário onde estava guardado o grande e verde compilador FORTRAN e começava tudo de novo. Se não tivesse tanta sorte, imprimia o conteúdo da memória, denominado de dump de memória, e o levava para casa a fim de estudá-lo. Esse procedimento, com pequenas variações, foi o normal em muitos centros de computação durante anos. Ele forçava os programadores a aprender como operar a máquina e o que fazer quando ela parava, o que acontecia com frequência. A máquina costumava ficar ociosa enquanto as pessoas carregavam cartões pela sala afora ou coçavam a cabeça tentando descobrir por que seus programas não estavam funcionando adequadamente. Por volta de 1960, as pessoas tentaram reduzir o desperdício de tempo automatizando o trabalho do opera- dor. Um programa denominado sistema operacional era mantido no computador o tempo todo. O programador produzia certos cartões de controle junto com o programa, que eram lidos e executados pelo sistema operacional. A Figura 1.3 apresenta uma amostra de serviço (job) para um dos primeiros sistemas operacionais de ampla uti- lização, o FMS (FORTRAN Monitor System), no BM 709. Figura 1.3 Amostra de servic o (job) para o sistema operacional FMS. Programa FORTRAN Cartões de dados *JOB, 5494, BARBARA *XEQ *FORTRAN *DATA *END O sistema operacional lia o cartão *JOB e usava a informação nele contida para fins de contabilidade. (O asterisco era usado para identificar cartões de controle, para que eles não fossem confundidos com cartões de programa e de dados.) Depois, o sistema lia o cartão *FORTRAN, que era uma instrução para carregar o com- pilador FORTRAN a partir de uma fita magnética. Então, o programa era lido para a máquina e compilava pelo programa FORTRAN. Quando o compiladorterminava, ele devolvia o controle ao sistema operacional, que então lia o cartão *DATA. sso era uma instrução para executar o programa traduzido, usando como dados os cartões que vinham após o cartão *DATA. Embora o sistema operacional fosse projetado para automatizar o trabalho do operador (daí seu nome), foi também o primeiro passo para o desenvolvimento de uma nova máquina virtual. O cartão *FORTRAN podia ser considerado uma instrução virtual “compilar programa”. De modo semelhante, o cartão *DATA podia ser con- siderado uma instrução virtual “executar programa”. Um nível que contivesse apenas duas instruções não era lá um grande nível, mas já era um começo. Nos anos seguintes, os sistemas operacionais tornaram-se cada vez mais sofisticados. Novas instruções, facili- dades e características foram adicionadas ao nível SA até que ele começou a parecer um novo nível. Algumas das
  • 28. C a p  t u l o 1 I n t r o d u c  a  o 9 instruções desse novo nível eram idênticas às do nível SA, mas outras, em particular as de entrada/saída, eram completamente diferentes. As novas instruções começaram a ficar conhecidas como macros de sistema operacio- nal ou chamadas do supervisor. Agora, o termo mais comum é chamada do sistema. Sistemas operacionais também se desenvolveram de outras maneiras. Os primeiros liam maços de cartões e imprimiam a saída na impressora de linha. Essa organização era conhecida como sistema batch. Em geral, havia uma espera de várias horas entre o momento em que um programa entrava na máquina e o horário em que os resultados ficavam prontos. Era difícil desenvolver software em tais circunstâncias. No início da década de 1960, pesquisadores do Dartmouth College, do MT e de outros lugares desenvol- veram sistemas operacionais que permitiam a vários programadores se comunicarem diretamente com o com- putador. Esses sistemas tinham terminais remotos conectados ao computador central por linhas telefônicas. O computador era compartilhado por muitos usuários. Um programador podia digitar um programa e obter os resultados impressos quase de imediato em seu escritório, na garagem de sua casa ou onde quer que o terminal estivesse localizado. Esses sistemas eram denominados sistemas de tempo compartilhado (ou timesharing). Nosso interesse em sistemas operacionais está nas partes que interpretam as instruções e características pre- sentes no nível 3 e que não estão presentes no nível SA, em vez de nos aspectos de compartilhamento de tempo. Embora não venhamos a destacar o fato, você sempre deve estar ciente de que os sistemas operacionais fazem mais do que apenas interpretar características adicionadas ao nível SA. Migrac a o de funcionalidade para microco digo Assim que a microprogramação se tornou comum (por volta de 1970), os projetistas perceberam que podiam acrescentar novas instruções simplesmente ampliando o microprograma. Em outras palavras, eles podiam acrescentar “hardware” (novas instruções de máquina) por programação. Essa revelação levou a uma explosão virtual de conjun- tos de instruções de máquina, pois os projetistas competiam uns com os outros para produzir conjuntos de ins- truções maiores e melhores. Muitas delas não eram essenciais considerando que seu efeito podia ser conseguido com facilidade pelas instruções existentes, embora às vezes fossem um pouco mais velozes do que uma sequência já existente. Por exemplo, muitas máquinas tinham uma instrução NC (NCrement) que somava 1 a um número. Como essas máquinas também tinham uma instrução geral ADD, não era necessário ter uma instrução especial para adicionar 1 (ou 720, se fosse o caso). Contudo, NC normalmente era um pouco mais rápida que ADD, e por isso foi inserida. Por essa razão, muitas outras instruções foram adicionadas ao microprograma. Entre elas, as mais frequentes eram: 1. nstruções para multiplicação e divisão de inteiros. 2. nstruções aritméticas para ponto flutuante. 3. nstruções para chamar e sair de procedimentos. 4. nstruções para acelerar laços (looping). 5. nstruções para manipular cadeias de caracteres. Além do mais, assim que os projetistas de máquinas perceberam como era fácil acrescentar novas instruções, começaram a procurar outras características para adicionar aos seus microprogramas. Alguns exemplos desses acréscimos são: 1. Características para acelerar cálculos que envolvessem vetores (indexação e endereçamento indireto). 2. Características para permitir que os programas fossem movidos na memória após o início da execução (facilidades de relocação). 3. Sistemas de interrupção que avisavam o computador tão logo uma operação de entrada ou saída estivesse concluída.
  • 29. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 10 4. Capacidade para suspender um programa e iniciar outro com um pequeno número de instruções (comutação de processos). 5. nstruções especiais para processar arquivos de áudio, imagem e multimídia. Diversas outras características e facilidades também foram acrescentadas ao longo dos anos, em geral para acelerar alguma atividade particular. Eliminac a o da microprogramac a o Os microprogramas engordaram durante os anos dourados da microprogramação (décadas de 1960 e 1970) e também tendiam a ficar cada vez mais lentos à medida que se tornavam mais volumosos. Por fim, alguns pes- quisadores perceberam que, eliminando o microprograma, promovendo uma drástica redução no conjunto de instruções e fazendo com que as restantes fossem executadas diretamente (isto é, controle do caminho de dados por hardware), as máquinas podiam ficar mais rápidas. Em certo sentido, o projeto de computadores fechou um círculo completo, voltando ao modo como era antes que Wilkes inventasse a microprogramação. Mas a roda continua girando. Processadores modernos ainda contam com a microprogramação para tradu- zir instruções complexas em microcódigo interno, que pode ser executado diretamente no hardware preparado para isso. O objetivo dessa discussão é mostrar que a fronteira entre hardware e software é arbitrária e muda cons- tantemente. O software de hoje pode ser o hardware de amanhã, e vice-versa. Além do mais, as fronteiras entre os diversos níveis também são fluidas. Do ponto de vista do programador, o modo como uma instrução é implementada não é importante, exceto, talvez, no que se refere à sua velocidade. Uma pessoa que esteja programando no nível SA pode usar sua instrução de “multiplicar” como se fosse uma instrução de hardware sem ter de se preocupar com ela ou até mesmo sem saber se ela é, na verdade, uma instrução de hardware. O hardware de alguém é o software de outrem. oltaremos a todos esses tópicos mais adiante neste livro. 1.2 Marcos da arquitetura de computadores Durante a evolução do computador digital moderno, foram projetados e construídos centenas de diferentes tipos de computadores. Grande parte já foi esquecida há muito tempo, mas alguns causaram um impacto sig- nificativo sobre as ideias modernas. Nesta seção, vamos apresentar um breve esboço de alguns dos principais desenvolvimentos históricos, para entender melhor como chegamos onde estamos agora. Nem é preciso dizer que esta seção apenas passa por alto os pontos de maior interesse e deixa muita coisa de fora. A Figura 1.4 apresenta algumas máquinas que marcaram época e que serão discutidas nesta seção. Slater (1987) é uma boa referência de consulta para quem quiser material histórico adicional sobre as pessoas que inauguraram a era do computador. Biografias curtas e belas fotos em cores, de autoria de Louis Fabian Bachrach, de alguns dos principais fundadores da era do computador são apresentadas no livro de arte de Morgan (1997). 1.2.1 A gerac a o zero  computadores meca nicos (16421945) A primeira pessoa a construir uma máquina de calcular operacional foi o cientista francês Blaise Pascal (1623–1662), em cuja honra a linguagem Pascal foi batizada. Esse dispositivo, construído em 1642, quando Pascal tinha apenas 19 anos, foi projetado para ajudar seu pai, um coletor de impostos do governo francês. Era inteiramente mecânico, usava engrenagens e funcionava com uma manivela operada à mão.
  • 30. C a p  t u l o 1 I n t r o d u c  a  o 11 Figura 1.4 Alguns marcos no desenvolvimento do computador digital moderno. Ano Nome Construído por Comentários 1834 Máquina analítica Babbage Primeira tentativa de construir um computador digital 1936 Z1 Zuse Primeira máquina de calcular com relés 1943 COLOSSUS Governo britânico Primeiro computador eletrônico 1944 Mark I Aiken Primeiro computador norte-americano de uso geral 1946 ENIAC Eckert/Mauchley A história moderna dos computadores começa aqui 1949 EDSAC Wilkes Primeiro computador com programa armazenado 1951 Whirlwind I MIT Primeiro computador de tempo real 1952 IAS von Neumann A maioria das máquinas atuais usa esse projeto 1960 PDP-1 DEC Primeiro minicomputador (50 vendidos) 1961 1401 IBM Máquina para pequenos negócios, com enorme popularidade 1962 7094 IBM Dominou computação científica no início da década de 1960 1963 B5000 Burroughs Primeira máquina projetada para uma linguagem de alto nível 1964 360 IBM Primeira linha de produto projetada como uma família 1964 6600 CDC Primeiro supercomputador científico 1965 PDP-8 DEC Primeiro minicomputador de mercado de massa (50 mil vendidos) 1970 PDP-11 DEC Dominou os minicomputadores na década de 1970 1974 8080 Intel Primeiro computador de uso geral de 8 bits em um chip 1974 CRAY-1 Cray Primeiro supercomputador vetorial 1978 VAX DEC Primeiro superminicomputador de 32 bits 1981 IBM PC IBM Deu início à era moderna do computador pessoal 1981 Osborne-1 Osborne Primeiro computador portátil 1983 Lisa Apple Primeiro computador pessoal com uma GUI 1985 386 Intel Primeiro ancestral de 32 bits da linha Pentium 1985 MIPS MIPS Primeira máquina comercial RISC 1985 XC2064 Xilinx Primeiro FPGA (Field-Programmable Gate Array) 1987 SPARC Sun Primeira estação de trabalho RISC baseada em SPARC 1989 GridPad Grid Systems Primeiro computador tablet comercial 1990 RS6000 IBM Primeira máquina superescalar 1992 Alpha DEC Primeiro computador pessoal de 64 bits 1992 Simon IBM Primeiro smartphone 1993 Newton Apple Primeiro computador palmtop (PDA) 2001 POWER4 IBM Primeiro multiprocessador com chip dual core
  • 31. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 12 A máquina de Pascal podia efetuar apenas operações de adição e subtração, mas 30 anos mais tarde o grande matemático alemão, barão Gottfried Wilhelm von Leibniz (1646–1716), construiu uma outra máquina mecânica que também podia multiplicar e dividir. Na verdade, Leibniz construiu o equivalente a uma calculadora de bolso de quatro operações três séculos atrás. Durante 150 anos nada de muito importante aconteceu, até que um professor de matemática da Universidade de Cambridge, Charles Babbage (1792–1871), o inventor do velocímetro, projetou e construiu sua primeira máqui- na diferencial. Esse dispositivo mecânico que, assim como o de Pascal, só podia somar e subtrair, foi projetado para calcular tabelas de números úteis para a navegação marítima. Toda a construção da máquina foi projetada para exe- cutar um único algoritmo, o método de diferenças finitas que usava polinômios. A característica mais interessante dessa máquina era seu método de saída: ela perfurava seus resultados sobre uma chapa de gravação de cobre com uma punção de aço, prenunciando futuros meios de escrita única como cartões perfurados e CD-ROMs. Embora o dispositivo funcionasse razoavelmente bem, Babbage logo se cansou dessa máquina que só podia exe- cutar um único algoritmo. Ele começou a gastar quantidades cada vez maiores de seu tempo e da fortuna da família (sem falar nas 17 mil libras do governo) no projeto e na construção de uma sucessora denominada máquina ana- lítica. A máquina analítica tinha quatro componentes: a armazenagem (memória), o moinho (unidade de cálculo), a seção de entrada (leitora de cartões perfurados) e a seção de saída (saída perfurada e impressa). A armazenagem consistia em 1.000 palavras de 50 algarismos decimais, cada uma usada para conter variáveis e resultados. O moinho podia aceitar operandos da armazenagem e então os somava, subtraía, multiplicava ou dividia e, por fim, devolvia o resultado à armazenagem. Assim como a máquina diferencial, ela era inteiramente mecânica. O grande avanço da máquina analítica era ser de uso geral. Lia instruções de cartões perfurados e as execu- tava. Algumas instruções mandavam a máquina buscar dois números na armazenagem, trazê-los até o moinho, efetuar uma operação com eles (por exemplo, adição) e enviar o resultado de volta para a armazenagem. Outras podiam testar um número e desviá-lo condicionalmente, dependendo se ele era positivo ou negativo. Perfurando um programa diferente nos cartões de entrada, era possível fazer com que a máquina analítica realizasse cálculos diversos, o que não acontecia com a máquina diferencial. isto que a máquina analítica era programável em uma linguagem de montagem simples, ela precisava de software. Para produzi-lo, Babbage contratou uma jovem de nome Ada Augusta Lovelace, que era filha do famoso poeta britânico Lord Byron. Assim, Ada Lovelace foi a primeira programadora de computadores do mundo. A linguagem de programação Ada tem esse nome em sua homenagem. nfelizmente, assim como muitos projetistas modernos, Babbage nunca conseguiu depurar o hardware por completo. O problema era que ele precisava de milhares e milhares de dentes e rodas e engrenagens produzidos com um grau de precisão que a tecnologia do século  não podia oferecer. Ainda assim, suas ideias estavam muito à frente de sua época e, até hoje, a maioria dos computadores modernos tem uma estrutura muito semelhante à da máquina analítica; portanto, é mais do que justo dizer que Babbage foi avô do computador digital moderno. O próximo desenvolvimento importante ocorreu no final da década de 1930, quando um estudante de enge- nharia alemão chamado Konrad Zuse construiu uma série de máquinas calculadoras automáticas usando relés eletromagnéticos. Ele não conseguiu financiamento do governo após o início da guerra porque os burocratas governamentais esperavam ganhar a guerra tão rapidamente que a nova máquina só estaria pronta após o término do conflito. Zuse não conhecia o trabalho de Babbage, e suas máquinas foram destruídas pelo bombardeio aliado de Berlim em 1944, portanto, seu trabalho não teve influência alguma sobre as máquinas subsequentes. Mesmo assim, ele foi um dos pioneiros da área. Um pouco mais tarde, nos Estados Unidos, duas pessoas também projetaram calculadoras, John Atanasoff no owa State College e George Stibbitz no Bell Labs. A máquina de Atanasoff era surpreendentemente avançada para sua época. Usava aritmética binária e a memória era composta de capacitores recarregados periodicamente para impedir fuga de carga, um processo que ele denominou “sacudir a memória”. Os chips modernos de memória dinâmica (DRAM) funcionam desse mesmo modo. nfelizmente, a máquina nunca se tornou operacional de fato. De certo modo, Atanasoff era como Babbage: um visionário que acabou derrotado pela tecnologia de hardware inadequada que existia em seu tempo.
  • 32. C a p  t u l o 1 I n t r o d u c  a  o 13 O computador de Stibbitz, embora mais primitivo do que o de Atanasoff, funcionou de verdade. Stibbitz fez uma grande demonstração pública de sua máquina durante uma conferência no Dartmouth College em 1940. Uma dos presentes era John Mauchley, desconhecido professor de física da Universidade da Pensilvânia. Mais tarde, o mundo da computação ouviria mais a respeito do professor Mauchley. Enquanto Zuse, Stibbitz e Atanasoff projetavam calculadoras automáticas, um jovem chamado Howard Aiken remoía tediosos cálculos numéricos à mão como parte de sua pesquisa de doutorado em Harvard. Depois de concluído o doutorado, Aiken reconheceu a importância de fazer cálculos à máquina. Foi à biblioteca, desco- briu o trabalho de Babbage e decidiu construir com relés o computador de uso geral que ele não tinha conseguido construir com rodas dentadas. A primeira máquina de Aiken, a Mark , foi concluída em Harvard em 1944. Tinha 72 palavras de 23 algaris- mos decimais cada e um tempo de instrução de 6 s. A entrada e a saída usavam fita de papel perfurada. Quando Aiken concluiu o sucessor dessa máquina, a Mark , os computadores de relés já eram obsoletos. A era eletrônica tinha começado. 1.2.2 A primeira gerac a o  va lvulas (19451955) O estímulo para o computador eletrônico foi a Segunda Guerra Mundial. Durante a fase inicial do conflito, submarinos alemães causavam estragos em navios britânicos. As instruções de comando dos almirantes em Berlim eram enviadas aos submarinos por rádio, as quais os britânicos podiam interceptar – e interceptavam. O problema era que as mensagens eram codificadas usando um dispositivo denominado ENIGM, cujo antecessor foi proje- tado pelo inventor amador e outrora presidente dos Estados Unidos, Thomas Jefferson. Logo no início da guerra, a inteligência britânica conseguiu adquirir uma máquina ENGMA da inteligência polo- nesa, que a tinha roubado dos alemães2 . Contudo, para decifrar uma mensagem codificada era preciso uma quantidade enorme de cálculos e, para a mensagem ser de alguma utilidade, era necessário que esse cálculo fosse concluído logo depois de ela ter sido interceptada. Para decodificar essas mensagens, o governo britânico montou um laboratório ultrassecreto que construiu um computador eletrônico denominado COLOSSUS. O famoso matemático britânico Alan Turing ajudou a projetar essa máquina. Esse computador funcionava desde 1943, mas, uma vez que o governo britâ- nico guardou praticamente todos os aspectos do projeto como segredo militar durante 30 anos, a linha COLOSSUS foi um beco sem saída. Só vale a pena citá-lo por ter sido o primeiro computador digital eletrônico do mundo. Além de destruir as máquinas de Zuse e estimular a construção do COLOSSUS, a guerra também afetou a computação nos Estados Unidos. O exército precisava de tabelas de alcance visando sua artilharia pesada, e as produzia contratando centenas de mulheres para fazer os cálculos necessários com calculadoras de mão (as mulheres eram consideradas mais precisas que os homens). Ainda assim, o processo era demorado e surgiam erros com frequência. John Mauchley, que conhecia o trabalho de Atanasoff, bem como o de Stibbitz, sabia que o exército estava interessadoemcalculadorasmecânicas.Comomuitoscientistasdacomputaçãoquevieramdepoisdele,Mauchley montou uma proposta solicitando ao exército financiamento para a construção de um computador eletrônico. A proposta foi aceita em 1943, e Mauchley e seu aluno de pós-graduação, J. Presper Eckert, passaram a construir um computador eletrônico, ao qual deram o nome de ENIC (Electronic Numerical Integrator nd Computer  integrador e computador numérico eletrônico). O ENAC consistia em 18 mil válvulas e 1.500 relés, pesava 30 toneladas e consumia 140 kw de energia. Em termos de arquitetura, a máquina tinha 20 registradores, cada um com capacidade para conter um número decimal de 10 algarismos. (Um registrador decimal é uma memória muito pequena que pode conter desde um número até outro número máximo de casas decimais, mais ou menos como o odômetro, que registra quanto um carro rodou em seu tempo de vida útil.) O ENAC era programado com o ajuste de até 6 mil interruptores multiposição e com a conexão de uma imensa quan- tidade de soquetes com uma verdadeira floresta de cabos de interligação. 2 N. do RT: Antes da guerra, os alemães vendiam uma versão comercial da ENIGMA com três engrenagens, modelo igual ao que os poloneses passaram aos ingleses. A versão militar possuía quatro engrenagens. Em: Stephen Budiansky. Battle of Wits  The complete story of codebreaking in World War II. Penguin Books Ltd.: Londres, 2000.
  • 33. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 14 A construção da máquina só foi concluída em 1946, tarde demais para ser de alguma utilidade em relação a seu propósito original. Todavia, como a guerra tinha acabado, Mauchley e Eckert receberam permissão para organizar um curso de verão para descrever seu trabalho para seus colegas cientistas. Aquele curso de verão foi o início de uma explosão de interesse na construção de grandes computadores digitais. Após aquele curso de verão histórico, outros pesquisadores se dispuseram a construir computadores ele- trônicos. O primeiro a entrar em operação foi o EDSAC (1949), construído na Universidade de Cambridge por Maurice Wilkes. Entre outros, figuravam JOHNNAC, da Rand Corporation; o LLAC, da Universidade de llinois; o MANAC, do Los Alamos Laboratory; e o WEZAC, do Weizmann nstitute em srael. Eckert e Mauchley logo começaram a trabalhar em um sucessor, o EVC (Electronic iscrete Variable utomatic Computer). Contudo, o projeto ficou fatalmente comprometido quando eles deixaram a Universidade da Pensilvânia para fundar uma empresa nova, a Eckert-Mauchley Computer Corporation, na Filadélfia. (O ale do Silício ainda não tinha sido inventado.) Após uma série de fusões, a empresa se tornou a moderna Unisys Corporation. Como um aporte legal, Eckert e Mauchley solicitaram uma patente alegando que haviam inventado o compu- tador digital. Em retrospecto, possuir essa patente não seria nada mau. Após anos de litígio, o tribunal decidiu que a patente de Eckert-Mauchley era inválida e que John Atanasoff tinha inventado o computador digital, embora nunca o tivesse patenteado, colocando efetivamente a invenção em domínio público. Enquanto Eckert e Mauchley trabalhavam no EDAC, uma das pessoas envolvidas no projeto ENAC, John von Neumann, foi para o nstitute of Advanced Studies de Princeton para construir sua própria versão do EDAC, a máquina IS. on Neumann era um gênio, da mesma estirpe de Leonardo da inci. Falava muitos idiomas, era especialista em ciências físicas e matemática e guardava na memória tudo o que já tinha ouvido, visto ou lido. Conseguia citar sem consulta, palavra por palavra, o texto de livros que tinha lido anos antes. Na época em que se interessou por computadores, já era o mais eminente matemático do mundo. Uma das coisas que logo ficou óbvia para ele foi que programar computadores com quantidades imensas de interruptores e cabos era uma tarefa lenta, tediosa e inflexível. Ele percebeu que o programa podia ser represen- tado em forma digital na memória do computador, junto com os dados. Também viu que a desajeitada aritmética decimal serial usada pelo ENAC, com cada dígito representado por 10 válvulas (1 acesa e 9 apagadas), podia ser substituída por aritmética binária paralela, algo que Atanasoff tinha percebido anos antes. O projeto básico, o primeiro que ele descreveu, agora é conhecido como máquina de von Neumann. Ela foi usada no EDSAC, o primeiro computador de programa armazenado, e agora, mais de meio século depois, ainda é a base de quase todos os computadores digitais. Esse projeto – e a máquina AS, construída em colaboração com Herman Goldstine – teve uma influência tão grande que vale a pena descrevê-lo rapidamente. Embora o nome de von Neumann esteja sempre ligado a esse projeto, Goldstine e outros também lhe deram grande contribuição. Um esboço da arquitetura é dado na Figura 1.5. Figura 1.5 Ma quina original de von Neumann. Memória Unidade de controle Unidade de lógica e aritmética Acumulador Entrada Saída
  • 34. C a p  t u l o 1 I n t r o d u c  a  o 15 A máquina de von Neumann tinha cinco partes básicas: a memória, a unidade de lógica e aritmética, a unidade de controle e o equipamento de entrada e saída. A memória consistia em 4.096 palavras, uma palavra contendo 40 bits, cada bit sendo 0 ou 1. Cada palavra continha ou duas instruções de 20 bits ou um inteiro de 40 bits com sinal. As instruções tinham 8 bits dedicados a identificar o tipo da instrução e 12 bits para especificar uma das 4.096 palavras de memória. Juntas, a unidade de lógica e aritmética e a unidade de controle formavam o “cérebro” do computador. Em computadores modernos, elas são combinadas em um único chip, denominado CPU (Central Processing Unit  unidade central de processamento). Dentro da unidade de lógica e aritmética havia um registrador interno especial de 40 bits, denominado acu- mulador. Uma instrução típica adicionava uma palavra de memória ao acumulador ou armazenava o conteúdo deste na memória. A máquina não tinha aritmética de ponto flutuante porque von Neumann achava que qualquer matemático competente conseguiria acompanhar o ponto decimal (na verdade, o ponto binário) de cabeça. Mais ou menos ao mesmo tempo em que von Neumann construía sua máquina AS, pesquisadores do MT também estavam construindo um computador. Diferente do AS, do ENAC e de outras máquinas desse tipo, cujas palavras tinham longos comprimentos e eram destinadas a cálculos numéricos pesados, a máquina do MT, a Whirlwind , tinha uma palavra de 16 bits e era projetada para controle em tempo real. Esse projeto levou à inven- ção da memória de núcleo magnético por Jay Forrester e, depois, por fim, ao primeiro minicomputador comercial. Enquanto tudo isso estava acontecendo, a BM era uma pequena empresa dedicada ao negócio de produzir perfuradoras de cartões e máquinas mecânicas de classificação de cartões. Embora tenha contribuído para o finan- ciamento de Aiken, a BM não estava muito interessada em computadores até que produziu o 701 em 1953, muito tempo após a empresa de Eckert e Mauchley ter alcançado o posto de número um no mercado comercial, com seu computador UNAC. O 701 tinha 2.048 palavras de 36 bits, com duas instruções por palavra. Foi o primeiro de uma série de máquinas científicas que vieram a dominar o setor dentro de uma década. Três anos mais tarde, apareceu o 704 que, de início, tinha 4.096 palavras de memória de núcleos, instruções de 36 bits e uma inovação: hardware de ponto flutuante. Em 1958, a BM começou a produzir sua última máquina de válvulas, a 709, que era basicamente um 704 incrementado. 1.2.3 A segunda gerac a o  transistores (19551965) O transistor foi inventado no Bell Labs em 1948 por John Bardeen, Walter Brattain e William Shockley, pelo qual receberam o Prêmio Nobel de física de 1956. Em dez anos, o transistor revolucionou os computadores e, ao final da década de 1950, os computadores de válvulas estavam obsoletos. O primeiro computador transistorizado foi construído no Lincoln Laboratory do MT, uma máquina de 16 bits na mesma linha do Whirlwind . Recebeu o nome de X-0 (ransistorized eXperimental computer 0  computador transistorizado experimental 0), e a intenção era usá-la apenas como dispositivo para testar o muito mais elegante T-2. O T-2 nunca foi um grande sucesso, mas um dos engenheiros que trabalhava no laboratório, Kenneth Olsen, fundou uma empresa, a Digital Equipment Corporation (DEC), em 1957, para fabricar uma máquina comercial muito parecida com o T-0. Quatro anos se passaram antes que tal máquina, o PDP-1, aparecesse, principalmente porque os investidores de risco que fundaram a DEC estavam convictos de que não havia merca- do para computadores. Afinal, T. J. Watson, antigo presidente da BM, certa vez dissera que o mercado mundial de computadores correspondia a cerca de quatro ou cinco unidades. Em vez de computadores, a DEC vendia pequenas placas de circuitos. Quando o PDP-1 finalmente apareceu em 1961, tinha 4.096 palavras de 18 bits e podia executar 200 mil ins- truções por segundo. Esse desempenho era a metade do desempenho do BM 7090, o sucessor transistorizado do 709 e o computador mais rápido do mundo na época. O PDP-1 custava 120 mil dólares; o 7090 custava milhões. A DEC vendeu dezenas de PDP-1s, e nascia a indústria de minicomputadores. Um dos primeiros PDP-1s foi dado ao MT, onde logo atraiu a atenção de alguns novos gênios em aprimo- ramento tão comuns ali. Uma das muitas inovações do PDP-1 era um visor e a capacidade de plotar pontos em qualquer lugar de sua tela de 512 por 512. Em pouco tempo, os estudantes já tinham programado o PDP-1 para jogar Spacewar, e o mundo teria ganhado seu primeiro videogame.
  • 35. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 16 Alguns anos mais tarde, a DEC lançou o PDP-8, que era uma máquina de 12 bits, porém muito mais barata que o PDP-1 (16 mil dólares). O PDP-8 tinha uma importante inovação: um barramento único, o omnibus, con- forme mostra a Figura 1.6. Um barramento é um conjunto de fios paralelos usados para conectar os componen- tes de um computador. Essa arquitetura foi uma ruptura importante em relação à arquitetura da máquina AS, centrada na memória, e, desde então, foi adotada por quase todos os computadores de pequeno porte. A DEC alcançou a marca de 50 mil PDP-8 vendidos, o que a consolidou como a líder no negócio de minicomputadores. Figura 1.6 Barramento omnibus do PDP-8. CPU Memória Terminal de console E/S de fita de papel Outra E/S Omnibus Enquanto isso, a reação da BM ao transistor foi construir uma versão transistorizada do 709, o 7090, como já mencionamos, e, mais tarde, o 7094. Esse último tinha um tempo de ciclo de 2 microssegundos e 32.768 pala- vras de 36 bits de memória de núcleos. O 7090 e o 7094 marcaram o final das máquinas do tipo ENAC, mas dominaram a computação científica durante anos na década de 1960. Ao mesmo tempo em que se tornava uma grande força na computação científica com o 7094, a BM estava ganhando muito dinheiro com a venda de uma pequena máquina dirigida para empresas, denominada 1401. Essa máquina podia ler e escrever fitas magnéticas, ler e perfurar cartões, além de imprimir saída de dados quase tão rapidamente quanto o 7094, e por uma fração do preço dele. Era terrível para a computação científica, mas per- feita para manter registros comerciais. O 1401 era fora do comum porque não tinha nenhum registrador, nem mesmo um comprimento de palavra fixo. Sua memória tinha 4 mil bytes de 8 bits, embora modelos posteriores suportassem até incríveis 16 mil bytes. Cada byte continha um caractere de 6 bits, um bit administrativo e um bit para indicar o final da palavra. Uma instrução MOE, por exemplo, tinha um endereço-fonte e um endereço-destino, e começava a transferir bytes da fonte ao destino até encontrar um bit de final com valor 1. Em 1964, uma minúscula e desconhecida empresa, a Control Data Corporation (CDC), lançou a 6600, uma máquina que era cerca de uma ordem de grandeza mais rápida do que a poderosa 7094 e qualquer outra existente na época. Foi amor à primeira vista para os calculistas, e a CDC partiu a caminho do sucesso. O segredo de sua velocidade e a razão de ser tão mais rápida do que a 7094 era que, dentro da CPU, havia uma máquina com alto grau de paralelismo. Ela tinha diversas unidades funcionais para efetuar adições, outras para efetuar multiplica- ções e ainda mais uma para divisão, e todas elas podiam funcionar em paralelo. Embora extrair o melhor dessa máquina exigisse cuidadosa programação, com um pouco de trabalho era possível executar dez instruções ao mesmo tempo. Como se não bastasse, a 6600 tinha uma série de pequenos computadores internos para ajudá-la, uma espé- cie de “Branca de Neve e as Sete Pessoas erticalmente Prejudicadas”. sso significava que a CPU podia gastar todo o seu tempo processando números, deixando todos os detalhes de gerenciamento de jobs e entrada/saída para os computadores menores. Em retrospecto, a 6600 estava décadas à frente de sua época. Muitas das ideias fundamentais encontradas em computadores modernos podem ser rastreadas diretamente até ela. O projetista da 6600, Seymour Cray, foi uma figura legendária, da mesma estatura de von Neumann. Ele dedicou sua vida inteira à construção de máquinas cada vez mais rápidas, denominadas então de supercomputa- dores, incluindo a 6600, 7600 e Cray-1. Também inventou o famoso algoritmo para comprar carros: vá à conces-
  • 36. C a p  t u l o 1 I n t r o d u c  a  o 17 sionária mais próxima de sua casa, aponte para o carro mais próximo da porta e diga: “ou levar aquele”. Esse algoritmo gasta o mínimo de tempo em coisas sem importância (como comprar carros) para deixar o máximo de tempo livre para fazer coisas importantes (como projetar supercomputadores). Havia muitos outros computadores nessa época, mas um se destaca por uma razão bem diferente e que vale a pena mencionar: o Burroughs B5000. Os projetistas de máquinas como PDP-1, 7094 e 6600 estavam totalmente preocupados com o hardware, seja para que ficassem mais baratos (DEC) ou mais rápidos (BM e CDC). O software era praticamente irrelevante. Os projetistas do B5000 adotaram uma linha de ação diferente. Construíram uma máquina com a intenção específica de programá-la em linguagem Algol 60, uma precursora da C e da Java, e incluíram muitas características no hardware para facilitar a tarefa do compilador. Nascia a ideia de que o software também era importante. nfelizmente, ela foi esquecida quase de imediato. 1.2.4 A terceira gerac a o  circuitos integrados (19651980) A invenção do circuito integrado de silício por Jack Kilby e Robert Noyce (trabalhando independentemente) em 1958 permitiu que dezenas de transistores fossem colocados em um único chip. Esse empacotamento possi- bilitava a construção de computadores menores, mais rápidos e mais baratos do que seus precursores transistori- zados. Alguns dos computadores mais significativos dessa geração são descritos a seguir. Em 1964, a BM era a empresa líder na área de computadores e tinha um grande problema com suas duas máquinas de grande sucesso, a 7094 e a 1401: elas eram tão incompatíveis quanto duas máquinas podem ser. Uma era uma processadora de números de alta velocidade, que usava aritmética binária em registradores de 36 bits; a outra, um processador de entrada/saída avantajado, que usava aritmética decimal serial sobre palavras de comprimento variável na memória. Muitos de seus clientes empresariais tinham ambas e não gostavam da ideia de ter dois departamentos de programação sem nada em comum. Quando chegou a hora de substituir essas duas séries, a BM deu um passo radical. Lançou uma única linha de produtos, a linha System/360, baseada em circuitos integrados e projetada para computação científica e tam- bém comercial. A linha System/360 continha muitas inovações, das quais a mais importante era ser uma família de uma meia dúzia de máquinas com a mesma linguagem de montagem e tamanho e capacidade crescentes. Uma empresa poderia substituir seu 1401 por um 360 Modelo 30 e seu 7094 por um 360 Modelo 75. O Modelo 75 era maior e mais rápido (e mais caro), mas o software escrito para um deles poderia, em princípio, ser executado em outro. Na prática, o programa escrito para um modelo pequeno seria executado em um modelo grande sem problemas. Porém, a recíproca não era verdadeira. Quando transferido para uma máquina menor, o programa escrito para um modelo maior poderia não caber na memória. Ainda assim, era uma importante melhoria em relação à situação do 7094 e do 1401. A ideia de famílias de máquinas foi adotada de pronto e, em poucos anos, a maioria dos fabricantes de computadores tinha uma família de máquinas comuns que abrangiam uma ampla faixa de preços e desempenhos. Algumas características da primeira família 360 são mostradas na Figura 1.7. Mais tarde, foram lançados outros modelos. Figura 1.7 Oferta inicial da linha de produtos IBM 360. Propriedade Modelo 30 Modelo 40 Modelo 50 Modelo 65 Desempenho relativo 1 3,5 10 21 Tempo de ciclo (em bilionésimos de segundo) 1.000 625 500 250 Memória máxima (bytes) 65.536 262.144 262.144 524.288 Bytes lidos por ciclo 1 2 4 16 Número máximo de canais de dados 3 3 4 6
  • 37. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 18 Outra importante inovação da linha 360 era a multiprogramação, com vários programas na memória ao mesmo tempo, de modo que, enquanto um esperava por entrada/saída para concluir sua tarefa, outro podia exe- cutar, o que resultava em uma utilização mais alta da CPU. A 360 também foi a primeira máquina que podia emular (simular) outros computadores. Os modelos meno- res podiam emular a 1401, e os maiores podiam emular a 7094, de maneira que os clientes podiam continuar a executar seus antigos programas binários sem modificação durante a conversão para a 360. Alguns modelos exe- cutavam programas 1401 com uma rapidez tão maior que a própria 1401 que muitos clientes nunca converteram seus programas. A emulação era fácil na 360 porque todos os modelos iniciais e grande parte dos que vieram depois eram microprogramados. Bastava que a BM escrevesse três microprogramas: um para o conjunto nativo de instruções da 360, um para o conjunto de instruções da 1401 e outro para o conjunto de instruções da 7094. Essa flexibili- dade foi uma das principais razões para a introdução da microprogramação na 360. É lógico que a motivação de Wilkes para reduzir a quantidade de válvulas não importava mais, pois a 360 não tinha válvula alguma. A 360 resolveu o dilema “binária paralela” versus “decimal serial” com uma solução conciliatória: a máquina tinha 16 registradores de 32 bits para aritmética binária, mas sua memória era orientada para bytes, como a da 1401. Também tinha instruções seriais no estilo da 1401 para movimentar registros de tamanhos variáveis na memória. Outra característica importante da 360 era (para a época) um imenso espaço de endereçamento de 224 (16.777.216) bytes. Como naquele tempo a memória custava vários dólares por byte, esse tanto de memória parecia uma infinidade. nfelizmente, a série 360 foi seguida mais tarde pelas séries 370, 4300, 3080, 3090, 390 e a série z, todas usando basicamente a mesma arquitetura. Em meados da década de 1980, o limite de memória tornou-se um problema real e a BM teve de abandonar a compatibilidade em parte, quando mudou para endere- ços de 32 bits necessários para endereçar a nova memória de 232 bytes. Com o benefício de uma percepção tardia, podemos argumentar que, uma vez que de qualquer modo tinham palavras e registros de 32 bits, provavelmente também deveriam ter endereços de 32 bits, mas na época ninguém podia imaginar uma máquina com 16 milhões de bytes de memória. Embora a transição para endereços de 32 bits tenha sido bem-sucedida para a BM, essa mais uma vez foi apenas uma solução temporária para o problema do endereçamento de memória, pois os sistemas de computação logo exigiriam a capacidade de endereçar mais de 232 (4.294.967.296) bytes de memória. Dentro de mais alguns anos, entrariam em cena os computadores com endereços de 64 bits. O mundo dos minicomputadores também avançou um grande passo na direção da terceira geração quando a DEC lançou a série PDP-11, um sucessor de 16 bits do PDP-8. Sob muitos aspectos, a série PDP-11 era como um irmão menor da série 360, tal como o PDP-1 era um irmãozinho da 7094. Ambos, 360 e PDP-11, tinham registra- dores orientados para palavras e uma memória orientada para bytes, e ambos ocupavam uma faixa que abrangia uma considerável relação preço/desempenho. O PDP-11 teve enorme sucesso, em especial nas universidades, e deu continuidade à liderança da DEC sobre os outros fabricantes de minicomputadores. 1.2.5 A quarta gerac a o  integrac a o em escala muito grande (1980?) Na década de 1980, a VLSI (Very Large Scale Integration  integração em escala muito grande) tinha pos- sibilitado colocar primeiro dezenas de milhares, depois centenas de milhares e, por fim, milhões de transistores em um único chip. Esse desenvolvimento logo levou a computadores menores e mais rápidos. Antes do PDP-1, os computadores eram tão grandes e caros que empresas e universidades tinham de ter departamentos especiais denominados centrais de computação para usá-los. Com a chegada do minicomputador, cada departamento podia comprar sua própria máquina. Em 1980, os preços caíram tanto que era viável um único indivíduo ter seu próprio computador. Tinha início a era do computador pessoal. Computadores pessoais eram utilizados de modo muito diferente dos computadores grandes. Eram usados para processar textos, montar planilhas e para numerosas aplicações de alto grau de interação (como os jogos) que as máquinas maiores não manipulavam bem. Os primeiros computadores pessoais costumavam ser vendidos como kits. Cada kit continha uma placa de circuito impresso, um punhado de chips, que em geral incluía um ntel 8080, alguns cabos, uma fonte de energia
  • 38. C a p  t u l o 1 I n t r o d u c  a  o 19 e talvez um disco flexível de 8 polegadas. Juntar essas partes para montar um computador era tarefa do com- prador. O software não era fornecido. Se quisesse algum, você mesmo teria de escrevê-lo. Mais tarde, o sistema operacional CP/M, escrito por Gary Kildall, tornou-se popular nos 8080s. Era um verdadeiro sistema operacional em disco flexível, com um sistema de arquivo e comandos de usuário digitados no teclado e enviados a um pro- cessador de comandos (shell). Outro computador pessoal era o Apple, e mais tarde o Apple , projetados por Steve Jobs e Steve Wozniak na tão falada garagem. Essa máquina gozava de enorme popularidade entre usuários domésticos e em escolas, e fez da Apple uma participante séria no mercado quase da noite para o dia. Depois de muito deliberar e observar o que as outras empresas estavam fazendo, a BM, que então era a força dominante na indústria de computadores, por fim decidiu que queria entrar no negócio de computadores pessoais. Em vez de projetar toda a máquina partindo do zero, usando somente peças da BM, o que levaria tempo demasiado, fez algo que não lhe era característico. Deu a Philip Estridge, um de seus executivos, uma grande mala de dinheiro e disse-lhe que fosse para bem longe dos acionistas intrometidos da sede da empresa em Armonk, Nova York, e só voltasse quando tivesse um computador pessoal em funcionamento. Estridge se estabeleceu a dois mil km da sede, em Boca Raton, Flórida, escolheu o ntel 8088 como sua CPU, e construiu o BM Personal Computer com componentes encontrados na praça. Foi lançado em 1981 e logo se tornou o maior campeão de vendas de computadores da história. Quando o PC alcançou 30 anos, foram publicados diversos artigos sobre sua história, incluindo os de Bradley (2011), Goth (2011), Bride (2011) e Singh (2011). A BM também fez algo que não lhe era característico e de que mais tarde viria a se arrepender. Em vez de manter o projeto da máquina em total segredo (ou ao menos protegido por uma patente), como costumava fazer, a empresa publicou os planos completos, incluindo todos os diagramas de circuitos, em um livro vendido por 49 dólares. A ideia era possibilitar a fabricação, por outras empresas, de placas de expansão (plug-in) para o BM PC, a fim de aumentar sua flexibilidade e popularidade. nfelizmente para a BM, uma vez que o projeto se tornara totalmente público e era fácil obter todas as peças no mercado, inúmeras outras empresas começaram a fabricar clones do PC, muitas vezes por bem menos do que a BM estava cobrando. Assim, começava toda uma indústria. Embora outras empresas fabricassem computadores pessoais usando CPUs não fornecidas pela ntel, entre elas Commodore, Apple e Atari, o impulso adquirido pela indústria do BM PC era tão grande que os outros foram esmagados por esse rolo compressor. Apenas uns poucos sobreviveram, em nichos de mercado. Um dos que sobreviveram, embora por um triz, foi o Macintosh da Apple. O Macintosh foi lançado em 1984 como o sucessor do malfadado Lisa, o primeiro computador que vinha com uma GUI (Graphical User Interface  interface gráfica de usuário), semelhante à agora popular interface Windows. O Lisa fracassou porque era muito caro, mas o Macintosh de menor preço lançado um ano depois foi um enorme sucesso e inspirou amor e paixão entre seus muitos admiradores. Esse primeiro mercado do computador pessoal também levou ao desejo até então inaudito por computadores portáteis. Naquele tempo, um computador portátil fazia tanto sentido quanto hoje faz um refrigerador portátil. O primeiro verdadeiro computador pessoal portátil foi o Osborne-1 que, com 11 quilos, era mais um computa- dor “arrastável” do que portátil. Ainda assim, era prova de que a ideia de um computador portátil era possível. O Osborne-1 foi um sucesso comercial modesto, mas um ano mais tarde a Compaq lançou seu primeiro clone portátil do BM PC e logo se estabeleceu como a líder no mercado de computadores portáteis. A versão inicial do BM PC vinha equipada com o sistema operacional MS-DOS fornecido pela então minús- cula Microsoft Corporation. Assim como a ntel conseguia produzir CPUs cada vez mais potentes, a BM e a Microsoft conseguiram desenvolver um sucessor do MS-DOS, denominado OS/2, que apresentava uma interface gráfica de usuário semelhante à do Apple Macintosh. Ao mesmo tempo, a Microsoft também desenvolvia seu próprio sistema operacional, o Windows, que rodava sobre o MS-DOS caso o OS/2 não pegasse. Para encurtar a história, o OS/2 não pegou, a BM e a Microsoft tiveram uma ruptura notavelmente pública e a Microsoft foi adiante e transformou o Windows em um enorme sucesso. O modo como a minúscula ntel e a mais insignifi- cante ainda Microsoft conseguiram destronar a BM, uma das maiores, mais ricas e mais poderosas corporações da história mundial, é uma parábola sem dúvida relatada com grandes detalhes nas escolas de administração de empresas de todo o mundo.
  • 39. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 20 Com o sucesso do 8088 em mãos, a ntel continuou fazendo versões maiores e melhores dele. Particularmente digno de nota foi o 80386, lançado em 1985, que tinha uma CPU de 32 bits. Este foi segui- do por uma versão melhorada, naturalmente denominada 80486. As versões seguintes receberam os nomes Pentium e Core. Esses chips são usados em quase todos os PCs modernos. O nome genérico que muita gente usa para descrever a arquitetura desses processadores é x86. Os chips compatíveis, fabricados pela AMD, tam- bém são denominados x86s. Em meados da década de 1980, um novo desenvolvimento denominado RSC (discutido no Capítulo 2) começou a se impor, substituindo complicadas arquiteturas (CSC) por outras bem mais simples, embora mais rápidas. Na década de 1990, começaram a aparecer CPUs superescalares. Essas máquinas podiam executar várias instruções ao mesmo tempo, muitas vezes em ordem diferente da que aparecia no programa. amos apresentar os conceitos de CSC, RSC e superescalar no Capítulo 2 e discuti-los em detalhes ao longo de todo este livro. Também em meados da década de 1980, Ross Freeman e seus colegas na ilinx desenvolveram uma técnica inteligente para montar circuitos integrados, que não exigia uma fortuna ou o acesso a uma fábrica de silício. Esse novo tipo de chip de computador, denominado FPG (Field-Programmable Gate rray), continha uma grande quantidade de portas lógicas genéricas, que poderiam ser “programadas” em qualquer circuito que coubesse no dispositivo. Essa extraordinária nova técnica de projeto tornou o hardware FPGA tão maleável quanto o software. Usando FPGAs que custavam dezenas a centenas de dólares americanos, era possível montar sistemas de compu- tação especializados para aplicações exclusivas, que serviam apenas a alguns usuários. Felizmente, as empresas de fabricação de silício ainda poderiam produzir chips mais rápidos, com menor consumo de energia e mais baratos para aplicações que precisavam de milhões de chips. Porém, para aplicações com apenas alguns poucos usuários, como prototipagem, aplicações de projeto em baixo volume e educação, FPGAs continuam sendo uma ferramenta popular para a construção do hardware. Até 1992, computadores pessoais eram de 8, 16 ou 32 bits. Então, a DEC surgiu com o revolucioná- rio Alpha de 64 bits, uma verdadeira máquina RSC de 64 bits cujo desempenho ultrapassava por grande margem o de todos os outros computadores pessoais. Seu sucesso foi modesto, mas quase uma década se passou antes que as máquinas de 64 bits começassem a ter grande sucesso e, na maior parte das vezes, como servidores de topo de linha. Durante a década de 1990, os sistemas de computação estavam se tornando cada vez mais rápidos usando uma série de aperfeiçoamentos microarquitetônicos, e muitos deles serão examinados neste livro. Os usuários desses sistemas eram procurados pelos vendedores de computador, pois cada novo sistema que eles compravam executava seus programas muito mais depressa do que em seu antigo sistema. Porém, ao final da década, essa tendência estava começando a desaparecer, devido a obstáculos importantes no projeto do computador: os arquitetos estavam esgotando seus truques para tornar seus programas mais rápidos e os processadores estavam ficando mais caros de resfriar. Desesperadas para continuar a montar processa- dores mais rápidos, a maioria das empresas de computador começou a se voltar para arquiteturas paralelas como um modo de obter mais desempenho do seu silício. Em 2001, a BM introduziu a arquitetura dual core POWER4. Essa foi a primeira vez que uma CPU importante incorporava dois processadores no mesmo substrato. Hoje, a maioria dos processadores da classe desktop e servidor, e até mesmo alguns processadores embutidos, incorporam múltiplos processadores no chip. nfelizmente, o desempenho desses multiproces- sadores tem sido menor que estelar para o usuário comum, pois (como veremos em outros capítulos) as máquinas paralelas exigem que os programadores trabalhem explicitamente em paralelo, o que é difícil e passível de erros. 1.2.6 A quinta gerac a o  computadores de baixa pote ncia e invis veis Em 1981, o governo japonês anunciou que estava planejando gastar 500 milhões de dólares para ajudar empresas a desenvolver computadores de quinta geração que seriam baseados em inteligência artificial e repre- sentariam um salto quântico em relação aos computadores “burros” da quarta geração. Como já tinham visto
  • 40. C a p  t u l o 1 I n t r o d u c  a  o 21 empresas japonesas se apossarem do mercado em muitos setores, de máquinas fotográficas a aparelhos de som e de televisão, os fabricantes de computadores americanos e europeus foram de zero a pânico total em um milisse- gundo, exigindo subsídios do governo e outras coisas. A despeito do grande barulho, o projeto japonês da quinta geração fracassou e foi abandonado sem alarde. Em certo sentido, foi como a máquina analítica de Babbage – uma ideia visionária, mas tão à frente de seu tempo que nem se podia vislumbrar a tecnologia necessária para realmente construí-la. Não obstante, aquilo que poderia ser denominado a quinta geração na verdade aconteceu, mas de modo ines- perado: os computadores encolheram. Em 1989, a Grid Systems lançou o primeiro tablet, denominado GridPad. Ele consistia em uma pequena tela em que os usuários poderiam escrever com uma caneta especial, para controlar o sistema. Sistemas como o GridPad mostraram que os computadores não precisam estar sobre uma mesa ou em uma sala de servidores, mas poderiam ser colocados em um pacote fácil de carregar, com telas sensíveis ao toque e reconhecimento de escrita, para torná-los ainda mais valiosos. O Newton da Apple, lançado em 1993, mostrou que um computador podia ser construído dentro de um invólucro não maior do que um tocador de fitas cassete portátil. Assim como o GridPad, o Newton usava escrita à mão para entrada do usuário, o que provou ser um grande obstáculo, mas máquinas posteriores dessa classe, agora denominadas Ps (Personal igital ssistants  assistentes digitais pessoais), aprimoraram as interfa- ces de usuário e tornaram-se muito populares. Agora, elas evoluíram para smartphones. Por fim, a interface de escrita do PDA foi aperfeiçoada por Jeff Hawkins, que criou uma empresa chamada Palm para desenvolver um PDA de baixo custo para o mercado consumidor em massa. Hawkins era engenheiro elétrico por treinamento, mas tinha um real interesse pela neurociência, que é o estudo do cérebro humano. Ele observou que o reconhecimento da escrita à mão poderia se tornar mais confiável treinando-se os usuários a escreverem de uma maneira mais legível pelos computadores, uma técnica de entrada que ele chamou de “Graffiti”. Ela exigia um pouco de treinamento para o usuário, mas por fim levou a uma escrita mais rápida e mais confiável, e o primeiro PDA da Palm, denominado Palm Pilot, foi um grande sucesso. Graffiti é um dos grandes sucessos na computação, demonstrando o poder da mente humana de tirar proveito do poder da mente humana. Os usuários de PDAs eram adeptos destes dispositivos, usando-os religiosamente para gerenciar seus com- promissos e contatos. Quando os telefones celulares começaram a ganhar popularidade no início da década de 1990, a BM aproveitou a oportunidade para integrar o telefone celular com o PDA, criando o “smartphone”. O primeiro, chamado Simon, usava uma tela sensível ao toque como entrada e dava ao usuário todas as capacidades de um PDA mais telefone, jogos e e-mail. A redução no tamanho dos componentes e no custo por fim levou ao grande uso de smartphones, incorporado nas populares plataformas Apple iPhone e Google Android. Mas mesmo os PDAs e smartphones não são revolucionários de verdade. Ainda mais importantes são os computadores “invisíveis”, embutidos em eletrodomésticos, relógios, cartões bancários e diversos outros dispositivos (Bechini et al., 2004). Esses processadores permitem maior funcionalidade e custo mais baixo em uma ampla variedade de aplicações. Considerar esses chips uma verdadeira geração é discutível (estão por aí desde a década de 1970, mais ou menos), mas eles estão revolucionando o modo de funcionamento de milhares de aparelhos e outros dispositivos. Já começaram a causar um importante impacto no mundo e sua influência crescerá rapidamente nos próximos anos. Um aspecto peculiar desses computadores embutidos é que o hard- ware e software costumam ser projetados em conjunto (Henkel et al., 2003). oltaremos a eles mais adiante neste livro. Se entendermos a primeira geração como máquinas a válvula (por exemplo, o ENAC), a segunda geração como máquinas a transistores (por exemplo, o BM 7094), a terceira geração como as primeiras máquinas de circuito integrado (por exemplo, o BM 360), e a quarta geração como computadores pessoais (por exemplo, as CPUs ntel), a real quinta geração é mais uma mudança de paradigma do que uma nova arquitetura específica. No futuro, computadores estarão por toda parte e embutidos em tudo – de fato, invisíveis. Eles serão parte da estrutura da vida diária, abrindo portas, acendendo luzes, fornecendo cédulas de dinheiro e milhares de outras coisas. Esse modelo, arquitetado pelo falecido Mark Weiser, foi denominado originalmente computação ubí- qua, mas o termo computação pervasiva também é usado agora com frequência (Weiser, 2002). Ele mudará
  • 41. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 22 o mundo com tanta profundidade quanto a Revolução ndustrial. Não o discutiremos mais neste livro, mas se o leitor quiser mais informações sobre ele, deve consultar: Lyytinen e Yoo, 2002; Saha e Mukherjee, 2003 e Sakamura, 2002. 1.3 O zoolo gico dos computadores Na seção anterior, apresentamos uma breve história dos sistemas de computação. Nesta, examinaremos o presente e olharemos para o futuro. Embora computadores pessoais sejam os mais conhecidos, há outros tipos de máquinas hoje, portanto, vale a pena dar uma pesquisada no que há mais por aí. 1.3.1 Forc as tecnolo gicas e econo micas A indústria de computadores está avançando como nenhuma outra. A força propulsora primária é a capaci- dade dos fabricantes de chips de empacotar cada vez mais transistores por chip todo ano. Mais transistores, que são minúsculos interruptores eletrônicos, significam memórias maiores e processadores mais poderosos. Gordon Moore, cofundador e ex-presidente do conselho da ntel, certa vez disse, brincando, que, se a tecnologia da aviação tivesse progredido tão depressa quanto a tecnologia de computadores, um avião custaria 500 dólares e daria uma volta na Terra em 20 minutos com 20 litros de gasolina. Entretanto, seria do tamanho de uma caixa de sapatos. Especificamente, ao preparar uma palestra para um grupo do setor, Moore observou que cada nova geração de chips de memória estava sendo lançada três anos após a anterior. Uma vez que cada geração tinha quatro vezes mais memória do que sua antecessora, ele percebeu que o número de transistores em um chip estava crescendo a uma taxa constante e previu que esse crescimento continuaria pelas próximas décadas. Essa observação ficou conhecida como lei de Moore. Hoje, a lei de Moore costuma ser expressa dizendo que o número de transistores dobra a cada 18 meses. Note que isso equivale a um aumento de 60% no número de transistores por ano. Os tamanhos dos chips de memória e suas datas de lançamento mostrados na Figura 1.8 confirmam que a lei de Moore está valendo há mais de quatro décadas. Figura 1.8 A lei de Moore preve  um aumento anual de 60% no nu mero de transistores que podem ser colocados em um chip. Os dados pontuais informados nesta figura sa o tamanhos de memo rias em bits. 100G 10G 1G 100M 10M 1M 100K 10K 1K 100 10 1 1965 1970 1K 16K 4K 64K 256K 4M 1M 16M 64M 256M 512M 1G 2G 1975 1980 1985 1990 1995 2000 2005 2010 Claro que a lei de Moore não é uma lei real, mas uma simples observação empírica sobre quão rápido os físicos do estado sólido e os engenheiros estão avançando o estado da arte e uma previsão de que eles continuarão Número de transistores Ano
  • 42. C a p  t u l o 1 I n t r o d u c  a  o 23 na mesma taxa no futuro. Alguns observadores do setor esperam que a lei de Moore continue válida ao menos por mais uma década, talvez até por mais tempo. Outros observadores esperam que dissipação de energia, fuga de corrente e outros efeitos apareçam antes e causem sérios problemas que precisam ser resolvidos (Bose, 2004; Kim et al., 2003). Contudo, a realidade do encolhimento de transistores é que a espessura desses dispositivos logo será de apenas alguns átomos. Nesse ponto, os transistores consistirão de muito poucos átomos para que sejam confiáveis, ou simplesmente chegaremos a um ponto onde outras diminuições de tamanho exigirão blocos de montagem subatômicos. (Como um conselho, recomenda-se que aqueles que trabalham em uma fábrica de silício tirem folga no dia em que decidirem dividir o transistor de um átomo!) Apesar dos muitos desafios na extensão das tendências da lei de Moore, existem tecnologias favoráveis no horizonte, incluindo os avanços na computação quântica (Oskin et al., 2002) e nanotubos de carbono (Heinze et al., 2002), que podem criar oportunidades para escalar a eletrônica além dos limites do silício. A lei de Moore criou o que os economistas chamam de círculo virtuoso. Progressos na tecnologia (transisto- res/chip) levam a melhores produtos e preços mais baixos. Preços mais baixos levam a novas aplicações (ninguém estava fabricando videogames para computadores quando estes custavam 10 milhões de dólares cada, embora, quando o preço caiu para 120 mil dólares, os alunos do MT aceitaram o desafio). Novas aplicações levam a novos mercados e a novas empresas, que surgem para aproveitar as vantagens desses mercados. A existência de todas essas empresas leva à concorrência que, por sua vez, cria demanda econômica por melhores tecnologias, que substituirão as outras. Então, o círculo deu uma volta completa. Outro fator que trouxe avanço tecnológico foi a primeira lei do software de Nathan (trata-se de Nathan Myhrvold, antigo alto executivo da Microsoft). Diz a lei: “O software é um gás. Ele se expande até preencher o recipiente que o contém”. Na década de 1980, processamento de textos era feito com programas como o troff (ainda usado para este livro). O troff ocupa kilobytes de memória. Os modernos processadores de textos ocupam megabytes de memória. Os futuros sem dúvida exigirão gigabytes de memória. (Por uma primeira aproximação, os prefixos kilo, mega, giga e tera significam mil, milhão, bilhão e trilhão, respectivamente, mas veja a Seção 1.5 para outros detalhes.) O software que continua a adquirir características (não muito diferente dos celulares que estão sempre adquirindo novas aplicações) cria uma demanda constante por processadores mais velozes, memó- rias maiores e mais capacidade de E/S. Enquanto os ganhos em transistores por chip tinham sido vultosos ao longo dos anos, os ganhos em outras tecnologias não foram menores. Por exemplo, o BM PC/T foi lançado em 1982 com um disco rígido de 10 mega- bytes. Trinta anos depois, discos rígidos de 1 terabyte eram comuns nos sucessores do PC/T. Esse avanço de cinco ordens de grandeza em 30 anos representa um aumento de capacidade de 50% ao ano. Contudo, medir o avanço em discos é mais enganoso, visto que há outros parâmetros além da capacidade, como taxas (de transferência) de dados, tempo de busca e preço. Não obstante, quase qualquer método de medição mostrará que a razão preço/desempenho aumentou desde 1982 pelo menos 50% ao ano. Esses enormes ganhos em desempenho do disco, aliados ao fato de que o volume de dólares de discos despachados do ale do Silício ultrapassou o de chips de CPU, levaram Al Hoagland a sugerir que o nome do local estava errado: deveria ser ale do Óxido de Ferro (já que é esse o mate- rial de gravação utilizado em discos). Lentamente, essa tendência está se deslocando em favor do silício, enquanto memórias flash baseadas em silício começam a substituir os discos giratórios tradicionais em muitos sistemas. Outra área que teve ganhos espetaculares foi a de telecomunicações e redes. Em menos de duas décadas fomos de modems de 300 bits/s para modems analógicos de 56 mil bits/s, e daí para redes de fibra ótica de 1012 bits/s. Os cabos de telefonia transatlânticos de fibra ótica, como o TAT-12/13, custam cerca de 700 milhões de dólares, duram dez anos e podem transportar 300 mil ligações telefônicas simultâneas, o que se traduz em menos do que 1 centavo de dólar para uma ligação telefônica intercontinental de dez minutos. Sistemas ópticos de comunicação que funcionam a 1012 bits/s, a distâncias que passam de 100 km e sem amplificadores, mostraram ser viáveis. Nem é preciso comentar aqui o crescimento exponencial da nternet. 1.3.2 Tipos de computadores Richard Hamming, antigo pesquisador do Bell Labs, certa vez observou que uma mudança de uma ordem de grandeza em quantidade causa uma mudança na qualidade. Assim, um carro de corrida que alcança 1.000 km/h
  • 43. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 24 no deserto de Nevada é um tipo de máquina muito diferente de um carro normal que alcança 100 km/h em uma rodovia. De modo semelhante, um arranha-céu de 100 andares não é apenas um edifício de apartamentos de 10 andares em escala maior. E, no que se refere a computadores, não estamos falando de fatores de 10, mas, no decurso de três décadas, estamos falando de fatores na casa de milhão. Os ganhos concedidos pela lei de Moore podem ser usados de vários modos por vendedores de chips. Um deles é construir computadores cada vez mais poderosos a preço constante. Outra abordagem é construir o mesmo computador por uma quantia de dinheiro cada vez menor a cada ano. A indústria fez ambas as coisas e ainda mais, o que resultou na ampla variedade de computadores disponíveis agora. Uma categorização muito aproximada dos computadores existentes hoje é dada na Figura 1.9. Figura 1.9 Tipos de computador dispon veis atualmente. Os prec os devem ser vistos com certa condescende ncia (cum grano salis). Tipo Preço (US$) Exemplo de aplicação Computador descartável 0,5 Cartões de felicitação Microcontrolador 5 Relógios, carros, eletrodomésticos Computador móvel e de jogos 50 Videogames domésticos e smartphones Computador pessoal 500 Computador de desktop ou notebook Servidor 5K Servidor de rede Mainframe 5M Processamento de dados em bloco em um banco Nas seções seguintes, examinaremos cada uma dessas categorias e discutiremos brevemente suas propriedades. 1.3.3 Computadores descarta veis Na extremidade inferior desse tipo encontramos um único chip colado na parte interna de um cartão de con- gratulações, que toca “Feliz Aniversário” ou “Lá vem a noiva”, ou qualquer outra dessas musiquinhas igualmente horrorosas. O autor ainda não encontrou um cartão de condolências que tocasse uma marcha fúnebre, mas, como lançou essa ideia em público, espera encontrá-lo em breve. Para quem cresceu com mainframes de muitos milhões de dólares, a ideia de computadores descartáveis faz tanto sentido quanto a de um avião descartável. Contudo, os computadores descartáveis chegaram para ficar. Provavelmente, o desenvolvimento mais impor- tante na área dos computadores descartáveis é o chip RFI (Radio Frequency Ientification  identificação por radiofrequência). Agora é possível fabricar, por alguns centavos, chips RFD sem bateria com menos de 0,5 mm de espessura, que contêm um minúsculo transponder de rádio e um único número de 128 bits embutido. Quando pulsados por uma antena externa, são alimentados pelo sinal de rádio de entrada por tempo suficiente para trans- mitir seu número de volta à antena. Embora os chips sejam minúsculos, suas implicações com certeza não são. amos começar com uma aplicação corriqueira: acabar com os códigos de barras de produtos. Já foram feitos testes experimentais nos quais o fabricante anexou chips RFD (em vez de códigos de barras) a seus produtos à venda em lojas. O cliente escolhe as mercadorias, coloca-as em um carrinho de compras e apenas as leva para fora da loja, sem passar pela caixa registradora. Na saída da loja, um leitor munido de uma antena envia um sinal solicitando que cada produto se identifique, o que cada um faz por meio de uma curta transmissão sem fio. O cliente também é identificado por um chip embutido em seu cartão bancário ou de crédito. No final do mês, a loja envia ao cliente uma fatura, identificada por itens, referente às compras do mês. Se o cartão de banco ou cartão de crédito RFD do cliente não for válido, um alarme é ativado. Esse sistema não só elimina a necessidade de caixas e a correspondente espera na fila, mas também serve como método antifurto, porque de nada adianta esconder um produto no bolso ou na sacola.
  • 44. C a p  t u l o 1 I n t r o d u c  a  o 25 Uma propriedade interessante desse sistema é que, embora os códigos de barra identifiquem o tipo de produ- to, não identificam o item específico. Com 128 bits à disposição, os chips RFD fazem isso. Como consequência, cada pacote de aspirina, por exemplo, em um supermercado, terá um código RFD diferente. sso significa que, se um fabricante de medicamentos descobrir um defeito de fabricação em um lote de aspirinas após ele ter sido despachado, poderá informar a todos os supermercados do mundo inteiro para que façam disparar o alarme sempre que um cliente comprar qualquer pacote cujo número RFD esteja na faixa afetada, mesmo que a compra aconteça em um país distante, meses depois. As cartelas de aspirina que não pertençam ao lote defeituoso não farão soar o alarme. Mas rotular pacotes de aspirina, de bolachas, de biscoitos para cachorro é só o começo. Por que parar nos bis- coitos para cachorro quando você pode rotular o próprio cachorro? Donos de animais de estimação já estão pedindo aos veterinários para implantar chips RFD em seus animais de modo que possam ser rastreados se forem roubados ou perdidos. Fazendeiros também vão querer marcar seus rebanhos. O próximo passo óbvio é pais ansiosos pedirem a seus pediatras que implantem chips RFD em seus filhos para o caso de eles se perderem ou serem sequestrados. Já que estamos nisso, por que não fazer os hospitais identificarem todos os recém-nascidos para evitar troca de bebês? E os governos e a polícia sem dúvida terão muitas boas razões para rastrear todos os cidadãos o tempo todo. Agora, as “implicações” dos chips RFD a que aludimos anteriormente estão ficando um pouco mais claras. Outra aplicação (um pouco menos controvertida) de chips RFD é o rastreamento de veículos. Quando uma fila de automóveis com chips RFD embutidos estiver trafegando por uma rodovia e passarem por uma leitora, o computador ligado à leitora terá uma lista dos carros que estiveram por ali. Esse sistema facilita o rastreamento da localização de todos os veículos que passam por uma rodovia, o que ajuda fornecedores, seus clientes e as rodovias. Um esquema semelhante pode ser aplicado a caminhões. No caso dos carros, a ideia já está sendo usada para cobrar pedágio por meios eletrônicos (por exemplo, o sistema E-Z Pass). Sistemas de transporte de bagagens aéreas e muitos outros sistemas de transporte de encomendas também podem usar chips RFD. Um sistema experimental testado no aeroporto de Heathrow, em Londres, permitia que os passageiros eliminassem a necessidade de carregar sua bagagem. As malas dos clientes que pagavam por esse serviço recebiam um chip RFD, eram descarregadas em separado no aeroporto e entregues diretamente nos hotéis dos passageiros em questão. Entre outras utilizações de chips RFD estão carros que chegam à seção de pintura da linha de montagem com a cor que devem ter já especificada, estudo de migração de animais, roupas que informam à máquina de lavar que temperatura usar e muitas mais. Alguns chips podem ser integrados com sensores de modo que bits de baixa ordem possam conter temperatura, pressão e umidade correntes, ou outra variável ambiental. Chips RFD avançados também contêm armazenamento permanente. Essa capacidade levou o Banco Central Europeu a tomar a decisão de incorporar chips RFD a notas de euros nos próximos anos. Os chips registrariam por onde as cédulas teriam passado. sso não apenas tornaria a falsificação de notas de euros praticamente impos- sível, mas também facilitaria muito o rastreamento e a possível invalidação remota de resgates de sequestros, do produto de assaltos e de dinheiro lavado. Quando o dinheiro vivo não for mais anônimo, o futuro procedimento padrão da polícia poderia ser verificar por onde o dinheiro do suspeito passou recentemente. Quem precisa implantar chips em pessoas quando suas carteiras estão cheias deles? Mais uma vez, quando o público souber o que os chips RFD podem fazer, é provável que surjam discussões públicas sobre o assunto. A tecnologia usada em chips RFD está se desenvolvendo rapidamente. Os menores são passivos (não têm alimentação interna) e podem apenas transmitir seus números exclusivos quando consultados. Todavia, os maio- res são ativos, podem conter uma pequena bateria e um computador primitivo, e são capazes de fazer alguns cálculos. Os smart cards usados em transações financeiras estão nessa categoria. Chips RFD são diferentes não só por serem ativos ou passivos, mas também pela faixa de radiofrequências à qual respondem. Os que funcionam em baixas frequências têm uma taxa de transferência de dados limitada, mas podem ser captados a grandes distâncias por uma antena. Os que funcionam em altas frequências têm uma taxa de transferência de dados mais alta e alcance mais reduzido. Os chips também diferem de outras formas e estão sendo aperfeiçoados o tempo todo. A nternet está repleta de informações sobre chips RFD, e o site <www.rfid.org> é um bom ponto de partida.
  • 45. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 26 1.3.4 Microcontroladores No degrauseguinte da escada temos computadores que são embutidos em dispositivos que não são vendidos como computadores. Os computadores embutidos, às vezes denominados microcontroladores, gerenciam os dispositivos e manipulam a interface de usuário. São encontrados em grande variedade de aparelhos diferentes, entre eles os seguintes. Alguns exemplos de cada categoria são dados entre parênteses. 1. Eletrodomésticos (rádio-relógio, máquina de lavar, secadora, forno de micro-ondas, alarme antifurto). 2. Aparelhos de comunicação (telefone sem fio, telefone celular, fax, pager). 3. Periféricos de computadores (impressora, scanner, modem, drive de CD-ROM). 4. Equipamentos de entretenimento (CR, DD, aparelhos de som, MP3 player, transdutores de T). 5. Aparelhos de reprodução de imagens (T, câmera digital, filmadora, lentes, fotocopiadora). 6. Equipamentos médicos (raio-x, RM – ressonância magnética, monitor cardíaco, termômetro digital). 7. Sistemas de armamentos militares (míssil teleguiado, MBC – míssil balístico intercontinental, torpedo). 8. Dispositivos de vendas (máquina de venda automática, ATM – caixa eletrônico, caixa registradora). 9. Brinquedos (bonecas que falam, consoles de jogos, carro ou barco com radiocontrole). Um carro de primeira linha poderia sem problema conter 50 microcontroladores que executam subsistemas, como freios antitravamento, injeção de combustível, rádio e GPS. Um avião a jato poderia com facilidade ter 200 ou mais deles. Uma família poderia possuir facilmente centenas de computadores sem saber. Dentro de alguns anos, quase tudo o que funciona por energia elétrica ou baterias conterá um microcontrolador. Os números de microcontroladores vendidos todo ano deixam longe, por ordens de grandeza, todos os outros tipos de compu- tadores, exceto os descartáveis. Enquanto chips RFD são sistemas mínimos, minicontroladores são computadores pequenos, mas com- pletos. Cada microcontrolador tem um processador, memória e capacidade de E/S. A capacidade de E/S inclui detectar os botões e interruptores do aparelho e controlar suas luzes, monitores, sons e motores. Na maioria dos casos, o software está incorporado no chip na forma de uma memória somente de leitura criada quando o micro- controlador é fabricado. Os microcontroladores são de dois tipos gerais: propósito geral e propósito específico. Os primeiros são apenas computadores pequenos, porém comuns; os últimos têm uma arquitetura e um conjunto de instruções dirigido para alguma aplicação específica, como multimídia. Microcontroladores podem ter versões de 4, 8, 16 e 32 bits. Contudo, mesmo os microcontroladores de uso geral apresentam importantes diferenças em relação aos PCs. Primeiro, há a questão relacionada ao custo: uma empresa que compra milhões de unidades pode basear sua esco- lha em diferenças de preços de 1 centavo por unidade. Essa restrição obriga os fabricantes de microcontroladores a optar por arquiteturas muito mais com base em custos de fabricação do que em chips que custam centenas de dólares. Os preços de microcontroladores variam muito dependendo de quantos bits eles têm, de quanta memó- ria têm e de que tipo é a memória, além de outros fatores. Para dar uma ideia, um microcontrolador de 8 bits comprado em volume grande o bastante pode custar apenas 10 centavos de dólar por unidade. Esse preço é o que possibilita inserir um computador em um rádio-relógio de 9,95 dólares. Segundo, quase todos os microcontroladores funcionam em tempo real. Eles recebem um estímulo e devem dar uma resposta instantânea. Por exemplo, quando o usuário aperta um botão, em geral uma luz se acende e não deve haver nenhuma demora entre pressionar o botão e a luz se acender. A necessidade de funcionar em tempo real costuma causar impacto na arquitetura. Terceiro, os sistemas embutidos muitas vezes têm limitações físicas relativas a tamanho, peso, consumo de bateria e outras limitações elétricas e mecânicas. Os microcontroladores neles utilizados devem ser projetados tendo essas restrições em mente.
  • 46. C a p  t u l o 1 I n t r o d u c  a  o 27 Uma aplicação particularmente divertida dos microcontroladores é na plataforma de controle embutida Arduino, que foi projetada por Massimo Banzi e David Cuartielles em vrea, tália. Seu objetivo para o projeto foi produzir uma plataforma de computação embutida completa, que custa menos que uma pizza grande com cobertura extra, tornando-o facilmente acessível a alunos e curiosos. (Essa foi uma tarefa difícil, pois há muitas pizzarias na tália, de modo que as pizzas são realmente baratas.) Eles alcaçaram seu objetivo muito bem: um sistema Arduino completo custa menos de 20 dólares! O sistema Arduino é um projeto de hardware de fonte aberta, o que significa que todos os seus detalhes são publi- cados e gratuitos, de modo que qualquer um pode montar (e até mesmo vender) um sistema Arduino. Ele é baseado no microprocessador RSC de 8 bits Atmel AR, e a maioria dos projetos de placa também inclui suporte básico para E/S. A placa é programada usando uma linguagem de programação embutida, chamada Wiring, que tem embutidos todos os balangandãs exigidos para controlar dispositivos em tempo real. O que torna a plataforma Arduino divertida de usar é sua comunidade de desenvolvimento grande e ativa. Existem milhares de projetos publicados usando o Arduino,3 variando desde um farejador de poluentes eletrônico até uma jaqueta de ciclismo com sinais de seta, um detector de umidade que envia e-mail quando uma planta precisa ser aguada e um avião autônomo não pilotado. 1.3.5 Computadores mo veis e de jogos Um nível acima estão as máquinas de videogame. São computadores normais, com recursos gráficos especiais e capacidade de som, mas software limitado e pouca capacidade de extensão. Começaram como CPUs de baixo valor para telefones simples e jogos de ação, como pingue-pongue em aparelhos de televisão. Com o passar dos anos, evoluíram para sistemas muito mais poderosos, rivalizando com o desempenho de computadores pessoais e até ultrapassando esse desempenho em certas dimensões. Para ter uma ideia do que está dentro de um computador de jogos, considere a especificação de três produtos populares. Primeiro, o Sony PlayStation 3. Ele contém uma CPU proprietária multicore de 3,2 GHz (denomina- da microprocessador Cell), que é baseada na CPU RSC PowerPC da BM e sete Synergistic Processing Elements (SPEs) de 128 bits. O PlayStation 3 também contém 512 MB de RAM, um chip gráfico Nvidia de 550 MHz fabricado por encomenda e um player Blu-ray. Em segundo lugar, o Microsoft box 360. Ele contém uma CPU triple core PowerPC da BM de 3,2 GHz com 512 MB de RAM, um chip gráfico AT de 500 MHz fabricado por encomenda, um DD player e um disco rígido. Em terceiro lugar, o Samsung Galaxy Tablet (no qual este livro foi revisado). Ele contém dois núcleos ARM de 1 GHz mais uma unidade de processamento gráfico (integrada ao sistema-em-um- -chip Nvidia Tegra 2), 1 GB de RAM, duas câmeras, um giroscópio de 3 eixos e armazenamento com memória flash. Embora essas máquinas não sejam tão poderosas quanto os computadores pessoais produzidos no mesmo período de tempo, elas não ficam muito atrás e, em certos aspectos, estão à frente (por exemplo, a SPE de 128 bits do PlayStation 3 é maior do que a CPU de qualquer PC). A principal diferença entre essas máquinas de jogos e um PC não está tanto na CPU, mas no fato de que máquinas de jogos são sistemas fechados. Os usuários não podem expandir a CPU com cartões plug-in, embora às vezes sejam fornecidas interfaces USB ou FireWire. Além disso, e talvez o mais importante, máquinas de jogos são cuidadosamente otimizadas para algumas poucas áreas de aplicação: jogos de alta interatividade em 3D e saída de multimídia. Todo o resto é secundário. Essas restrições de hardware e software, falta de extensibilidade, memórias pequenas, ausência de um monitor de alta resolução e disco rígido pequeno (às vezes, ausente) possibilitam a construção e a venda dessas máquinas por um preço mais baixo do que o de computadores pessoais. A despeito dessas restrições, são vendidas milhões dessas máquinas de jogos, e a quantidade cresce o tempo todo. Computadores móveis têm o requisito adicional de que utilizam o mínimo de energia possível para realizar suas tarefas. Quanto menos energia eles usam, mais tempo irá durar sua bateria. Essa é uma tarefa de projeto desafiadora, pois as plataformas móveis, como tablets e smartphones, devem reduzir seu uso de energia, mas, ao mesmo tempo, os usuários desses dispositivos esperam capacidades de alto desempenho, como gráficos 3D, processamento de multimídia de alta definição e jogos. 3 Para descobrir mais sobre o Arduino e começar a trabalhar com seus próprios projetos Arduino, visite <www.arduino.cc>.
  • 47. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 28 1.3.6 Computadores pessoais Em seguida, chegamos aos computadores pessoais nos quais a maioria das pessoas pensa quando ouve o termo “computador”. O termo “computadores pessoais” abrange os modelos de desktop e notebook. Costumam vir equipados com gigabytes de memória e um disco rígido que contém terabytes de dados, um drive de CD-ROM/ DD/Blu-ray, placa de som, interface de rede, monitor de alta resolução e outros periféricos. Têm sistemas ope- racionais elaborados, muitas opções de expansão e uma imensa faixa de softwares disponíveis. O coração de todo computador pessoal é uma placa de circuito impresso que está no fundo ou na lateral da caixa. Em geral, essa placa contém a CPU, memória, vários dispositivos de E/S (como um chip de som e possi- velmente um modem), bem como interfaces para teclado, mouse, disco, rede etc., e alguns encaixes (slots) de expansão. A Figura 1.10 mostra a foto de uma dessas placas de circuito. Figura 1.10 A placa de circuito impresso esta  no corac a o de cada computador pessoal. Essa e  uma fotografia da placa Intel DQ67SW. Direitos de reproduc a o da Intel Corporation, 2011, reproduc a o permitida. Notebooks são basicamente PCs em uma embalagem menor e utilizam os mesmos componentes de hardware, mas em tamanhos menores. Também executam os mesmos softwares que os PCs de desktop. Uma vez que grande parte dos leitores deve conhecer computadores pessoais e notebooks muito bem, não será preciso fazer uma apresentação introdutória mais detalhada. Outra variante desse tema é o computador tablet, como o popular iPad. Esses dispositivos são apenas PCs normais em um pacote menor, com um disco em estado sólido em vez de um disco rígido giratório, uma tela sensível ao toque e uma CPU diferente do x86. Mas, do ponto de vista arquitetônico, os tablets são apenas note- books com tamanho e forma diferentes.
  • 48. C a p  t u l o 1 I n t r o d u c  a  o 29 1.3.7 Servidores Computadores pessoais reforçados ou estações de trabalho são muito usados como servidores de rede, tanto em redes locais (em geral, dentro de uma única empresa) quanto na nternet. Os servidores vêm em configura- ções com um único processador com múltiplos processadores, têm gigabytes de memória, centenas de gigabytes de espaço de disco rígido e capacidade para trabalho em rede de alta velocidade. Alguns deles podem manipular milhares de transações por segundo. Em termos de arquitetura, contudo, um servidor com um único processador na verdade não é muito dife- rente de um computador pessoal com um único processador. Apenas é mais rápido, maior e tem mais espaço de disco, e possivelmente conexão de rede mais rápida. Servidores executam os mesmos sistemas operacionais que os computadores pessoais, normalmente alguma variação de Unix ou Windows. Clusters Graças às melhorias quase contínuas na relação preço/desempenho dos servidores, nos últimos anos os projetistas de sistemas começaram a conectar grandes números deles para formar clusters. Eles consistem em sistemas padrão do tipo servidor, conectados por redes de gigabits/s e executam software especial que permite a todas as máquinas trabalharem juntas em um único problema, muitas vezes científico ou de engenharia. Normalmente, são o que se costuma denominar COS (Commodity Off he Shelf  mercadoria de prateleira), computadores que qualquer um pode comprar de algum vendedor de PCs comuns. O principal acréscimo é a capacidade de trabalho em rede de alta velocidade, mas às vezes isso também é uma placa de rede padrão encontrada no mercado. Grandes clusters costumam ser acomodados em salas de usuário especial ou prédios denominados data centers. A escala desses data centers é muito grande, e vai desde um punhado de máquinas até milhares delas. Em geral, o fator limitador é a verba disponível. Devido ao baixo preço por componente, agora departamentos individuais podem ter essas máquinas para uso interno. Muitas pessoas utilizam os termos “cluster” e “data center” para indi- car a mesma coisa, embora, tecnicamente, o primeiro seja a coleção de servidores e o outro seja a sala ou prédio que os abriga. Um uso comum para um cluster é como um servidor web. Quando um site espera milhares de solicitações por segundo para suas páginas, a solução mais econômica normalmente é construir um data center com centenas ou mesmo milhares de servidores. As solicitações que chegam são então espalhadas entre os servidores, para per- mitir que sejam processadas em paralelo. Por exemplo, a Google tem data centers por todo o mundo, para atender às solicitações de busca. O maior deles, em The Dalles, Oregon, é uma instalação com o tamanho de dois campos de futebol americano. O local foi escolhido porque os data centers exigem grandes quantidades de energia elétrica, e The Dalles é o local de uma represa hidrelétrica de 2 GW no rio Colúmbia, que pode fornecer essa energia. No total, considera-se que a Google tenha mais de um milhão de servidores em seus data centers. O negócio de computação é muito dinâmico, e as coisas mudam o tempo todo. Na década de 1960, a com- putação era dominada por computadores mainframe gigantes (veja mais adiante), custando dezenas de milhões de dólares, aos quais os usuários se conectavam usando terminais remotos. Esse era um modelo bastante centraliza- do. Depois, na década de 1980, os computadores pessoais entraram em cena, milhões de pessoas os compraram, e a computação tornou-se descentralizada. Com o advento dos data centers, estamos começando a reviver o passado na forma de computação em nuvens (cloud computing), que é a computação do mainframe versão 2.0. A ideia aqui é que todos terão um ou mais dispositivos simples, incluindo PCs, notebooks, tablets e smartphones, que são basicamente interfaces do usuário para a nuvem (ou seja, o data center), onde todas as fotos, vídeos, músicas e outros dados do usuário são armazenados. Nesse modelo, os dados são acessíveis a partir de diferentes dispositivos em qualquer lugar e a qualquer hora, sem que o usuário precise saber onde estão. Aqui, o data center cheio de servidores substituiu o único grande computador centralizado, mas o paradigma retornou ao que era antes: os usuários têm terminais e dados simples, e o poder da computação está centralizado em algum outro lugar.
  • 49. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 30 Quem sabe por quanto tempo esse modelo será popular? Poderia acontecer simplesmente que, em dez anos, tantas pessoas tenham armazenado tantas músicas, fotos e vídeos na nuvem que a infraestrutura (sem fios) para a comunicação com tudo isso se torne um gargalo. sso poderia levar a uma nova revolução: computadores pes- soais, onde as pessoas armazenam seus próprios dados em suas próprias máquinas localmente, evitando assim o engarrafamento no ar. A mensagem “leve para casa” aqui é que o modelo de computação popular em determinado momento depen- de muito da tecnologia, da economia e das aplicações disponíveis, e pode mudar quando esses fatores mudarem. 1.3.8 Mainframes Agora chegamos aos mainframes: computadores que ocupam uma sala e nos fazem voltar à década de 1960. Essas máquinas são as descendentes diretas dos mainframes BM 360 adquiridos há décadas. Em sua maior parte, não são muito mais rápidas do que servidores de grande potência, mas sempre têm mais capacidade de E/S e cos- tumam ser equipadas com vastas coleções de discos que contêm milhares de gigabytes de dados. Embora sejam caras, é comum serem mantidas em funcionamento por causa do enorme investimento em software, dados, pro- cedimentos operacionais e pessoal que representam. Muitas empresas acham mais barato pagar alguns milhões de dólares de vez em quando na compra de uma nova do que sequer pensar no esforço exigido para reprogramar todas as suas aplicações para máquinas menores. É essa classe de computadores que levou ao infame problema do “Ano 2000”, causado pelos programadores (principalmente COBOL) nas décadas de 1960 e 1970 porque representavam o ano com dois algarismos (dígitos) decimais para economizar memória. Eles nunca imaginaram que seus softwares durariam três ou quatro décadas. Embora o desastre previsto não tenha ocorrido graças ao imenso trabalho realizado para solucionar o problema, muitas empresas repetiram o mesmo erro quando acrescentaram mais dois dígitos ao ano. O autor prevê aqui o final da civilização que conhecemos à meia-noite de 31 de dezembro de 9999, quando 8 mil anos de velhos programas COBOL falharem simultaneamente. Além de sua utilização para executar software herdado de 40 anos de existência, nos últimos anos a nternet deu um novo fôlego a esses mainframes. Ela achou um novo nicho, como poderosos servidores de nternet, por exemplo, porque podem manipular quantidades maciças de transações de e-commerce por segundo, em particular em empresas que exigem imensas bases de dados. Até há pouco tempo havia outra categoria de computadores ainda mais poderosa que os mainframes: os super- computadores. Eles tinham CPUs incrivelmente velozes, muitos gigabytes de memória principal e discos rígidos e redes muito velozes. Eram usados para cálculos científicos e de engenharia maciços, como a simulação de galáxias em colisão, síntese de novos medicamentos ou modelagem do fluxo de ar em torno da asa de um avião. Porém, nos últimos anos, data centers construídos por componentes comerciais passaram a oferecer todo esse poder de computação com preços muito mais baixos, e os verdadeiros supercomputadores agora são uma raça em extinção. 1.4 Exemplos de fam lias de computadores Neste livro, vamos analisar três arquiteturas de conjunto de instruções (SAs) populares: x86, ARM e AR. A arquitetura x86 é encontrada em quase todos os sistemas de computadores pessoais (incluindo PCs Windows e Linux e Macs) e servidores. Os computadores pessoais são de interesse porque todo leitor sem dúvida já usou um. Os servidores são de interesse porque eles rodam todos os serviços na nternet. A arquitetura ARM domina o mercado móvel. Por exemplo, a maioria dos smartphones e computadores tablet é baseada em processadores ARM. Por fim, a arquitetura AR é empregada em microcontroladores de muito baixo custo, encontrados em muitas aplicações de computação embutidas. Computadores embutidos são invisíveis aos seus usuários, mas controlam carros, televisões, fornos de micro-ondas, máquinas de lavar e praticamente cada dispositivo elétrico que custa mais de 50 dólares. Nesta seção, faremos uma breve introdução às três arquiteturas de conjunto de instruções que serão usadas como exemplos no restante do livro.
  • 50. C a p  t u l o 1 I n t r o d u c  a  o 31 1.4.1 Introduc a o a  arquitetura x86 Em 1968, Robert Noyce, inventor do circuito integrado de silício, Gordon Moore, aquele famoso pela lei de Moore, e Arthur Rock, um capitalista de risco de São Francisco, formaram a ntel Corporation para fabricar chips de memória. Em seu primeiro ano de operação, a ntel vendeu apenas 3 mil dólares de chips, mas desde então o negócio melhorou (a ntel agora é o maior fabricante de chips de CPU do mundo). No final da década de 1960, as calculadoras eram grandes máquinas eletromecânicas do tamanho de uma moderna impressora a laser e pesavam 20 kg. Em setembro de 1969, uma empresa japonesa, a Busicom, consultou a ntel sobre um pedido de fabricação de 12 chips sob encomenda para uma calculadora eletrônica proposta. Ted Hoff, o engenheiro da ntel designado para esse projeto, analisou o plano e percebeu que podia colocar uma CPU de uso geral de 4 bits em um único chip, que faria a mesma coisa e seria mais simples e tam- bém mais barata. Assim, nascia, em 1970, a primeira CPU de um só chip com 2.300 transistores, denominada 4004 (Faggin et al., 1996). ale a pena observar que nem a ntel nem a Busicom tinham a mínima ideia do que acabavam de fazer. Quando a ntel decidiu que poderia valer a pena tentar usar a 4004 em outros projetos, propôs à Busicom comprar de volta os direitos ao novo chip devolvendo os 60 mil dólares que aquela empresa pagara à ntel para desenvolvê- -lo. A oferta foi aceita de pronto e então a ntel começou a trabalhar em uma versão de 8 bits do chip, o 8008, lançado em 1972. A família ntel, que começou com o 4004 e o 8008, é mostrada na Figura 1.11, com a data de introdução, taxa de clock, quantidade de transistores e memória. Figura 1.11 Principais membros da fam lia de CPUs da Intel. As velocidades de clock sa o medidas em MHz (megahertz) em que 1 MHz e  1 milha o de ciclos/s. Chip Data MHz Trans. Memória Notas 4004 4/1971 0,108 2.300 640 Primeiro microprocessador em um chip 8008 4/1972 0,108 3.500 16 KB Primeiro microprocessador de 8 bits 8080 4/1974 2 6.000 64 KB Primeira CPU de uso geral em um chip 8086 6/1978 5–10 29.000 1 MB Primeira CPU de 16 bits em um chip 8088 6/1979 5–8 29.000 1 MB Usada no IBM PC 80286 2/1982 8–12 134.000 16 MB Com proteção de memória 80386 10/1985 16–33 275.000 4 GB Primeira CPU de 32 bits 80486 4/1989 25–100 1,2M 4 GB Memória cache de 8 KB embutida Pentium 3/1993 60–233 3,1M 4 GB Dois pipelines; modelos posteriores tinham MMX Pentium Pro 3/1995 150–200 5,5M 4 GB Dois níveis de cache embutidos Pentium II 5/1997 233–450 7,5M 4 GB Pentium Pro mais instruções MMX Pentium III 2/1999 650–1.400 9,5M 4 GB Instruções SSE para gráficos em 3D Pentium 4 11/2000 1.300–3.800 42M 4 GB Hyperthreading; mais instruções SSE Core Duo 1/2006 1.600–3.200 152M 2 GB Dual cores em um único substrato Core 7/2006 1.200–3.200 410M 64 GB Arquitetura quad core de 64 bits Core i7 1/2011 1.100–3.300 1.160M 24 GB Processador gráfico integrado Como a empresa não esperava muita demanda pelo 8008, montou uma linha de produção de baixo volume. Para o espanto de todos, houve um enorme interesse, portanto, a ntel passou a projetar um novo chip de CPU que ultrapassava o limite de 16 kilobytes de memória do 8008 (imposto pelo número de pinos no chip). Esse projeto resultou no 8080, uma CPU pequena, de uso geral, lançada em 1974. Muito parecido com o PDP-8, esse produto tomou o setor de assalto e se tornou de imediato um item de mercado de massa. Só que, em vez de vender milhares, como a DEC tinha vendido, a ntel vendeu milhões.
  • 51. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 32 Em 1978, veio o 8086, uma genuína CPU de 16 bits em um único chip. O 8086 foi projetado para ser seme- lhante ao 8080, mas não era totalmente compatível com o 8080. O 8086 foi seguido pelo 8088, que tinha a mesma arquitetura do 8086 e executava os mesmos programas, mas tinha um barramento de 8 bits, em vez de 16 bits, o que o tornava mais lento e mais barato do que o 8086. Quando a BM escolheu o 8088 como a CPU do BM PC original, esse chip rapidamente se tornou o padrão da indústria dos computadores pessoais. Nem o 8088 nem o 8086 podiam endereçar mais do que 1 megabyte de memória. No início da década de 1980, isso se tornou um problema cada vez mais sério, por isso a ntel projetou o 80286, uma versão do 8086 compatível com os chips anteriores. O conjunto de instruções básicas era em essência o mesmo do 8086 e do 8088, mas a organização da memória era bem diferente e um pouco desajeitada por causa do requisito de compa- tibilidade com os chips mais antigos. O 80286 foi usado no BM PC/AT e nos modelos de faixa média PS/2. Assim como o 8088, ele foi um grande sucesso, em grande parte, porque todos o consideravam um 8088 mais veloz. O próximo passo lógico seria uma verdadeira CPU de 32 bits em um chip, o 80386, lançado em 1985. Assim como o 80286, esse chip era mais ou menos compatível com tudo que havia antes, até o 8080. Sendo compatível com a família anterior, era importante para pessoas que queriam rodar velhos programas, mas um aborrecimento para quem preferia uma arquitetura simples, limpa e moderna que não fosse prejudicada pelos erros e pela tec- nologia do passado. Quatro anos mais tarde, foi lançado o 80486 que, em essência, era uma versão mais veloz do 80386, que também tinha uma unidade de ponto flutuante e 8 kilobytes de memória cache no chip. A memória cache é usada para conter as palavras de memória mais usadas, dentro ou próximas da CPU, de modo a evitar o acesso (lento) à memória principal. O 80486 também tinha suporte de multiprocessador embutido, o que permitia que os fabri- cantes construíssem sistemas com várias CPUs que compartilhavam uma memória em comum. Nesse ponto, a ntel descobriu do modo mais difícil (perdendo uma ação judicial de violação de marca regis- trada) que números (como 80486) não podem ser considerados marca registrada, portanto, a geração seguinte ganhou um nome: Pentium (da palavra grega para cinco, πεντε). Diferente do 80486, que tinha um só pipeline interno, o Pentium tinha dois, o que ajudava a torná-lo duas vezes mais rápido (discutiremos pipelines em deta- lhes no Capítulo 2). Mais tarde, a ntel acrescentou à linha de produção as instruções especiais MMX (MultiMedia eXtension). O propósito dessas instruções era acelerar os cálculos exigidos para processar áudio e vídeo, o que tornou desne- cessária a adição de coprocessadores especiais de multimídia. Quando a próxima geração apareceu, quem estava esperando por um Sexium (sex é “seis” em latim) ficou desapontado. O nome Pentium agora era tão conhecido que o pessoal de marketing resolveu conservá-lo, e o novo chip foi denominado Pentium Pro. A despeito da pequena mudança de nome em relação a seu antecessor, esse processador representou uma grande ruptura com o passado. Em vez de ter dois ou mais pipelines, o Pentium Pro tinha uma organização interna muito diferente e podia executar até cinco instruções por vez. Outra inovação encontrada no Pentium Pro era uma memória cache de dois níveis. O chip do processador em si tinha 8 kilobytes de memória rápida para conter instruções mais usadas e mais 8 kilobytes de memória rápida para conter dados mais usados. Na mesma cavidade dentro do pacote Pentium Pro (mas não no chip em si) havia uma segunda memória cache de 256 kilobytes. Embora o Pentium Pro tivesse uma grande cache, faltavam as instruções MM (porque a ntel não conse- guiu fabricar um chip tão grande com desempenho aceitável). Quando a tecnologia melhorou o bastante para conseguir colocar as instruções MM e a cache no mesmo chip, o produto combinado foi lançado como Pentium . Logo após, foram adicionadas ainda mais instruções de multimídia, denominadas SSE (Streaming SIM Extensions), para melhorar os gráficos em 3D (Raman et al., 2000). O novo chip foi denominado Pentium , mas internamente era, em essência, um Pentium . O próximo Pentium, lançado em novembro de 2000, era baseado em uma arquitetura interna diferente, mas tinha o mesmo conjunto de instruções dos anteriores. Para celebrar esse evento, a ntel mudou de algarismos romanos para algarismos arábicos e o denominou Pentium 4. Como sempre, o Pentium 4 era mais rápido do que todos os seus antecessores. A versão de 3,06 GHz também introduziu uma nova e intrigante característica,
  • 52. C a p  t u l o 1 I n t r o d u c  a  o 33 o hyperthreading. Essa característica permitia que os programas distribuíssem seu trabalho para dois threads de controle que o Pentium 4 podia executar em paralelo, acelerando a execução. Além disso, foi acrescentado um novo lote de instruções SSE para acelerar ainda mais o processamento de áudio e vídeo. Em 2006, a ntel mudou o nome da marca Pentium para Core e lançou um chip dual core, o Core 2 duo. Quando a ntel decidiu que queria uma versão mais barata em um único núcleo do chip, ela simplesmente ven- deu os Core 2 duos com um núcleo desabilitado, pois desperdiçar um único silício em cada chip fabricado, por fim, era mais barato do que incorrer na enorme despesa de projetar e testar um novo chip do zero. A série Core continuou a evoluir, com o i3, i5 e i7 sendo variantes populares para computadores com desempenho baixo, médio e alto. Sem dúvida, haverá mais variantes. Uma foto do i7 aparece na Figura 1.12. Na realidade, existem oito núcleos nela, mas, exceto na versão eon, somente seis estão habilitados. Essa técnica significa que um chip com um ou dois núcleos com defeito ainda será vendido, desabilitando o(s) defeituoso(s). Cada núcleo tem suas próprias caches de nível 1 e 2, mas há também uma cache de nível 3 (L3) compartilhada, usada por todos os núcleos. Discutiremos as caches com mais detalhes em outro ponto deste livro. Figura 1.12 O chip Intel Core i7-3960X. O substrato tem 21 × 21 mm e 2,27 bilho es de transistores. Direitos da fotografia da Intel Corporation, 2011, reproduc a o permitida. Fila, Uncore & E/S Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Cache L3 compartilhado Controlador de memória Além das CPUs de desktop de uso geral discutidas até aqui, a ntel fabricou variantes de alguns dos chips Pentium para mercados especiais. No início de 1998, introduziu uma nova linha de produtos chamada Celeron, que era uma versão de baixo custo e baixo desempenho do Pentium 2, voltada para PCs inferiores. Uma vez que o Celeron tem a mesma arquitetura Pentium 2, não o discutiremos mais neste livro. Em junho de 1998, lançou uma versão especial do Pentium 2 para a faixa mais alta do mercado. Esse processador, denominado Xeon, tinha uma cache maior, barramento mais rápido e melhor suporte de microprocessador, mas, fora isso, era um Pentium 2 normal, portanto, tampouco vamos discuti-lo em separado. O Pentium  também teve uma versão eon, assim como os chips mais recentes. Nestes, um recurso do eon é a maior quantidade de núcleos. Em 2003, a ntel lançou o Pentium M (de Mobile), um chip projetado para notebooks. Esse chip era parte da arquitetura Centrino, cujos objetivos eram menor consumo de energia para maior tempo de vida útil das baterias, computadores menores e mais leves, e capacidade de rede sem fio embutida usando o padrão EEE 802.11 (WiFi).
  • 53. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 34 O Pentium M consumia muito menos potência e era muito menor que o Pentium 4, duas características que logo lhe permitiriam (e aos seus sucessores) substituir a microarquitetura do Pentium 4 em produtos futuros da ntel. Todos os chips da ntel são compatíveis com seus antecessores até os antigos 8086. Em outras palavras, um Pentium 4 pode executar antigos programas 8086 sem modificação. A ntel sempre considerou essa compatibili- dade como um requisito de projeto, para permitir que seus usuários não percam seus investimentos em software. Claro que o Pentium 4 é quatro ordens de grandeza mais complexo do que o 8086, por isso pode fazer algumas coisas que o 8086 não podia. Essas extensões escalonadas resultaram em uma arquitetura que não é tão elegante quanto poderia ter sido se alguém tivesse dado aos arquitetos do Pentium 4 42 milhões de transistores e instru- ções para começar tudo de novo. É interessante notar que, embora a lei de Moore venha há tempos sendo associada com o número de bits em uma memória, ela se aplica igualmente bem a chips de CPU. Plotando o número de transistores dados na Figura 1.8 contra as datas de lançamento de cada chip em uma escala semilogarítmica, vemos que a lei de Moore também vale nesse caso. Esse gráfico é apresentado na Figura 1.13. Figura 1.13 Lei de Moore para chips de CPU (Intel). Lei de Moore Ano de lançamento 2010 2005 2000 1995 1990 1985 1980 1975 8008 4004 8080 8086 80286 Pentium Pentium II Pentium III Pentium 4 Core Duo Core 2 Core i7 8008 80386 80486 Pentium Pro 1970 1 10 100 1K 10K 100K 1M 10M 100M 1G 10G Transistores Embora a lei de Moore provavelmente continue válida por alguns anos ainda, outro problema está come- çando a lançar uma sombra sobre ela: a dissipação de calor. Transistores menores possibilitam execução em fre- quências de clock mais altas, o que requer a utilização de uma tensão mais alta. O consumo de energia e o calor dissipado são proporcionais ao quadrado da tensão elétrica, portanto, execução mais rápida significa ter mais calor para se livrar. Em 3,6 GHz, o Pentium 4 consome 115 watts de potência, o que significa que ele fica quase tão quente quanto uma lâmpada de 100 watts. Acelerar o clock agrava o problema. Em novembro de 2004, a ntel cancelou o Pentium 4 de 4 GHz por causa de problemas de dissipação de calor. Grandes ventiladores podem ajudar, mas o barulho que fazem não agrada aos usuários, e a refrigeração com água, embora usada em grandes mainframes, não é uma opção viável para equipamentos de desktop (menos ainda para notebooks). Como consequência, a antes implacável marcha do clock pode ter terminado, ao menos até que os engenheiros da ntel descubram como se livrar com eficiência de todo o calor gerado. Em vez disso, os planos atuais da ntel são colocar duas ou mais CPUs em um mesmo chip, junto com uma grande cache compar- tilhada. Por causa do modo como o consumo de energia está relacionado com a tensão elétrica e a velocidade de clock, duas CPUs em um chip consomem muito menos energia do que uma CPU a uma velocidade duas vezes maior. Como consequência, o ganho oferecido pela lei de Moore pode ser ainda mais explorado no futuro para incluir mais núcleos e caches cada vez maiores embutidas em um chip, em vez de velocidades de clock cada vez
  • 54. C a p  t u l o 1 I n t r o d u c  a  o 35 mais altas. Tirar proveito desses multiprocessadores impõe grandes desafios aos programadores, pois, diferente das sofisticadas microarquiteturas uniprocessador, os multiprocessadores exigem que o programador orquestre explicitamente a execução paralela, usando threads, semáforos, memória compartilhada e outras tecnologias que causam bugs e dores de cabeça. 1.4.2 Introduc a o a  arquitetura ARM No início da década de 1980, a empresa Acorn Computer, sediada na Grã-Bretanha, após o sucesso de seu computador pessoal de 8 bits BBC Micro, começou a trabalhar em uma segunda máquina com a esperança de competir com o recém-lançado BM PC. O BBC Micro era baseado no processador de 8 bits 6502, e Steve Furber e seus colegas da Acorn acharam que o 6502 não tinha força para competir com o processador de 16 bits 8086 do BM PC. Eles começaram a examinar as opções no mercado, e decidiram que estavam muito limitados. nspirados pelo projeto RSC de Berkeley, em que uma pequena equipe projetou um processador incrivel- mente rápido (que, por fim, levou à arquitetura SPARC), decidiram montar sua própria CPU para o projeto. Eles chamaram seu projeto de Acorn RSC Machine (ou ARM, que mais tarde seria rebatizado para a máquina Advanced RSC, quando o ARM por fim se separou da Acorn). O projeto foi concluído em 1985. Ele incluía ins- truções e dados de 32 bits, um espaço de endereços de 26 bits, e foi fabricado pela LS Technology. A primeira arquitetura ARM (denominada ARM2) apareceu no computador pessoal Acorn Archimedes. O Archimedes era uma máquina muito rápida e barata para a sua época, rodando em até 2 MPS (milhões de instru- ções por segundo) e custando apenas 899 libras esterlinas no lançamento. A máquina tornou-se muito popular na Grã-Bretanha, rlanda, Austrália e Nova Zelândia, em especial nas escolas. Com base no sucesso do Archimedes, a Apple fez contato com a Acorn para desenvolver um processa- dor ARM para seu próximo projeto Apple Newton, o primeiro computador palmtop. Para focar melhor no projeto, a equipe de arquitetura ARM saiu da Acorn para criar uma nova empresa, chamada Advanced RSC Machines (ARM). Seu novo processador foi chamado de ARM 610, que controlou o Apple Newton quando ele foi lançado em 1993. Diferente do projeto ARM original, esse novo processador ARM incorporava uma cache de 4 KB, o que melhorou significativamente o desempenho do projeto. Embora o Apple Newton não tenha sido um grande sucesso, o ARM 610 viu outras aplicações bem-sucedidas, incluindo o computador RSC PC da Acorn. Em meados dos anos 1990, a ARM colaborou com a Digital Equipment Corporation para desenvolver uma versão de alta velocidade e baixa potência do ARM, voltada para aplicações móveis com escassez de energia, como PDAs. Eles produziram o projeto StrongARM, que desde o seu lançamento causou um rebuliço no setor devido à sua alta velocidade (233 MHz) e demandas de potência ultrabaixa (1 watt). Ele ganhou eficiência por meio de um projeto simples e limpo, que incluía duas caches de 16 KB para instruções e dados. O StrongARM e seus suces- sores na DEC foram moderadamente bem-sucedidos no mercado, fazendo parte de diversos PDAs, transdutores de T, dispositivos de mídia e roteadores. Talvez a mais venerável das arquiteturas ARM seja o projeto ARM7, lançado inicialmente pela ARM em 1994 e ainda bastante utilizado hoje em dia. O projeto incluía caches separados para instrução e dados, e também incorporava o conjunto de instruções de 16 bits Thumb. O conjunto de instruções Thumb é uma versão reduzida do conjunto de instruções completo de 32 bits do ARM, permitindo que os programadores codifiquem muitas das operações mais comuns em instruções menores de 16 bits, reduzindo bastante a quantidade de memória de programa necessária. O processador funcionava bem para uma grande variedade de aplicações embutidas, de nível inferior a médio, como torradeiras, controle de motor e até mesmo o console de jogos portátil Gameboy Advance da Nintendo. Diferente de muitas empresas de computador, a ARM não fabrica qualquer microprocessador. Em vez disso, ela cria projetos e ferramentas e bibliotecas para o desenvolvedor baseadas em ARM, licenciando-as para proje- tistas de sistemas e fabricantes de chips. Por exemplo, a CPU usada no computador tablet Samsung Galaxy Tab baseado no Android é um processador baseado no ARM. O Galaxy Tab contém o processador de sistema-em-um- -chip Tegra 2, que inclui dois processadores ARM Cortex-A9 e uma unidade de processamento gráfico Nvidia
  • 55. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 36 GeForce. Os núcleos do Tegra 2 foram projetados pela ARM, integrados a um projeto de sistema-em-um-chip pela Nvidia e fabricados pela Taiwan Semiconductor Manufacturing Company (TSMC). Essa é uma colaboração impressionante por empresas em diferentes países, na qual todas elas agregaram valor ao projeto final. A Figura 1.14 mostra uma foto do substrato do sistema-em-um-chip Tegra 2 da Nvidia. O projeto contém três processadores ARM: dois núcleos ARM Cortex-A9 de 1,2 GHz mais um núcleo ARM7. Os núcleos Cortex-A9 são núcleos fora de ordem de emissão dual e uma cache L2 de 1 MB, com suporte para multiprocessamento de memória compartilhada. (Todos esses termos serão explicados em outros capítulos. Por enquanto, basta saber que esses recursos tornam o projeto muito veloz!) O núcleo ARM7 é um núcleo ARM mais antigo e menor, usado para configuração do sistema e gerenciamento de energia. O núcleo gráfico é um projeto com uma unidade de processamento gráfico (GPU) GeForce de 333 MHz, otimizado para operação com baixa potência. Também incluídos no Tegra 2 estão um codificador/decodificador de vídeo, um processador de áudio e uma interface de saída de vídeo HDM. Figura 1.14 O sistema Nvidia Tegra 2 em um chip. Direitos de reproduc a o da Nvidia Corporation, 2011, reproduc a o permitida. Processador de sinal de imagem Processador de codificação de vídeo Processador de áudio Vídeo dual HDMI NAND Processador de decodificação de vídeo E/S USB Cache CPU A7 CPU Cortex A9 CPU Cortex A9 Processador gráfico A arquitetura ARM teve grande sucesso nos mercados de dispositivos de baixa potência, móveis e embutidos. Em janeiro de 2011, a ARM anunciou que tinha vendido 15 bilhões de processadores desde o seu lançamento, e indicou que as vendas estavam continuando a crescer. Embora apropriada para mercados de classe mais baixa, a arquitetura ARM tem a capacidade de computação para funcionar em qualquer mercado, e existem indícios de que poderá estar expandindo seus horizontes. Por exemplo, em outubro de 2011, foi anunciado um ARM de 64 bits. Também em janeiro de 2011, a Nvidia anunciou o “Projeto Denver”, um sistema-em-um-chip baseado em ARM, sendo desenvolvido para o mercado de servidores e outros. O projeto irá incorporar vários processadores ARM de 64 bits e mais uma GPU de uso geral (GPGPU). Os aspectos de baixa potência do projeto ajudarão a reduzir os requisitos de resfriamento de server farms e data centers.
  • 56. C a p  t u l o 1 I n t r o d u c  a  o 37 1.4.3 Introduc a o a  arquitetura AVR Nosso terceiro exemplo é muito diferente do primeiro (a arquitetura x86, usada em computadores pessoais e servidores) e do segundo (a arquitetura ARM, usada em PDAs e smartphones). É a arquitetura AR, usada em sistemas embutidos de muito baixo nível. A história do AR começa em 1996, no Norwegian nstitute of Technology, onde os estudantes Alf-Egil Bogen e egard Wollan projetaram uma CPU RSC de 8 bits chamada AR. Esse nome supostamente significa “(A)lf and ()egard’s (R)SC processor” (processador RSC de Alf e egard). Logo depois que o projeto foi concluído, a Atmel o comprou e lançou a Atmel Norway, onde os dois arquitetos continuaram a refinar o projeto do processador AR. A Atmel lançou seu primeiro microcontrolador AR, o AT90S1200, em 1997. Para facilitar sua adoção pelos projetistas de sistemas, eles executaram a pinagem para que fosse idêntica à do ntel 8051, que era um dos microcontroladores mais populares da época. Hoje, há muito interesse na arquitetura AR porque ela está no centro da plataforma muito popular de controle embutido Arduino, de fonte aberta. A arquitetura AR é realizada em três classes de microcontroladores, listados na Figura 1.15. A classe mais baixa, a tinyAR, foi projetada para aplicações mais restritas quanto a superfície, potência e custo. Ela inclui uma CPU de 8 bits, suporte digital básico para E/S e suporte para entrada analógica (por exemplo, na leitura de valores de temperatura de um termômetro). O tinyAR é tão pequeno que seus pinos trabalham com dupla função, de modo que podem ser reprogramados em tempo de execução para qualquer uma das funções digitais ou analógicas admitidas pelo microcontrolador. O megaAR, que é encontrado no popular sistema embutido de fonte aberta Arduino, também acrescenta suporte para E/S serial, clocks internos e saídas analógicas programáveis. O topo de linha nessa ponta inferior é o microcontrolador AR MEGA, que também incorpora um acelerador para opera- ções criptográficas e mais suporte interno para interfaces USB. Figura 1.15 Classes de microcontrolador na fam lia AVR. Chip Flash EEPROM RAM Pinos Características tinyAVR 0,5–16 KB 0–512 B 32–512 B 6–32 Pequeno, E/S digital, entrada analógica megaAVR 8–256 KB 0,5–4 KB 0,25–8 KB 28–100 Muitos periféricos, saída analógica AVR XMEGA 16–256 KB 1–4 KB 2–16 KB 44–100 Aceleração criptográfica, E/S USB Junto com diversos periféricos adicionais, cada classe de processador AR inclui alguns recursos de memória adicionais. Os microcontroladores possuem em geral três tipos de memória na placa: flash, EEPROM e RAM. A memória flash é programável usando uma interface externa e altas voltagens, e é nela que são armazenados código de programa e dados. A RAM flash é não volátil, de modo que, mesmo que o sistema perca a energia, a memória flash se lembrará do que foi gravado nela. Assim como a flash, a EEPROM também é não volátil, mas, diferente da RAM flash, ela pode ser mudada pelo programa enquanto está rodando. Esse é o armazenamento em que um sistema embutido manteria informações de configuração do usuário, como se o seu relógio mostra as horas em formato de 12 ou 24 horas. Por fim, a RAM é onde as variáveis do programa serão armazenadas enquanto o pro- grama roda. Essa memória é volátil, de modo que qualquer valor armazenado aqui será perdido quando o sistema estiver sem energia. Estudamos os tipos de RAM volátil e não volátil com detalhes no Capítulo 2. A receita para o sucesso no negócio de microcontroladores é colocar no chip tudo o que ele possivelmente precisará (e a pia da cozinha também, se puder ser reduzida para um milímetro quadrado) e depois colocá-lo em um pacote barato e pequeno, com muito poucos pinos. ntegrando muitas características no microcontrolador, ele pode funcionar para muitas aplicações, e tornando-o barato e pequeno, ele pode caber em muitos tamanhos. Para entender melhor quantas coisas podem caber em um microcontrolador moderno, vejamos os periféricos incluídos no Atmel ATmega168 AR:
  • 57. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 38 1. Três temporizadores (dois temporizadores de 8 bits e um de 16 bits). 2. Clock de tempo real com oscilador. 3. Seis canais por modulação de largura de pulso usados, por exemplo, para controlar a intensidade da luz ou a velocidade do motor. 4. Oito canais de conversão analógico-digital usados para ler níveis de tensão elétrica. 5. Receptor/transmissor serial universal. 6. nterface serial 2C, um padrão comum para a interface com sensores. 7. Temporizador de vigia programável, que detecta quando o sistema ficou travado. 8. Comparador analógico no chip, que compara duas tensões de entrada. 9. Detector de falha de energia, que interrompe o sistema quando a energia estiver faltando. 10. Oscilador de clock interno programável, para controlar o clock da CPU. 1.5 Unidades me tricas Para evitar qualquer confusão, vale a pena deixar explícito que, neste livro, assim como na ciência da computação em geral, são usadas unidades métricas em vez das tradicionais unidades inglesas (o sistema furlong-stone- -fortnight). Os principais prefixos métricos estão relacionados na Figura 1.16. Os prefixos costumam ser abrevia- dos por suas primeiras letras, sendo a unidade maior do que 1 em maiúsculas (KB, MB etc.). Uma exceção (por razões históricas) é kbps para kilobits/s. Assim, uma linha de comunicação de 1 Mbps transmite 106 bits/s e um relógio de 100 ps bate a cada 10–10 segundos. Uma vez que ambos os prefixos, mili e micro, começam com a letra “m”, foi preciso fazer uma escolha. Normalmente, “m” representa mili e “μ” (a letra grega mu) representa micro. Figura 1.16 Os principais prefixos me tricos. Exp. Explícito Prefixo Exp. Explícito Prefixo 10–3 0,001 mili 103 1.000 kilo 10–6 0,000001 micro 106 1.000.000 mega 10–9 0,000000001 nano 109 1.000.000.000 giga 10–12 0,000000000001 pico 1012 1.000.000.000.000 tera 10–15 0,000000000000001 femto 1015 1.000.000.000.000.000 peta 10–18 0,000000000000000001 ato 1018 1.000.000.000.000.000.000 exa 10–21 0,000000000000000000001 zepto 1021 1.000.000.000.000.000.000.000 zeta 10–24 0,000000000000000000000001 iocto 1024 1.000.000.000.000.000.000.000.000 iota Também vale a pena lembrar que, para medir tamanhos de memórias, discos, arquivos e banco de dados, na prática comum do setor as unidades têm significados ligeiramente diferentes. Quilo, por exemplo, significa 210 (1.024) em vez de 103 (1.000), porque as memórias são sempre uma potência de dois. Assim, uma memó- ria de 1 KB contém 1.024 bytes, e não 1.000 bytes. De modo semelhante, uma memória de 1 MB contém 220 (1.048.576) bytes, uma memória de 1 GB contém 230 (1.073.741.824) bytes e um banco de dados de 1 TB contém 240 (1.099.511.627.776) bytes.
  • 58. C a p  t u l o 1 I n t r o d u c  a  o 39 Todavia, uma linha de comunicação de 1 kbps pode transmitir 1.000 bits por segundo e uma LAN de 10 Mbps funciona a 10.000.000 bits/s porque essas velocidades não são potências de dois. nfelizmente, muitas pes- soas confundem esses dois sistemas, em especial quando se tratam de tamanhos de disco. Para evitar ambiguidade, as organizações de padrões introduziram os novos termos kibibyte para 210 bytes, mebibyte para 220 bytes, gibibyte para 230 bytes e tebibyte para 240 bytes, mas o setor não os adotou ainda. Achamos que, até esses novos termos serem mais utilizados, é melhor ficar com os símbolos KB, MB, GB e TB para 210 , 220 , 230 e 240 bytes, respectivamente, e os símbolos kbps, Mbps, Gbps e Tbps para 103 , 106 , 109 e 1012 bits/s, respectivamente. 1.6 Esquema deste livro Este livro trata de computadores multiníveis (o que inclui praticamente todos os computadores modernos) e de como eles são organizados. Examinaremos quatro níveis com considerável detalhe – a saber, o nível lógico digital, o da microarquitetura, o SA e o do sistema operacional da máquina. Entre alguns dos assuntos básicos examinados estão o projeto global do nível (e por que foi projetado desse jeito), os tipos de instruções e dados disponíveis, a organização e endereçamento da memória e o método de execução do nível. O estudo desses tópicos e de tópicos semelhantes é denominado organização de computadores ou arquitetura de computadores. Preocupamo-nos principalmente com os conceitos, em vez dos detalhes ou da matemática formal. Por esse motivo, alguns dos exemplos dados serão um pouco simplificados, a fim de enfatizar as ideias centrais, e não os detalhes. Para dar uma ideia de como os princípios apresentados neste livro podem ser, e são, aplicados na prática, usaremos as arquiteturas x86, ARM e AR como exemplos correntes em todo o livro. Esses três foram escolhidos por diversas razões. Primeiro, todos são muito usados e é provável que o leitor tenha acesso a no mínimo um deles. Segundo, cada um tem sua própria arquitetura exclusiva, o que dá uma base de comparação e incentiva uma atitude de questionamento a respeito das possíveis alternativas. Livros que tratam apenas de uma máquina costumam deixar o leitor com uma sensação de estar revelando um projeto de máquina absoluto, o que é absurdo à luz das muitas concessões e decisões arbitrárias que os projetistas são obrigados a tomar. ncentivamos estudar esses e todos os outros computadores com espírito crítico e tentar entender por que as coisas são como são e também como poderiam ser diferentes, em vez de simplesmente aceitá-las como fatos. É preciso que fique claro desde o início que este livro não diz respeito a programar o x86, ARM ou AR. Essas máquinas serão usadas como ilustração quando adequado, mas não temos a pretensão de sermos completos. Os leitores que desejarem uma introdução minuciosa a uma delas devem consultar o material publicado pelos fabricantes. O Capítulo 2 é uma introdução aos componentes básicos de um computador – processadores, memórias e equipamento de E/S. Pretende oferecer uma visão geral da arquitetura de sistema e uma introdução aos capítulos seguintes. Cada um dos capítulos seguintes – 3, 4, 5 e 6 – trata de um único nível específico mostrado na Figura 1.2. Nosso tratamento é de baixo para cima, porque as máquinas são tradicionalmente projetadas dessa maneira. O projeto do nível k é determinado em grande parte pelas propriedades do nível k – 1, portanto, é difícil entender qualquer nível, a menos que você já tenha um bom domínio do nível subjacente que o motivou. Além disso, em termos educacionais, parece mais sensato partir dos níveis inferiores mais simples para os níveis superiores mais complexos do que o contrário. O Capítulo 3 é sobre o nível lógico digital, o verdadeiro hardware da máquina. Discute o que são portas e como podem ser combinadas para formar circuitos úteis. Também introduzimos a álgebra booleana, uma ferramenta para analisar circuitos digitais. São explicados barramentos de computador, em especial o popular barramento PC. Nesse capítulo, são discutidos diversos exemplos do setor, incluindo os três exemplos cor- rentes já mencionados.
  • 59. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 40 O Capítulo 4 apresenta a arquitetura do nível de microarquitetura e seu controle. Uma vez que a função desse nível é interpretar instruções de nível 2 na camada acima dele, nós nos concentraremos nesse tópico e o ilustraremos por meio de exemplos. O capítulo também contém discussões do nível de microarquitetura de algu- mas máquinas reais. O Capítulo 5 discute o nível SA, aquele que a maioria dos fornecedores anuncia como a linguagem de máquina. Aqui, examinaremos em detalhes nossas máquinas de exemplo. O Capítulo 6 abrange algumas das instruções, organização de memória e mecanismos de controle presentes no nível do sistema operacional da máquina. Os exemplos usados aqui são o sistema operacional Windows (popu- lar em sistemas de desktop baseados no x86) e o Unix, usado em muitos sistemas baseados no ARM. O Capítulo 7 trata do nível de linguagem de montagem. Abrange a linguagem de montagem e o processo de montagem. Aqui também é apresentado o tópico da ligação. O Capítulo 8 discute computadores paralelos, um tópico de crescente importância nos dias de hoje. Alguns desses computadores paralelos têm múltiplas CPUs que compartilham a mesma memória. Outros têm múltiplas CPUs sem memória em comum. Alguns são supercomputadores; alguns são sistemas em um chip e outros são clusters de computadores. O Capítulo 9 contém uma lista comentada de leituras sugeridas, que estão na Sala irtual. Consulte <sv.pearson.com.br>. Problemas 1. Explique cada um dos termos seguintes com suas próprias palavras: a. Tradutor. b. nterpretador. c. Máquina virtual. 2. É concebível um compilador gerar saída para o nível de microarquitetura em vez de para o nível SA? Discuta prós e contras dessa proposta. 3. ocê pode imaginar qualquer computador multiní- veis no qual o nível de dispositivo e os níveis lógi- cos digitais não estivessem nos níveis mais baixos? Explique. 4. Considere um computador multinível no qual todos os níveis são diferentes. Cada nível tem instruções que são m vezes mais poderosas do que as do nível abaixo dele; isto é, uma instrução de nível r pode fazer o trabalho de m instruções de nível r – 1. Se um programa de nível 1 requer k segundos para execu- tar, quanto tempo levariam programas equivalentes nos níveis 2, 3 e 4 admitindo que são necessárias n instruções de nível r para interpretar uma única instrução de nível r + 1? 5. Algumas instruções no nível do sistema operacional da máquina são idênticas a instruções em linguagem SA. Elas são executadas diretamente pelo micropro- grama ou pelo hardware, e não pelo sistema opera- cional. À luz de sua resposta ao problema anterior, por que você acha que isso acontece? 6. Considere um computador com interpretadores idênticos nos níveis 1, 2 e 3. Um interpretador preci- sa de n instruções para buscar, examinar e executar uma instrução. Uma instrução de nível 1 demora k nanossegundos para executar. Quanto tempo demo- ra para executar uma instrução nos níveis 2, 3 e 4? 7. Em que sentido hardware e software são equivalen- tes? E não equivalentes? 8. A máquina diferencial de Babbage tinha um progra- ma fixo que não podia ser trocado. sso é em essência a mesma coisa que um CD-ROM moderno que não pode ser trocado? Explique sua resposta. 9. Uma das consequências da ideia de von Neumann de armazenar um programa na memória é que esses programas podem ser modificados, exatamente como os dados. ocê consegue imaginar um exemplo onde essa facilidade poderia ser útil? (Dica: pense em efe- tuar aritmética em vetores.) 10. A relação entre desempenho do 360 modelo 75 e do 360 modelo 30 era de 50 vezes. Ainda assim, o tempo de ciclo era só cinco vezes mais rápido. Como você explica essa discrepância? 11. Dois projetos de sistemas são mostrados nas figuras 1.5 e 1.6. Descreva como poderia ocorrer entrada/
  • 60. C a p  t u l o 1 I n t r o d u c  a  o 41 saída em cada sistema. Qual deles tem potencial para melhor desempenho global do sistema? 12. Suponha que cada um dos 300 milhões de habitantes dos Estados Unidos consome totalmente dois pacotes de mercadoria por dia marcados com etiquetas RFD. Quantas dessas etiquetas teriam de ser produzidas por ano para satisfazer à demanda? Se a etiqueta cus- tar um centavo de dólar por unidade, qual é o custo total das etiquetas? Dado o tamanho do PB, essa quantia será um obstáculo à sua utilização em cada pacote oferecido à venda? 13. Dê o nome de três eletrodomésticos ou aparelhos candidatos a funcionar com uma CPU embutida. 14. Em certa época, um transistor instalado em um microprocessador tinha 0,1 mícron de diâmetro. Segundo a lei de Moore, que tamanho teria um tran- sistor no modelo do ano seguinte? 15. Mostrou-se que a lei de Moore não se aplica apenas à densidade de semicondutores, mas também prevê o aumento em tamanhos de simulação (razoáveis), e a redução nos tempos de simulação de cálculo. Primeiro, mostre, para uma simulação de mecânica de fluidos que gasta 4 horas para rodar em uma máquina hoje, que só deverá gastar 1 hora para rodar em máquinas montadas daqui a 3 anos, e apenas 15 minutos em máquinas montadas daqui a 6 anos. Depois, mostre que, para uma simulação grande, que possui um tempo de execução estimado de 5 anos, ela seria completada mais cedo se esperássemos 3 anos para iniciar a simulação. 16. Em 1959, o BM 7090 poderia executar cerca de 500 mil instruções/s, tinha uma memória de 32.768 pala- vras de 36 bits e custava US$ 3 milhões. Compare isso com um computador atual e determine o quanto melhor o atual é, multiplicando a razão de tamanhos e velocidades de memória e depois dividindo isso pela razão dos preços. Agora, veja o que os mesmos ganhos teriam feito com o setor de aviação no mesmo período de tempo. O Boeing 707 foi entregue às companhias aéreas em quantidades substanciais em 1959. Sua velocidade era de 950 km/h e sua capaci- dade era inicialmente de 180 passageiros. Ele custa US$ 4 milhões. Quais seriam agora a velocidade, capacidade e custo de uma aeronave se ela tivesse os mesmos ganhos de um computador? De forma clara, expresse suas suposições sobre velocidade, tamanho de memória e preço. 17. Os desenvolvimentos no setor de computação geral- mente são cíclicos. De início, os conjuntos de instruções eram fixos, depois foram microprogra- mados, depois surgiram máquinas RSC e eles eram novamente fixos. Na origem, a computação era centralizada em grandes computadores mainframe. Liste dois desenvolvimentos que demonstram o comportamento cíclico aqui também. 18. A questão legal que envolvia quem teria inventado o computador foi resolvida em abril de 1973 pelo juiz Earl Larson, que julgou uma ação judicial de violação de patente impetrada pela Sperry Rand Corporation, que tinha adquirido as patentes do ENAC. A posição da Sperry Rand era de que todos os fabricantes de computadores lhe deviam royalties porque as patentes principais lhe pertenciam. O caso foi a julgamento em junho de 1971 e mais de 30 mil provas foram apre- sentadas. O arquivo do caso passou de 20 mil páginas. Estude esse caso com mais cuidado usando a grande quantidade de informações disponíveis na nternet e redija um relatório que discuta seus aspectos técnicos. O que, exatamente, Eckert e Mauchley patentearam e por que o juiz achou que o sistema deles era baseado no trabalho anterior de Atanasoff? 19. Escolha três pessoas que você considera serem as mais influentes na criação do moderno hardware de computadores e redija um curto relatório que des- creva suas contribuições e o motivo de escolhê-las. 20. Escolha três pessoas que você considera serem as mais influentes na criação do moderno software de sistemas de computação e redija um curto relató- rio que descreva suas contribuições e o motivo de escolhê-las. 21. Escolha três pessoas que você considera serem as mais influentes na criação dos modernos sites da web e redija um curto relatório que descreva suas contri- buições e o motivo de escolhê-las.
  • 61. U m computador digital consiste em um sistema interconectado de processadores, memória e dispositi- vos de entrada/saída. Este capítulo é uma introdução a esses três componentes e a sua interconexão, como base para o exame mais detalhado de níveis específicos nos cinco capítulos subsequentes. Processadores, memórias e dispositivos de entrada/saída são conceitos fundamentais e estarão presentes em todos os níveis, portanto, iniciaremos nosso estudo da arquitetura de computadores examinando todos os três, um por vez. 2.1 Processadores A organização de um computador simples com barramento é mostrada na Figura 2.1. A CPU (Central Processing Unit  unidade central de processamento) é o “cérebro” do computador. Sua função é executar programas armazenados na memória principal buscando suas instruções, examinando-as e então executando-as uma após a outra. Os componentes são conectados por um barramento, conjunto de fios paralelos que transmi- tem endereços, dados e sinais de controle. Barramentos podem ser externos à CPU, conectando-a à memória e aos dispositivos de E/S, mas também podem ser internos, como veremos em breve. Os computadores modernos possuem vários barramentos. Organizac a o de sistemas de computadores 2 Cap tulo
  • 62. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 43 Figura 2.1 A organizac a o de um computador simples com uma CPU e dois dispositivos de E/S. Barramento … … Unidade central de processamento (CPU) Unidade de controle Unidade de lógica e aritmética (ULA) Registradores Dispositivos de E/S Memória principal Disco Impressora A CPU é composta por várias partes distintas. A unidade de controle é responsável por buscar instruções na memória principal e determinar seu tipo. A unidade de aritmética e lógica efetua operações como adição e AND (E) booleano para executar as instruções. A CPU também contém uma pequena memória de alta velocidade usada para armazenar resultados tem- porários e para algum controle de informações. Essa memória é composta de uma quantidade de registradores, cada um deles com determinado tamanho e função. Em geral, todos os registradores têm o mesmo tamanho. Cada um pode conter um número, até algum máximo definido pelo tamanho do registrador. Registradores podem ser lidos e escritos em alta velocidade porque são internos à CPU. O registrador mais importante é o Contador de Programa (PC – Program Counter), que indica a próxi- ma instrução a ser buscada para execução. (O nome “contador de programa” é um tanto enganoso, porque nada tem a ver com contar qualquer coisa; porém, o termo é de uso universal.) Também importante é o Registrador de Instrução (IR – Instruction Register), que mantém a instrução que está sendo executada no momento em questão. A maioria dos computadores também possui diversos outros registradores, alguns de uso geral, outros de uso específico. Outros registradores são usados pelo sistema operacional para controlar o computador. 2.1.1 Organizac a o da CPU A organização interna de parte de uma típica CPU de von Neumann é mostrada na Figura 2.2 com mais detalhes. Essa parte é denominada caminho de dados e é composta por registradores (em geral 1 a 32), da UL (unidade lógica e aritmética) e por diversos barramentos que conectam as partes. Os registradores alimentam dois registradores de entrada da ULA, representados por A e B na figura. Eles contêm a entrada da ULA enquan- to ela está executando alguma operação de computação. O caminho de dados é muito importante em todas as máquinas e nós o discutiremos minuciosamente em todo este livro.
  • 63. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 44 Figura 2.2 O caminho de dados de uma t pica ma quina de von Neumann. A + B A + B A A B B Registradores Registrador de entrada da ULA Barramento de entrada da ULA Registrador de saída da ULA ULA A ULA efetua adição, subtração e outras operações simples sobre suas entradas, produzindo assim um resul- tado no registrador de saída, o qual pode ser armazenado em um registrador. Mais tarde, ele pode ser escrito (isto é, armazenado) na memória, se desejado. Nem todos os projetos têm os registradores A, B e de saída. No exemplo, ilustramos uma adição, mas as ULAs também realizam outras operações. Grande parte das instruções pode ser dividida em uma de duas categorias: registrador-memória ou registrador-registrador. nstruções registrador-memória permitem que palavras de memória sejam buscadas em registradores, onde podem ser usadas como entradas de ULA em instruções subsequentes, por exemplo. (“Palavras” são as unidades de dados movimentadas entre memória e registradores. Uma palavra pode ser um número inteiro. Discutiremos organização de memória mais adiante neste capítulo.) Outras instruções registrador-memória permitem que registradores voltem à memória para armazenagem. O outro tipo de instrução é registrador-registrador. Uma instrução registrador-registrador típica busca dois operandos nos registradores, traz os dois até os registradores de entrada da ULA, efetua alguma operação com eles (por exemplo, adição ou AND booleano) e armazena o resultado em um dos registradores. O processo de passar dois operandos pela ULA e armazenar o resultado é denominado ciclo do caminho de dados e é o coração da maioria das CPUs. Até certo ponto considerável, ele define o que a máquina pode fazer. Quanto mais rápido for o ciclo do caminho de dados, mais rápido será o funcionamento da máquina. 2.1.2 Execuc a o de instruc a o A CPU executa cada instrução em uma série de pequenas etapas. Em termos simples, as etapas são as seguintes: 1. Trazer a próxima instrução da memória até o registrador de instrução. 2. Alterar o contador de programa para que aponte para a próxima instrução.
  • 64. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 45 3. Determinar o tipo de instrução trazida. 4. Se a instrução usar uma palavra na memória, determinar onde essa palavra está. 5. Trazer a palavra para dentro de um registrador da CPU, se necessário. 6. Executar a instrução. 7. oltar à etapa 1 para iniciar a execução da instrução seguinte. Tal sequência de etapas costuma ser denominada ciclo buscar-decodificar-executar. É fundamental para a operação de todos os computadores. Essa descrição do modo de funcionamento de uma CPU é muito parecida com um programa escrito em inglês. A Figura 2.3 mostra esse programa informal reescrito como um método Java (isto é, um procedimento) denominado interpret. A máquina que está sendo interpretada tem dois registradores visíveis para programas usuários: o contador de programa (PC), para controlar o endereço da próxima instrução a ser buscada, e o acu- mulador (AC), para acumular resultados aritméticos. Também tem registradores internos para conter a instrução corrente durante sua execução (instr), o tipo da instrução corrente (instr_type), o endereço do operando da ins- trução (data_loc) e o operando corrente em si (data). Admitimos que as instruções contêm um único endereço de memória. A localização de memória endereçada contém o operando, por exemplo, o item de dado a ser somado ao acumulador. Figura 2.3 Interpretador para um computador simples (escrito em Java). public class Interp { static int PC; // contador de programa contém endereço da próxima instr static int AC; // o acumulador, um registrador para efetuar aritmética static int instr; // um registrador para conter a instrução corrente static int instr_type; // o tipo da instrução (opcode) static int data_loc; // o endereço dos dados, ou –1 se nenhum static int data; // mantém o operando corrente static boolean run_bit = true; // um bit que pode ser desligado para parar a máquina public static void interpret(int memory[ ], int starting_ address) { // Esse procedimento interpreta programas para uma máquina simples com instruções que têm // um operando na memória. A máquina tem um registrador AC (acumulador), usado para // aritmética. A instrução ADD soma um inteiro na memória do AC, por exemplo. // O interpretador continua funcionando até o bit de funcionamento ser desligado pela instrução HALT. // O estado de um processo que roda nessa máquina consiste em memória, o // contador de programa, bit de funcionamento e AC. Os parâmetros de entrada consistem / na imagem da memória e no endereço inicial. PC = starting_address; while (run_bit) { instr = memory[PC]; // busca a próxima instrução e armazena em instr PC = PC + 1; // incrementa contador de programa instr_type = get_instr_type(instr); // determina tipo da instrução data_loc = find_data(instr, instr_type); // localiza dados (–1 se nenhum) if (data_loc >= 0) // se data_loc é –1, não há nenhum operando data = memory[data_loc]; // busca os dados execute(instr_type, data); // executa instrução } } private static int get_instr_type(int addr) { ... } private static int find_data(int instr, int type) { ... } private static void execute(int type, int data) { ... } }
  • 65. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 46 Essa equivalência entre processadores de hardware e interpretadores tem importantes implicações para a organização de computadores e para o projeto de sistemas de computadores. Após a especificação da lingua- gem de máquina, L, para um novo computador, a equipe de projeto pode decidir se quer construir um processador de hardware para executar programas em L diretamente ou se quer escrever um interpretador para interpretar programas em L. Se a equipe preferir escrever um interpretador, também deve providenciar alguma máquina de hardware para executá-lo. São possíveis ainda certas construções híbridas, com um pouco de execução em hard- ware, bem como alguma interpretação de software. Um interpretador subdivide as instruções da máquina em questão em pequenas etapas. Por conseguinte, a máquina na qual o interpretador roda deve ser muito mais simples e menos cara do que seria um processador de hardware para a máquina citada. Essa economia é bastante significativa se a máquina em questão tiver um grande número de instruções e estas forem razoavelmente complicadas, com muitas opções. Basicamente, a economia vem do fato de que o hardware está sendo substituído por software (o interpretador) e custa mais reproduzir hardware do que software. Os primeiros computadores tinham conjuntos de instruções pequenos, simples. Mas a procura por equipa- mentos mais poderosos levou, entre outras coisas, a instruções individuais mais poderosas. Logo se descobriu que instruções mais complexas muitas vezes levavam à execução mais rápida do programa mesmo que as instruções individuais demorassem mais para ser executadas. Uma instrução de ponto flutuante é um exemplo de instru- ção mais complexa. O suporte direto para acessar elementos matriciais é outro. Às vezes, isso era simples como observar que as mesmas duas instruções muitas vezes ocorriam em sequência, de modo que uma única instrução poderia fazer o trabalho de ambas. As instruções mais complexas eram melhores porque a execução de operações individuais às vezes podia ser sobreposta ou então executada em paralelo usando hardware diferente. No caso de computadores caros, de alto desempenho, o custo desse hardware extra poderia ser justificado de imediato. Assim, computadores caros, de alto desempenho, passaram a ter mais instruções do que os de custo mais baixo. Contudo, requisitos de compa- tibilidade de instruções e o custo crescente do desenvolvimento de software criaram a necessidade de executar instruções complexas mesmo em computadores de baixo custo, nos quais o custo era mais importante do que a velocidade. No final da década de 1950, a BM (na época a empresa que dominava o setor de computadores) percebeu que prestar suporte a uma única família de máquinas, todas executando as mesmas instruções, tinha muitas vantagens, tanto para a BM quanto para seus clientes. Então, a empresa introduziu o termo arquitetura para descrever esse nível de compatibilidade. Uma nova família de computadores teria uma só arquitetura, mas muitas implementações diferentes que poderiam executar o mesmo programa e seriam diferentes apenas em preço e velo- cidade. Mas como construir um computador de baixo custo que poderia executar todas as complicadas instruções de máquinas caras, de alto desempenho? A resposta foi a interpretação. Essa técnica, que já tinha sido sugerida por Maurice Wilkes (1951), permitia o projeto de computadores simples e de menor custo, mas que, mesmo assim, podiam executar um grande núme- ro de instruções. O resultado foi a arquitetura BM System/360, uma família de computadores compatíveis que abrangia quase duas ordens de grandeza, tanto em preço quanto em capacidade. Uma implementação de hardware direto (isto é, não interpretado) era usada somente nos modelos mais caros. Computadores simples com instruções interpretadas também tinham outros benefícios, entre os quais os mais importantes eram: 1. A capacidade de corrigir em campo instruções executadas incorretamente ou até compensar deficiên- cias de projeto no hardware básico. 2. A oportunidade de acrescentar novas instruções a um custo mínimo, mesmo após a entrega da máquina. 3. Projeto estruturado que permitia desenvolvimento, teste e documentação eficientes de instruções complexas.
  • 66. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 47 À medida que o mercado explodia em grande estilo na década de 1970 e as capacidades de computação cresciam depressa, a demanda por máquinas de baixo custo favorecia projetos de computadores que usassem interpretadores. A capacidade de ajustar hardware e interpretador para um determinado conjunto de instruções surgiu como um projeto muito eficiente em custo para processadores. À medida que a tecnologia subjacente dos semicondutores avançava, as vantagens do custo compensavam as oportunidades de desempenho mais alto e as arquiteturas baseadas em interpretador se tornaram o modo convencional de projetar computadores. Quase todos os novos computadores projetados na década de 1970, de microcomputadores a mainframes, tinham a interpre- tação como base. No final da década de 1970, a utilização de processadores simples que executavam interpretadores tinha se propagado em grande escala, exceto entre os modelos mais caros e de desempenho mais alto, como o Cray-1 e a série Cyber da Control Data. A utilização de um interpretador eliminava as limitações de custo inerentes às instruções complexas, de modo que os projetistas começaram a explorar instruções muito mais complexas, em particular os modos de especificar os operandos a utilizar. A tendência alcançou seu ponto mais alto com o A da Digital Equipment Corporation, que tinha várias centenas de instruções e mais de 200 modos diferentes de especificar os operandos a serem usados em cada ins- trução. nfelizmente, desde o início a arquitetura do A foi concebida para ser executada com um interpretador, sem dar muita atenção à realização de um modelo de alto desempenho. Esse modo de pensar resultou na inclusão de um número muito grande de instruções de valor marginal e que eram difíceis de executar diretamente. Essa omissão mostrou ser fatal para o A e, por fim, também para a DEC (a Compaq comprou a DEC em 1998 e a Hewlett-Packard comprou a Compaq em 2001). Embora os primeiros microprocessadores de 8 bits fossem máquinas muito simples com conjuntos de instru- ções muito simples, no final da década de 1970 até os microprocessadores tinham passado para projetos baseados em interpretador. Durante esse período, um dos maiores desafios enfrentados pelos projetistas de microproces- sadores era lidar com a crescente complexidade, possibilitada por meio de circuitos integrados. Uma importante vantagem do método baseado em interpretador era a capacidade de projetar um processador simples e confinar quase toda a complexidade na memória que continha o interpretador. Assim, um projeto complexo de hardware se transformou em um projeto complexo de software. O sucesso do Motorola 68000, que tinha um grande conjunto de instruções interpretadas, e o concomitante fracasso do Zilog Z8000 (que tinha um conjunto de instruções tão grande quanto, mas sem um interpretador) demonstraram as vantagens de um interpretador para levar um novo microprocessador rapidamente ao mercado. Esse sucesso foi ainda mais surpreendente dada a vantagem de que o Zilog desfrutava (o antecessor do Z8000, o Z80, era muito mais popular do que o antecessor do 68000, o 6800). Claro que outros fatores também contri- buíram para isso, e um dos mais importantes foi a longa história da Motorola como fabricante de chips e a longa história da Exxon (proprietária da Zilog) como empresa de petróleo, e não como fabricante de chips. Outro fator a favor da interpretação naquela época foi a existência de memórias rápidas somente de leitura, denominadas memórias de controle, para conter os interpretadores. Suponha que uma instrução interpretada típica precisasse de 10 instruções do interpretador, denominadas microinstruções, a 100 ns cada, e duas referên- cias à memória principal a 500 ns cada. Então, o tempo total de execução era 2.000 ns, apenas um fator de dois pior do que o melhor que a execução direta podia conseguir. Se a memória de controle não estivesse disponível, a instrução levaria 6.000 ns. Uma penalidade de fator seis é muito mais difícil de aceitar do que uma penalidade de fator dois. 2.1.3 RISC versus CISC Durante o final da década de 1970, houve experiências com instruções muito complexas que eram pos- sibilitadas pelo interpretador. Os projetistas tentavam fechar a “lacuna semântica” entre o que as máquinas podiam fazer e o que as linguagens de programação de alto nível demandavam. Quase ninguém pensava em projetar máquinas mais simples, exatamente como agora não há muita pesquisa na área de projeto de plani- lhas, redes, servidores Web etc. menos poderosos (o que talvez seja lamentável).
  • 67. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 48 Um grupo que se opôs à tendência e tentou incorporar algumas das ideias de Seymour Cray em um minicom- putador de alto desempenho foi liderado por John Cocke na BM. Esse trabalho resultou em um minicomputador denominado 801. Embora a BM nunca tenha lançado essa máquina no mercado e os resultados tenham sido publicados só muitos anos depois (Radin, 1982), a notícia vazou e outros começaram a investigar arquiteturas semelhantes. Em 1980, um grupo em Berkeley, liderado por David Patterson e Carlo Séquin, começou a projetar chips para CPUs LS que não usavam interpretação (Patterson, 1985; Patterson e Séquin, 1982). Eles cunharam o termo RISC para esse conceito e deram ao seu chip de CPU o nome RSC  CPU, seguido logo depois pelo RSC . Um pouco mais tarde, em 1981, do outro lado da baía de São Francisco, em Stanford, John Hennessy projetou e fabricou um chip um pouco diferente, que ele chamou de MIPS (Hennessy, 1984). Esses chips evoluíram para produtos de importância comercial, o SPARC e o MPS, respectivamente. Esses novos processadores tinham diferenças significativas em relação aos que havia no comércio naquela época. Uma vez que essas novas CPUs não eram compatíveis com os produtos existentes, seus projetistas tinham liberdade para escolher novos conjuntos de instruções que maximizassem o desempenho total do sistema. Embora a ênfase inicial estivesse dirigida a instruções simples, que podiam ser executadas rapidamente, logo se percebeu que projetar instruções que podiam ser emitidas (iniciadas) rapidamente era a chave do bom desem- penho. Na verdade, o tempo que uma instrução demorava importava menos do que quantas delas podiam ser iniciadas por segundo. Na época em que o projeto desses processadores simples estava no início, a característica que chamou a aten- ção de todos era o número relativamente pequeno de instruções disponíveis, em geral cerca de 50. Esse número era muito menor do que as 200 a 300 de computadores como o A da DEC e os grandes mainframes da BM. De fato, o acrônimo RSC quer dizer Reduced Instruction Set Computer (computador com conjunto de instru- ções reduzido), em comparação com CSC, que significa Complex Instruction Set Computer (computador com conjunto de instruções complexo), uma referência nada sutil ao A que, na época, dominava os departamentos de ciência da computação das universidades. Hoje em dia, poucas pessoas acham que o tamanho do conjunto de instruções seja um assunto importante, mas o nome pegou. Encurtando a história, seguiu-se uma grande guerra santa, com os defensores do RSC atacando a ordem estabelecida (A, ntel, grandes mainframes da BM). Eles afirmavam que o melhor modo de projetar um com- putador era ter um pequeno número de instruções simples que executassem em um só ciclo do caminho de dados da Figura 2.2, ou seja, buscar dois registradores, combiná-los de algum modo (por exemplo, adicionando-os ou fazendo AND) e armazenar o resultado de volta em um registrador. O argumento desses pesquisadores era de que, mesmo que uma máquina RSC precisasse de quatro ou cinco instruções para fazer o que uma CSC fazia com uma só, se as instruções RSC fossem dez vezes mais rápidas (porque não eram interpretadas), o RSC vencia. Também vale a pena destacar que, naquele tempo, a velocidade de memórias principais tinha alcançado a velo- cidade de memórias de controle somente de leitura, de modo que a penalidade imposta pela interpretação tinha aumentado demais, o que favorecia muito as máquinas RSC. Era de imaginar que, dadas as vantagens de desempenho da tecnologia RSC, as máquinas RSC (como a Sun UltraSPARC) passariam como rolo compressor sobre as máquinas CSC (tal como a Pentium da ntel) existentes no mercado. Nada disso aconteceu. Por quê? Antes de tudo, há a questão da compatibilidade e dos bilhões de dólares que as empresas tinham investido em software para a linha ntel. Em segundo lugar, o que era surpreendente, a ntel conseguiu empregar as mesmas ideias mesmo em uma arquitetura CSC. A partir do 486, as CPUs da ntel contêm um núcleo RSC que executa as instruções mais simples (que normalmente são as mais comuns) em um único ciclo do caminho de dados, enquanto interpreta as mais complicadas no modo CSC de sempre. O resultado disso é que as instruções comuns são rápidas e as menos comuns são lentas. Mesmo que essa abordagem híbrida não seja tão rápida quanto um projeto RSC puro, ela resulta em desempenho global competitivo e ainda permite que softwares antigos sejam executados sem modificação.
  • 68. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 49 2.1.4 Princ pios de projeto para computadores modernos Agora que já se passaram mais de duas décadas desde que as primeiras máquinas RSC foram lançadas, certos princípios de projeto passaram a ser aceitos como um bom modo de projetar computadores, dado o estado atual da tecnologia de hardware. Se ocorrer uma importante mudança na tecnologia (por exemplo, se, de repente, um novo processo de fabricação fizer o ciclo de memória ficar dez vezes mais rápido do que o tempo de ciclo da CPU), todas as apostas perdem. Assim, os projetistas de máquinas devem estar sempre de olho nas mudanças tecnológicas que possam afetar o equilíbrio entre os componentes. Dito isso, há um conjunto de princípios de projeto, às vezes denominados princípios de projeto RISC, que os arquitetos de CPUs de uso geral se esforçam por seguir. Limitações externas, como a exigência de compatibili- dade com alguma arquitetura existente, muitas vezes exigem uma solução de conciliação de tempos em tempos, mas esses princípios são metas que a maioria dos projetistas se esforça para cumprir. A seguir, discutiremos os principais. Todas as instruc o es sa o executadas diretamente por hardware Todas as instruções comuns são executadas diretamente pelo hardware – não são interpretadas por micro- instruções. Eliminar um nível de interpretação dá alta velocidade à maioria das instruções. No caso de compu- tadores que executam conjuntos de instruções CSC, as instruções mais complexas podem ser subdivididas em partes separadas que então podem ser executadas como uma sequência de microinstruções. Essa etapa extra torna a máquina mais lenta, porém, para instruções que ocorrem com menos frequência, isso pode ser aceitável. Maximize a taxa de execuc a o das instruc o es Computadores modernos recorrem a muitos truques para maximizar seu desempenho, entre os quais o prin- cipal é tentar iniciar o máximo possível de instruções por segundo. Afinal, se você puder emitir 500 milhões de instruções por segundo, terá construído um processador de 500 MPS, não importa quanto tempo elas realmente levem para ser concluídas. (MIPS quer dizer Milhões de nstruções Por Segundo. O processador MPS recebeu esse nome como um trocadilho desse acrônimo. Oficialmente, ele significa Microprocessor without Interlocked Pipeline Stages – microprocessador sem estágios paralelos de interbloqueio.) Esse princípio sugere que o parale- lismo pode desempenhar um importante papel na melhoria do desempenho, uma vez que emitir grandes quanti- dades de instruções lentas em curto intervalo de tempo só é possível se várias instruções puderem ser executadas ao mesmo tempo. Embora as instruções sempre sejam encontradas na ordem do programa, nem sempre elas são executadas nessa mesma ordem (porque algum recurso necessário pode estar ocupado) e não precisam terminar na ordem do programa. É claro que, se a instrução 1 estabelece um registrador e a instrução 2 usa esse registrador, deve-se tomar muito cuidado para garantir que a instrução 2 não leia o registrador até que ele contenha o valor correto. Fazer isso funcionar direito requer muito controle, mas possibilita ganhos de desempenho por executar várias instruções ao mesmo tempo. Instruc o es devem ser fa ceis de decodificar Um limite crítico para a taxa de emissão de instruções é a decodificação de instruções individuais para determinar quais recursos elas necessitam. Qualquer coisa que possa ajudar nesse processo é útil. sso inclui fazer instruções regulares, de comprimento fixo, com um pequeno número de campos. Quanto menor o número de formatos diferentes para as instruções, melhor. Somente LOAD e STORE devem referenciar a memo ria Um dos modos mais simples de subdividir operações em etapas separadas é requerer que os operandos para a maioria das instruções venham de registradores da CPU e a eles retornem. A operação de movimentação de operandos da memória para registradores pode ser executada em instruções separadas. Uma vez que o acesso à
  • 69. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 50 memória pode levar um longo tempo, e que o atraso é imprevisível, o melhor é sobrepor essas instruções a outras se elas nada fizerem exceto movimentar operandos entre registradores e memória. Essa observação significa que somente instruções LOAD e STORE devem referenciar a memória. Todas as outras devem operar apenas em registradores. Providencie muitos registradores isto que o acesso à memória é relativamente lento, é preciso providenciar muitos registradores (no mínimo, 32) de modo que, assim que uma palavra for buscada, ela possa ser mantida em um registrador até não ser mais necessária. Esgotar os registradores e ter de descarregá-los de volta à memória só para ter de recarregá-los mais tarde é indesejável e deve ser evitado o máximo possível. A melhor maneira de conseguir isso é ter um número suficiente de registradores. 2.1.5 Paralelismo no n vel de instruc a o Arquitetos de computadores estão sempre se esforçando para melhorar o desempenho das máquinas que projetam. Fazer os chips funcionarem com maior rapidez aumentando suas velocidades de clock é um modo, mas, para cada novo projeto, há um limite para o que é possível fazer por força bruta naquele momento da História. Por conseguinte, grande parte dos arquitetos de computadores busca o paralelismo (fazer duas ou mais coisas ao mesmo tempo) como um meio de conseguir desempenho ainda melhor para dada velocidade de clock. O paralelismo tem duas formas gerais, a saber, no nível de instrução e no nível de processador. Na primeira, o paralelismo é explorado dentro de instruções individuais para obter da máquina mais instruções por segundo. Na última, várias CPUs trabalham juntas no mesmo problema. Cada abordagem tem seus próprios méritos. Nesta seção, vamos estudar o paralelismo no nível de instrução; na seção seguinte, estudaremos o paralelismo no nível de processador. Pipelining (paralelismo) Há anos sabe-se que o processo de buscar instruções na memória é um grande gargalo na velocidade de execução da instrução. Para amenizar esse problema, os computadores, desde o BM Stretch (1959), tinham a capacidade de buscar instruções na memória antecipadamente, de maneira que estivessem presentes quando necessárias. Essas instruções eram armazenadas em um conjunto de registradores denominado buffer de busca antecipada (ou prefetch buffer). Desse modo, quando necessária, uma instrução podia ser apanhada no buffer de busca antecipada, em vez de esperar pela conclusão de uma leitura da memória. Na verdade, a busca antecipada divide a execução da instrução em duas partes: a busca e a execução propriamente dita. O conceito de pipeline (paralelismo, canalização) amplia muito mais essa estratégia. Em vez de dividir a execução da instrução em apenas duas partes, muitas vezes ela é dividida em muitas partes (uma dúzia ou mais), cada uma manipulada por uma parte dedicada do hardware, e todas elas podem exe- cutar em paralelo. A Figura 2.4(a) ilustra um pipeline com cinco unidades, também denominadas estágios. O estágio 1 busca a instrução na memória e a coloca em um buffer até que ela seja necessária. O estágio 2 decodifica a instrução, determina seu tipo e de quais operandos ela necessita. O estágio 3 localiza e busca os operandos, seja nos regis- tradores, seja na memória. O estágio 4 é que realiza o trabalho de executar a instrução, normalmente fazendo os operandos passarem pelo caminho de dados da Figura 2.2. Por fim, o estágio 5 escreve o resultado de volta no registrador adequado.
  • 70. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 51 Figura 2.4 (a) Pipeline de cinco esta gios. (b) Estado de cada esta gio como uma func a o do tempo. Sa o ilustrados nove ciclos de clock. (a) (b) S1: S2: S3: S4: S5: 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 1 2 3 4 5 6 1 2 3 4 5 1 2 3 4 5 6 7 8 9 … S1 S2 S3 S4 S5 Unidade de busca de instrução Unidade de decodificação de instrução Unidade de busca de operando Unidade de execução de instrução Unidade de gravação Tempo Na Figura 2.4(b), vemos como o pipeline funciona em função do tempo. Durante o ciclo de clock 1, o estágio S1 está trabalhando na instrução 1, buscando-a na memória. Durante o ciclo 2, o estágio S2 decodifica a instrução 1, enquanto o estágio S1 busca a instrução 2. Durante o ciclo 3, o estágio S3 busca os operandos para a instrução 1, o estágio S2 decodifica a instrução 2 e o estágio S1 busca a terceira instrução. Durante o ciclo 4, o estágio S4 executa a instrução 1, S3 busca os operandos para a instrução 2, S2 decodifica a instrução 3 e S1 busca a instrução 4. Por fim, durante o ciclo 5, S5 escreve (grava) o resultado da instrução 1 de volta ao registrador, enquanto os outros estágios trabalham nas instruções seguintes. amos considerar uma analogia para esclarecer melhor o conceito de pipelining. magine uma fábrica de bolos na qual a operação de produção dos bolos e a operação da embalagem para expedição são separadas. Suponha que o departamento de expedição tenha uma longa esteira transportadora ao longo da qual trabalham cinco funcionários (unidades de processamento). A cada 10 segundos (o ciclo de clock), o funcionário 1 coloca uma embalagem de bolo vazia na esteira. A caixa é transportada até o funcionário 2, que coloca um bolo dentro dela. Um pouco mais tarde, a caixa chega à estação do funcionário 3, onde é fechada e selada. Em seguida, prosse- gue até o funcionário 4, que coloca uma etiqueta na embalagem. Por fim, o funcionário 5 retira a caixa da esteira e a coloca em um grande contêiner que mais tarde será despachado para um supermercado. Em termos gerais, esse é o modo como um pipeline de computador também funciona: cada instrução (bolo) passa por diversos estágios de processamento antes de aparecer já concluída na extremidade final. oltando ao nosso pipeline da Figura 2.4, suponha que o tempo de ciclo dessa máquina seja 2 ns. Sendo assim, uma instrução leva 10 ns para percorrer todo o caminho do pipeline de cinco estágios. À primeira vista, como uma instrução demora 10 ns, parece que a máquina poderia funcionar em 100 MPS, mas, na verdade, ela funciona muito melhor do que isso. A cada ciclo de clock (2 ns), uma nova instrução é concluída, portanto, a velocidade real de processamento é 500 MPS, e não 100 MPS. O pipelining permite um compromisso entre latência (o tempo que demora para executar uma instrução) e lar- gura de banda de processador (quantos MPS a CPU tem). Com um tempo de ciclo de T ns e n estágios no pipeline, a latência é nT ns porque cada instrução passa por n estágios, cada um dos quais demora T ns. isto que uma instrução é concluída a cada ciclo de clock e que há 109 /T ciclos de clock por segundo, o número de instruções executadas por segundo é 109 /T. Por exemplo, se T = 2 ns, 500 milhões de instruções são executadas a cada segundo. Para obter o número de MPS, temos de dividir a taxa de execução de instrução por 1 milhão para obter (109 /T)/106 = 1.000/T MPS. Em teoria, poderíamos medir taxas de execução de instrução em BPS em vez de MPS, mas ninguém faz isso, portanto, nós também não o faremos.
  • 71. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 52 Arquiteturas superescalares Se um pipeline é bom, então certamente dois pipelines são ainda melhores. Um projeto possível para uma CPU com dois pipelines, com base na Figura 2.4, é mostrado na Figura 2.5. Nesse caso, uma única unidade de busca de instruções busca pares de instruções ao mesmo tempo e coloca cada uma delas em seu próprio pipeline, completo com sua própria ULA para operação paralela. Para poder executar em para- lelo, as duas instruções não devem ter conflito de utilização de recursos (por exemplo, registradores) e nenhuma deve depender do resultado da outra. Assim como em um pipeline único, ou o compilador deve garantir que essa situação aconteça (isto é, o hardware não verifica e dá resultados incorretos se as ins- truções não forem compatíveis), ou os conflitos deverão ser detectados e eliminados durante a execução usando hardware extra. Figura 2.5 Pipelines duplos de cinco esta gios com uma unidade de busca de instruc a o em comum. S1 S2 S3 S4 S5 Unidade de busca de instrução Unidade de decodificação de instrução Unidade de busca de operando Unidade de execução de instrução Unidade de gravação Unidade de decodificação de instrução Unidade de busca de operando Unidade de execução de instrução Unidade de gravação Embora pipelines, simples ou duplos, sejam usados em sua maioria em máquinas RSC (o 386 e seus antecessores não tinham nenhum), a partir do 486 a ntel começou a acrescentar pipelines de dados em suas CPUs. O 486 tinha um pipeline e o Pentium original tinha pipelines de cinco estágios mais ou menos como os da Figura 2.5, embora a exata divisão do trabalho entre os estágios 2 e 3 (denominados decode-1 e decode-2) era ligeiramente diferente do que em nosso exemplo. O pipeline principal, denominado pipeline u, podia executar uma instrução Pentium qualquer. O segundo, denominado pipeline v, podia executar apenas instruções com números inteiros (e também uma instrução simples de ponto flutuante – FCH). Regras fixas determinavam se um par de instruções era compatível e, portanto, se elas podiam ser exe- cutadas em paralelo. Se as instruções em um par não fossem simples o suficiente ou se fossem incompatíveis, somente a primeira era executada (no pipeline u). A segunda era retida para fazer par com a instrução seguin- te. nstruções eram sempre executadas em ordem. Assim, os compiladores específicos para Pentium que produziam pares compatíveis podiam produzir programas de execução mais rápidos do que compiladores mais antigos. Medições mostraram que um código de execução Pentium otimizado para ele era exatamente duas vezes mais rápido para programas de inteiros do que um 486 que executava à mesma velocidade de clock (Pountain, 1993). Esse ganho podia ser atribuído inteiramente ao segundo pipeline. Passar para quatro pipelines era concebível, mas exigiria duplicar muito hardware (cientistas da compu- tação, ao contrário de especialistas em folclore, não acreditam no número três). Em vez disso, uma aborda- gem diferente é utilizada em CPUs de topo de linha. A ideia básica é ter apenas um único pipeline, mas lhe dar várias unidades funcionais, conforme mostra a Figura 2.6. Por exemplo, a arquitetura ntel Core tem uma estrutura semelhante à dessa figura, que será discutida no Capítulo 4. O termo arquitetura superescalar foi cunhado para essa técnica em 1987 (Agerwala e Cocke, 1987). Entretanto, suas raízes remontam a mais de 40 anos, ao computador CDC 6600. O 6600 buscava uma instrução a cada 100 ns e a passava para uma das 10 unidades funcionais para execução paralela enquanto a CPU saía em busca da próxima instrução.
  • 72. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 53 Figura 2.6 Processador superescalar com cinco unidades funcionais. S2 S3 S5 S1 S4 Unidade de busca de instrução Unidade de decodificação de instrução Unidade de busca de operando ULA ULA LOAD STORE Ponto flutuante Unidade de gravação A definição de “superescalar” evoluiu um pouco ao longo do tempo. Agora, ela é usada para descrever processadores que emitem múltiplas instruções – frequentemente, quatro ou seis – em um único ciclo de clock. Claro que uma CPU superescalar deve ter várias unidades funcionais para passar todas essas instru- ções. Uma vez que, em geral, os processadores superescalares têm um só pipeline, tendem a ser parecidos com os da Figura 2.6. Usando essa definição, o 6600 não era tecnicamente um computador superescalar, pois emitia apenas uma instrução por ciclo. Todavia, o efeito era quase o mesmo: instruções eram terminadas em uma taxa muito mais alta do que podiam ser executadas. A diferença conceitual entre uma CPU com um clock de 100 ns que executa uma instrução a cada ciclo para um grupo de unidades funcionais e uma CPU com um clock de 400 ns que executa quatro instruções por ciclo para o mesmo grupo de unidades funcionais é muito pequena. Em ambos os casos, a ideia fundamental é que a taxa final é muito mais alta do que a taxa de execução, sendo a carga de trabalho distribuída entre um conjunto de unidades funcionais. mplícito à ideia de um processador superescalar é que o estágio S3 pode emitir instruções com rapidez muito maior do que o estágio S4 é capaz de executá-las. Se o estágio S3 executasse uma instrução a cada 10 ns e todas as unidades funcionais pudessem realizar seu trabalho em 10 ns, nunca mais do que uma unidade estaria ocupada ao mesmo tempo, o que negaria todo o raciocínio. Na verdade, grande parte das unidades fun- cionais no estágio 4 leva um tempo bem maior do que um ciclo de clock para executar, decerto as que acessam memória ou efetuam aritmética de ponto flutuante. Como pode ser visto na figura, é possível ter várias ULAs no estágio S4. 2.1.6 Paralelismo no n vel do processador A demanda por computadores cada vez mais rápidos parece ser insaciável. Astrônomos querem simular o que aconteceu no primeiro microssegundo após o Big Bang, economistas querem modelar a economia mundial e adolescentes querem se divertir com jogos multimídia em 3D com seus amigos virtuais pela nternet. Embora as CPUs estejam cada vez mais rápidas, haverá um momento em que elas terão problemas com a velocidade da luz, que provavelmente permanecerá a 20 cm/nanossegundo em fio de cobre ou fibra ótica, não importando o grau de inteligência dos engenheiros da ntel. Chips mais velozes também produzem mais calor, cuja dissipação é um problema. De fato, a dificuldade para se livrar do calor produzido é o principal motivo pelo qual as velocidades de clock da CPU se estagnaram na última década.
  • 73. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 54 Paralelismo no nível de instrução ajuda um pouco, mas pipelining e operação superescalar raramente rendem mais do que um fator de cinco ou dez. Para obter ganhos de 50, 100 ou mais, a única maneira é projetar compu- tadores com várias CPUs; portanto, agora vamos ver como alguns deles são organizados. Computadores paralelos Um número substancial de problemas em domínios de cálculo como ciências físicas, engenharia e gráficos de computador envolve laços e matrizes, ou então tem estrutura de alta regularidade. Muitas vezes, os mesmos cálcu- los são efetuados em muitos conjuntos diferentes de dados ao mesmo tempo. A regularidade e a estrutura desses programas os tornam alvos especialmente fáceis para aceleração por meio de execução paralela. Há dois métodos que têm sido usados para executar esses programas altamente regulares de modo rápido e eficaz: processadores SMD e processadores vetoriais. Embora esses dois esquemas guardem notáveis semelhanças na maioria de seus aspectos, por ironia o primeiro deles é considerado um computador paralelo, enquanto o segundo é considerado uma extensão de um processador único. Computadores paralelos de dados encontraram muitas aplicações bem-sucedidas como consequência de sua notável eficiência. Eles são capazes de produzir poder de computação significativo com menos transis- tores do que os métodos alternativos. Gordon Moore (da lei de Moore) observou que o silício custa cerca de 1 bilhão de dólares por acre (4.047 m²). Assim, quanto mais poder de computação puder ser espremido desse acre de silício, mais dinheiro uma empresa de computador poderá obter vendendo silício. Os processadores paralelos de dados são um dos meios mais eficientes de espremer o desempenho do silício. Como todos os processado- res estão rodando a mesma instrução, o sistema só precisa de um “cérebro” controlando o computador. Em consequência, o processador só precisa de um estágio de busca, um estágio de decodificação e um conjunto de lógica de controle. Essa é uma enorme economia no silício, que dá aos computadores paralelos uma grande vantagem sobre outros processadores, desde que o software que eles estejam rodando seja altamente regular, com bastante paralelismo. Um processador SIM (Single Instruction-stream Multiple ata-stream, ou fluxo único de instruções, fluxo múltiplo de dados) consiste em um grande número de processadores idênticos que efetuam a mesma sequência de instruções sobre diferentes conjuntos de dados. O primeiro processador SMD do mundo foi o LLAC  da Universidade de llinois (Bouknight et al., 1972). O projeto original do LLAC  consistia em qua- tro quadrantes, cada um deles com uma grade quadrada de 8 × 8 elementos de processador/memória. Uma única unidade de controle por quadrante transmitia uma única instrução a todos os processadores, que era executada no mesmo passo por todos eles, cada um usando seus próprios dados de sua própria memória. Por causa de um excesso de custo, somente um quadrante de 50 megaflops (milhões de operações de ponto flutuante por segun- do) foi construído; se a construção da máquina inteira de 1 gigaflop tivesse sido concluída, ela teria duplicado a capacidade de computação do mundo inteiro. As modernas unidades de processamento de gráficos (GPUs) contam bastante com o processamento SMD para fornecer poder computacional maciço com poucos transistores. O processamento de gráficos foi apropriado para processadores SMD porque a maioria dos algoritmos é altamente regular, com operações repetidas sobre pixels, vértices, texturas e arestas. A Figura 2.7 mostra o processador SMD no núcleo da GPU Fermi da Nvidia. A GPU Fermi contém até 16 multiprocessadores de fluxo (com memória compartilhada – SM) SMD, com cada multiprocessador contendo 32 processadores SMD. A cada ciclo, o escalonador seleciona dois threads para executar no processador SMD. A próxima instrução de cada thread é então executada em até 16 processadores SMD, embora possivelmente menos se não houver paralelismo de dados suficiente. Se cada thread for capaz de realizar 16 operações por ciclo, um núcleo GPU Fermi totalmente carregado com 32 multiprocessadores realizará incríveis 512 operações por ciclo. Esse é um feito impressionante, considerando que uma CPU quad-core de uso geral com tamanho semelhante lutaria para conseguir 1/32 desse processamento.
  • 74. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 55 Figura 2.7 O nu cleo SIMD da unidade de processamento de gra ficos Fermi. Cache de instruções Despacho de instruções Despacho de instruções Arquivo de registradores Operando Operando Unidade de PF ULA Registrador de resultado Núcleo Rede de interconexão Memória compartilhada Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Núcleo Para um programador, um processador vetorial se parece muito com um processador SMD. Assim como um processador SMD, ele é muito eficiente para executar uma sequência de operações em pares de elementos de dados. Porém, diferente de um processador SMD, todas as operações de adição são efetuadas em uma única unidade funcional, de alto grau de paralelismo. A Cray Research, empresa fundada por Seymour Cray, produziu muitos processadores vetoriais, começando com o Cray-1 em 1974 e continuando até os modelos atuais. Processadores SMD, bem como processadores vetoriais, trabalham com matrizes de dados. Ambos execu- tam instruções únicas que, por exemplo, somam os elementos aos pares para dois vetores. Porém, enquanto o processador SMD faz isso com tantos somadores quantos forem os elementos do vetor, o processador vetorial tem o conceito de um registrador vetorial, que consiste em um conjunto de registradores convencionais que podem ser carregados com base na memória em uma única instrução que, na verdade, os carrega serialmente com base na memória. Então, uma instrução de adição vetorial efetua as adições a partir dos elementos de dois desses vetores, alimentando-os em um somador com paralelismo (pipelined) com base em dois registradores vetoriais. O resultado do somador é outro vetor, que pode ser armazenado em um registrador vetorial ou usado diretamente como um operando para outra operação vetorial. As instruções SSE (Streaming SMD Extension) disponíveis na arquitetura ntel Core utilizam esse modelo de execução para agilizar o cálculo altamente regular, como multimídia e software científico. Nesse aspecto particular, o LLAC  é um dos ancestrais da arquitetura ntel Core.
  • 75. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 56 Multiprocessadores Os elementos de processamento em um processador SMD não são CPUs independentes, uma vez que há uma só unidade de controle compartilhada por todos eles. Nosso primeiro sistema paralelo com CPUs totalmen- te desenvolvidas é o multiprocessador, um sistema com mais de uma CPU que compartilha uma memória em comum, como um grupo de pessoas que, dentro de uma sala de aula, compartilha um quadro em comum. Uma vez que cada CPU pode ler ou escrever em qualquer parte da memória, elas devem se coordenar (em software) para evitar que uma atrapalhe a outra. Quando duas ou mais CPUs têm a capacidade de interagir de perto, como é o caso dos multiprocessadores, diz-se que elas são fortemente acopladas. Há vários esquemas de implementação possíveis. O mais simples é um barramento único com várias CPUs e uma memória, todas ligadas nele. Um diagrama desse tipo de multiprocessador de barramento único é mostrado na Figura 2.8(a). Figura 2.8 (a) Multiprocessador de barramento u nico. (b) Multicomputador com memo rias locais. (a) (b) CPU CPU CPU CPU CPU CPU CPU CPU Memórias locais Memória compartilhada Memória compartilhada Barramento Barramento Não é preciso muita imaginação para perceber que, com um grande número de processadores velozes ten- tando acessar a memória pelo mesmo barramento, surgirão conflitos. Projetistas de multiprocessadores apresen- taram vários esquemas para reduzir essa disputa e melhorar o desempenho. Um desses esquemas, mostrado na Figura 2.8(b), dá a cada processador um pouco de memória local só dele, que não é acessível para os outros. Essa memória pode ser usada para o código de programa e para os itens de dados que não precisam ser compartilhados. O acesso a essa memória privada não usa o barramento principal, o que reduz muito o tráfego no barramento. Outros esquemas (por exemplo, caching – veja mais adiante) também são possíveis. Multiprocessadores têm a vantagem sobre outros tipos de computadores paralelos: é fácil trabalhar com o modelo de programação de uma única memória compartilhada. Por exemplo, imagine um programa que procura células cancerosas na foto de algum tecido, tirada por um microscópio. A fotografia digitalizada poderia ser man- tida na memória em comum, sendo cada processador designado para caçar essas células em alguma região. Uma vez que cada processador tem acesso a toda a memória, estudar a célula que começa em sua região designada mas atravessa a fronteira da próxima região não é problema. Multicomputadores Embora seja um tanto fácil construir multiprocessadores com um número modesto de processadores (≤ 256), construir grandes é surpreendentemente difícil. A dificuldade está em conectar todos os processado- res à memória. Para evitar esses problemas, muitos projetistas simplesmente abandonaram a ideia de ter uma memória compartilhada e passaram a construir sistemas que consistissem em grandes números de computa- dores interconectados, cada um com sua própria memória privada, mas nenhuma em comum. Esses sistemas são denominados multicomputadores. Costuma-se dizer que as CPUs de um multicomputador são fracamente acopladas, para contrastá-las com as CPUs fortemente acopladas de um multiprocessador.
  • 76. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 57 As CPUs de um multicomputador se comunicam enviando mensagens umas às outras, mais ou menos como enviar e-mails, porém, com muito mais rapidez. Em sistemas grandes, não é prático ter cada computador liga- do a todos os outros, portanto, são usadas topologias como malhas 2D e 3D, árvores e anéis. O resultado é que mensagens de um computador para outro muitas vezes passam por um ou mais computadores ou comutadores (chaves) intermediários para ir da fonte até o destino. Não obstante, podem-se conseguir tempos de transmissão de mensagem da ordem de alguns microssegundos sem muita dificuldade. Multicomputadores com mais de 250 mil CPUs, como o Blue Gene/P da BM, já foram construídos. Uma vez que multiprocessadores são mais fáceis de programar e multicomputadores são mais fáceis de cons- truir, há muita pesquisa sobre projetos de sistemas híbridos que combinam as boas propriedades de cada um. Esses computadores tentam apresentar a ilusão de memória compartilhada sem bancar a despesa de realmente construí-la. Falaremos mais de multiprocessadores e multicomputadores no Capítulo 8. 2.2 Memo ria prima ria A memória é a parte do computador onde são armazenados programas e dados. Alguns cientistas da com- putação (em especial, os britânicos) usam o termo armazém ou armazenagem em vez de memória, se bem que o termo “armazenagem” está sendo usado cada vez mais para a armazenagem em disco. Sem uma memória da qual os processadores possam ler e na qual possam gravar, ou escrever, informações, não haveria computadores digitais com programas armazenados. 2.2.1 Bits A unidade básica de memória é dígito binário, denominado bit. Um bit pode conter um 0 ou um 1. É a unidade mais simples possível. (Um dispositivo capaz de armazenar somente zeros dificilmente poderia formar a base de um sistema de memória; são necessários pelo menos dois valores.) As pessoas costumam dizer que computadores usam aritmética binária porque ela é “eficiente”. O que elas querem dizer, embora quase nunca percebam, é que informações digitais podem ser armazenadas distinguindo entre valores diferentes de alguma quantidade física contínua, tal como tensão ou corrente elétrica. Quanto maior for o número de valores que precisam ser distinguidos, menores serão as separações entre valores adjacentes, e menos confiável será a memória. O sistema numérico binário requer a distinção entre apenas dois valores. Por conseguinte, é o método mais confiável para codificar informações digitais. Se você não estiver familiarizado com números binários, consulte o Apêndice A. Há empresas que anunciam que seus computadores têm aritmética decimal, bem como binária, como é o caso da BM e seus grandes mainframes. Essa façanha é realizada usando-se 4 bits para armazenar um dígito decimal que utiliza um código denominado BC (Binary Coded ecimal  decimal codificado em binário). Quatro bits oferecem 16 combinações, usadas para os 10 dígitos de 0 a 9, mas seis combinações não são usa- das. O número 1.944 é mostrado a seguir codificado em formato decimal e em formato binário puro, usando 16 bits em cada exemplo: decimal: 0001 1001 0100 0100 binário: 0000011110011000 Dezesseis bits no formato decimal podem armazenar os números de 0 a 9999, dando somente 10 mil com- binações, ao passo que um número binário puro de 16 bits pode armazenar 65.536 combinações diferentes. Por essa razão, as pessoas dizem que o binário é mais eficiente. No entanto, considere o que aconteceria se algum jovem e brilhante engenheiro elétrico inventasse um dis- positivo eletrônico de alta confiabilidade que pudesse armazenar diretamente os dígitos de 0 a 9 dividindo a região de 0 a 10 volts em 10 intervalos. Quatro desses dispositivos poderiam armazenar qualquer número decimal de 0 a 9999. Quatro desses dispositivos dariam 10 mil combinações. Eles também poderiam ser usados para armazenar
  • 77. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 58 números binários usando somente 0 e 1, caso em que quatro deles só poderiam armazenar 16 combinações. Com tais dispositivos, o sistema decimal é obviamente mais eficiente. 2.2.2 Enderec os de memo ria Memórias consistem em uma quantidade de células (ou locais), cada uma das quais podendo armazenar uma informação. Cada célula tem um número, denominado seu endereço, pelo qual os programas podem se referir a ela. Se a memória tiver n células, elas terão endereços de 0 a n – 1. Todas as células em uma memória contêm o mesmo número de bits. Se uma célula consistir em k bits, ela pode conter quaisquer das 2k diferentes combina- ções de bits. A Figura 2.9 mostra três organizações diferentes para uma memória de 96 bits. Note que as células adjacentes têm endereços consecutivos (por definição). Figura 2.9 Tre s maneiras de organizar uma memo ria de 96 bits. 0 (c) 1 2 3 4 5 6 7 8 9 10 11 0 1 2 3 4 5 6 7 0 1 2 3 4 5 16 bits (b) 12 bits (a) 8 bits Endereço Endereço 1 célula Endereço Computadores que usam o sistema de números binários (incluindo notação octal ou hexadecimal para números binários) expressam endereços de memória como números binários. Se um endereço tiver m bits, o número máximo de células endereçáveis é 2m . Por exemplo, um endereço usado para referenciar a memória da Figura 2.9(a) precisa de no mínimo 4 bits para expressar todos os números de 0 a 11. Contudo, um endereço de 3 bits é suficiente para as figuras 2.9(b) e (c). O número de bits no endereço determina o número máximo de células diretamente endereçáveis na memória e é independente do número de bits por célula. Uma memória com 212 células de 8 bits cada e uma memória com 212 células de 64 bits cada precisam de endereços de 12 bits. A Figura 2.10 mostra o número de bits por célula para alguns computadores que já foram vendidos comer- cialmente. A significância da célula é que ela é a menor unidade endereçável. Há poucos anos, praticamente todos os fabri- cantes de computadores padronizaram células de 8 bits, que é denominada um byte. O termo octeto também é usado. Bytes são agrupados em palavras. Um computador com uma palavra de 32 bits tem 4 bytes/palavra, enquanto um computador com uma palavra de 64 bits tem 8 bytes/palavra. A significância de uma palavra é que grande parte das instruções efetua operações com palavras inteiras, por exemplo, somando duas palavras. Assim, uma máquina de 32 bits terá registradores de 32 bits e instruções para manipular palavras de 32 bits, enquanto uma máquina de 64 bits terá registradores de 64 bits e instruções para movimentar, somar, subtrair e, em geral, manipular palavras de 64 bits.
  • 78. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 59 Figura 2.10 Nu mero de bits por ce lula para alguns computadores comerciais historicamente interessantes. Computador Bits/célula Burroughs B1700 1 IBM PC 8 DEC PDP-8 12 IBM 1130 16 DEC PDP-15 18 XDS 940 24 Electrologica X8 27 XDS Sigma 9 32 Honeywell 6180 36 CDC 3600 48 CDC Cyber 60 2.2.3 Ordenac a o de bytes Os bytes em uma palavra podem ser numerados da esquerda para a direita ou da direita para a esquerda. A princípio, essa opção pode parecer sem importância, mas, como veremos em breve, ela tem consideráveis impli- cações. A Figura 2.11(a) retrata parte da memória de um computador de 32 bits cujos bytes são numerados da esquerda para a direita, tal como o SPARC ou os grandes mainframes da BM. A Figura 2.11(b) dá uma represen- tação análoga de um computador de 32 bits que usa uma numeração da direita para a esquerda, como a família ntel. O primeiro sistema, no qual a numeração começa na ordem “grande”, isto é, na ordem alta, é denominado computador big endian, ao contrário do little endian da Figura 2.11(b). Esses termos se devem a Jonathan Swift, cujo livro As viagens de Gulliver satirizava os políticos que discutiam por que uns eram a favor de quebrar ovos no lado grande (big end) e outros achavam que deviam ser quebrados no lado pequeno (little end). O termo foi empregado pela primeira vez na arquitetura de computadores em um interessante artigo de Cohen (1981). Figura 2.11 (a) Memo ria big endian. (b) Memo ria little endian. 0 0 (a) 4 4 8 8 12 12 0 4 8 12 1 5 9 13 2 6 10 14 3 7 11 15 3 (b) 7 11 15 2 6 10 14 1 5 9 13 0 4 8 12 Endereço Big endian Little endian Endereço Byte Byte Palavra de 32 bits Palavra de 32 bits É importante entender que, tanto no sistema big endian como no little endian, um inteiro de 32 bits com o valor numérico de, digamos, 6 é representado pelos bits 110 nos três bits mais à direita (baixa ordem) de uma palavra e os zeros nos 29 bits da esquerda. No esquema big endian, os bits 110 estão no byte 3 (ou 7, ou 11 etc.), enquanto no esquema little endian eles estão no byte 0 (ou 4, ou 8 etc.). Em ambos os casos, a palavra que contém esses inteiros tem endereço 0.
  • 79. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 60 Se os computadores somente armazenassem inteiros, não haveria nenhum problema. Contudo, muitas apli- cações requerem uma mistura de inteiros, cadeias de caracteres e outros tipos de dados. Considere, por exemplo, um simples registro de pessoal composto de uma cadeia (nome do empregado) e dois inteiros (idade e número do departamento). A cadeia é encerrada com 1 ou mais bytes de valor 0 para completar uma palavra. Para o registro “Jim Smith, idade 21, departamento 260 (1 × 256 + 4 = 260)”, a representação big endian é mostrada na Figura 2.12(a) e a representação little endian é mostrada na Figura 2.12(b). Figura 2.12 (a) Registro de pessoal para uma ma quina big endian. (b) O mesmo registro para uma ma quina little endian. (c) Resultado da transfere ncia do registro de uma ma quina big endian para uma little endian. (d) Resultado da troca de bytes (c). (a) J 0 I M S 4 M I T H 8 0 0 0 0 12 0 0 21 0 16 0 1 4 (b) J 0 M I T 4 I M S 0 8 0 0 H 0 12 0 0 21 0 16 0 1 4 (c) J M I T I M S 0 0 0 H 21 0 0 0 4 1 0 0 (d) J 0 I M S 4 M I T H 8 0 0 0 0 12 0 0 21 0 16 0 1 4 Big endian Little endian Transferência de big endian para little endian Transferência e troca Ambas as representações são boas e internamente consistentes. Os problemas começam quando uma das máquinas tenta enviar um registro à outra por uma rede. amos supor que a big endian envie o registro à little endian um byte por vez, começando com o byte 0 e terminando com o byte 19. (amos ser otimistas e supor que os bits dos bytes não sejam invertidos pela transmissão porque, assim como está, já temos problemas suficientes.) Portanto, o byte 0 da big endian entra na memória da little endian no byte 0 e assim por diante, como mostra a Figura 2.12(c). Quando a little endian tenta imprimir o nome, ela funciona bem, mas a idade sai como 21 × 224 e o depar- tamento também fica errado. Essa situação surge porque a transmissão inverteu a ordem dos caracteres em uma palavra, como deveria, mas também inverteu os bytes de um inteiro, o que não deveria. Uma solução óbvia é fazer o software inverter os bytes de uma palavra após tê-la copiado. sso leva à Figura 2.12(d), que faz os dois inteiros se saírem bem, mas transforma a cadeia em “MJTMS” e deixa o “H” perdido no meio do nada. Essa inversão da cadeia ocorre porque, ao ler a cadeia, o computador lê primeiro o byte 0 (um espaço), em seguida o byte 1 (M), e assim por diante. Não há nenhuma solução simples. Um modo que funciona – porém, ineficiente – é incluir um cabeçalho na frente de cada item de dado, que informa qual tipo de dado vem a seguir (cadeia, inteiro ou outro) e qual é seu comprimento. sso permite que o destinatário efetue apenas as conversões necessárias. De qualquer modo, é preciso deixar claro que a falta de um padrão para a ordenação de bytes é um grande aborrecimento quando há troca de dados entre máquinas diferentes. 2.2.4 Co digos de correc a o de erro Memórias de computador podem cometer erros de vez em quando devido a picos de tensão na linha elé- trica, raios cósmicos ou outras causas. Para se resguardar contra esses erros, algumas memórias usam códigos de detecção de erros ou códigos de correção de erros. Quando são usados, bits extras são adicionados a cada palavra de memória de modo especial. Quando uma palavra é lida na memória, os bits extras são verificados para ver se ocorreu um erro. Para entender como os erros podem ser manipulados, é preciso ver de perto o que é, na realidade, um erro. Suponha que uma palavra de memória consista em m bits de dados, aos quais serão adicionados r bits redundantes,
  • 80. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 61 ou de verificação. Seja o comprimento total n (isto é, n = m + r). Uma unidade de n bits que contém m dados e r bits de verificação costuma ser denominada uma palavra de código de n bits. Dadas duas palavras de código quaisquer, por exemplo, 10001001 e 10110001, é possível determinar quan- tos bits correspondentes são diferentes. Nesse caso, 3 bits são diferentes. Para saber quantos bits são diferentes, basta calcular o ECLUSE OR (OU ECLUSO) booleano bit por bit das duas palavras de código e contar o número de bits 1 no resultado. O número de posições de bit nas quais as duas palavras de código diferem é deno- minado distância de Hamming (Hamming, 1950). Sua principal significância é que, se duas palavras de código estiverem separadas por uma distância de Hamming d, será preciso d erros de único bit para converter uma na outra. Por exemplo, as palavras de código 11110001 e 00110000 estão a uma distância de Hamming 3 porque é preciso 3 erros de único bit para converter uma na outra. Com uma palavra de memória de m bits, todos os 2m padrões de bits são válidos, mas, devido ao modo como os bits de verificação são computados, somente 2m das 2n palavras de código são válidas. Se uma leitura de memó- ria aparecer com uma palavra de código inválida, o computador sabe que ocorreu um erro de memória. Dado o algoritmo para calcular os bits de verificação, é possível montar uma lista completa das palavras de código válidas e, por meio dela, achar as duas palavras de código cuja distância de Hamming seja mínima. Essa distância é a distância de Hamming do código completo. As propriedades de detecção de erro e correção de erro de um código dependem de sua distância de Hamming. Para detectar d erros de único bit, você precisa de um código de distância d + 1 porque, com tal código, não existe nenhum modo que permita que d erros de único bit mudem uma palavra de código válida para outra. De modo semelhante, para corrigir erros de único bit, você precisa de um código de distância 2d + 1 porque, desse modo, as palavras de código válidas estão tão distantes uma da outra que, mesmo que d mude, a palavra de código original ainda estará mais perto do que qualquer outra, portanto, ela pode ser unicamente determinada. Como um exemplo simples de um código de detecção de erro, considere um código em que um único bit de paridade é anexado aos dados. O bit de paridade é escolhido de modo que o número de bits 1 na palavra de código seja par (ou ímpar). Tal código tem uma distância 2, uma vez que qualquer erro de bit único produz uma palavra de código com paridade errada. Ou seja, ele precisa de dois erros de único bit para ir de uma palavra de código válida até outra palavra de código válida. Ele pode ser usado para detectar erros isolados. Sempre que uma palavra que contenha paridade errada for lida da memória, uma condição de erro é sinalizada. O programa não pode continuar, mas, ao menos, nenhum resultado errado é calculado. Como um exemplo simples de um código de correção de erros, considere um código que tenha apenas quatro palavras de código válidas: 0000000000, 0000011111, 1111100000 e 1111111111 Esse código tem uma distância 5, o que significa que pode corrigir erros duplos. Se a palavra de código 0000000111 chegar, o destinatário sabe que a original deve ter sido 0000011111 (se não houver mais do que um duplo erro). Contudo, se um erro triplo mudar 0000000000 para 0000000111, o erro não pode ser corrigido. magine que queremos projetar um código com m bits de dados e r bits de verificação que permitirá que todos os erros de bits únicos sejam corrigidos. Cada uma das 2m palavras de memória válidas tem n palavras de código inválidas a uma distância 1. Essas palavras de código inválidas são formadas sistematicamente invertendo cada um dos n bits na palavra de código de n bits formada com base nela. Assim, cada uma das 2m palavras de memória válidas requer n + 1 padrões de bits dedicados a ela (para os n possíveis erros e padrão de correção). Uma vez que o número total de padrões de bits é 2n , temos de ter (n + 1)2m ≤ 2n . Usando n = m + r, esse requisito se torna (m + r + 1) ≤ 2r . Dado m, isso impõe um limite inferior ao número de bits de verificação necessários para corrigir erros únicos. A Figura 2.13 mostra o número de bits de verificação requeridos por vários tamanhos de palavras de memória.
  • 81. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 62 Figura 2.13 Nu mero de bits de verificac a o para um co digo que pode corrigir um erro u nico. Tamanho da palavra Bits de verificação Tamanho total Acréscimo percentual 8 4 12 50 16 5 21 31 32 6 38 19 64 7 71 11 128 8 136 6 256 9 265 4 512 10 522 2 Esse limite inferior teórico pode ser conseguido usando um método criado por Richard Hamming (1950). Antes de analisar o algoritmo de Hamming, vamos examinar uma representação gráfica simples que ilustra com clareza a ideia de um código de correção de erros para palavras de 4 bits. O diagrama de enn da Figura 2.14(a) contém três círculos, A, B e C, que juntos formam sete regiões. Como exemplo, vamos codificar a palavra de memória de 4 bits 1100 nas regiões AB, ABC, AC e BC, 1 bit por região (em ordem alfabética). Essa codificação é mostrada na Figura 2.14(a). Figura 2.14 (a) Codificac a o de 1100. (b) Paridade par adicionada. (c) Erro em AC. B A C 1 1 0 0 (a) B (b) A C 1 1 0 0 0 0 1 (c) A B C 1 1 1 1 0 0 0 Erro Bits de paridade Em seguida, acrescentamos um bit de paridade a cada uma dessas três regiões vazias para produzir pari- dade par, como ilustrado na Figura 2.14(b). Por definição, agora a soma dos bits em cada um dos três círculos, A, B e C, é um número par. No círculo A, temos os quatro números 0, 0, 1 e 1, cuja soma total é 2, um núme- ro par. No círculo B, os números são 1, 1, 0 e 0, cuja soma total é 2, um número par. Por fim, no círculo C, temos a mesma coisa. Nesse exemplo, por acaso todos os círculos são iguais, mas as somas de 0 e 4 também são possíveis em outros exemplos. Essa figura corresponde a uma palavra de código com 4 bits de dados e 3 bits de paridade. Agora, suponha que algo de ruim aconteça com o bit na região AC e ele mude de 0 para 1, conforme mostra a Figura 2.14(c). Agora, o computador pode ver que os círculos A e C têm a paridade errada (ímpar). A única mudança de bit individual que pode corrigi-los é restaurar AC para 0, o que corrige o erro. Desse modo, o com- putador pode corrigir automaticamente erros de memória em único bit. Agora, vamos ver como o algoritmo de Hamming pode ser usado para construir códigos de correção de erros para qualquer tamanho de palavra de memória. Em um código de Hamming, são acrescentados r bits de paridade a uma palavra de m bits, formando uma nova palavra de comprimento m + r bits. Os bits são numerados come- çando com 1, não com 0, sendo que o bit 1 é o da extrema esquerda (ordem alta). Todos os bits cujo número de bit for uma potência de 2 são de paridade; os restantes são usados para dados. Por exemplo, com uma palavra de 16 bits, são adicionados 5 bits de paridade. Os bits 1, 2, 4, 8 e 16 são bits de paridade e todos os restantes são
  • 82. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 63 bits de dados. No total, a palavra de memória tem 21 bits (16 de dados, 5 de paridade). Neste exemplo, usaremos (arbitrariamente) a paridade par. Cada bit de paridade verifica posições específicas de bits; o bit de paridade é estabelecido de modo que o número de 1s nas posições verificadas seja par. As posições de bits verificadas pelos bits de paridade são Bit 1 verifica bits 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21. Bit 2 verifica bits 2, 3, 6, 7, 10, 11, 14, 15, 18, 19. Bit 4 verifica bits 4, 5, 6, 7, 12, 13, 14, 15, 20, 21. Bit 8 verifica bits 8, 9, 10, 11, 12, 13, 14, 15. Bit 16 verifica bits 16, 17, 18, 19, 20, 21. Em geral, o bit b é verificado pelos bits b1 , b2 , ..., bj tais que b1 + b2 + ... + bj = b. Por exemplo, o bit 5 é verificado pelos bits 1 e 4 porque 1 + 4 = 5. O bit 6 é verificado pelos bits 2 e 4 porque 2 + 4 = 6 e assim por diante. A Figura 2.15 mostra a construção de um código de Hamming para a palavra de memória de 16 bits 1111000010101110. A palavra de código de 21 bits é 001011100000101101110. Para ver como funciona a correção de erros, considere o que aconteceria se o bit 5 fosse invertido por uma sobrecarga elétrica na linha de força. A nova palavra de código seria 001001100000101101110 em vez de 001011100000101101110. Os 5 bits de paridade serão verificados com os seguintes resultados: Bit de paridade 1 incorreto (1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21 contêm cinco 1s). Bit de paridade 2 correto (2, 3, 6, 7, 10, 11, 14, 15, 18, 19 contêm seis 1s). Bit de paridade 4 incorreto (4, 5, 6, 7, 12, 13, 14, 15, 20, 21 contêm cinco 1s). Bit de paridade 8 correto (8, 9, 10, 11, 12, 13, 14, 15 contêm dois 1s). Bit de paridade 16 correto (16, 17, 18, 19, 20, 21 contêm quatro 1s). Figura 2.15 Construc a o do co digo de Hamming para a palavra de memo ria 1111000010101110 adicionando 5 bits de verificac a o aos 16 bits de dados. 0 1 0 2 1 3 0 4 1 5 1 6 1 7 0 8 0 9 0 10 0 11 0 12 1 13 0 14 1 15 1 16 0 17 1 18 1 19 1 20 0 21 Palavra de memória 1111000010101110 Bits de paridade O número total de 1s nos bits 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 e 21 deve ser par porque está sendo usada a paridade par. O bit incorreto deve ser um dos bits verificados pelo bit de paridade 1 – ou seja, bit 1, 3, 5, 7, 9, 11, 13, 15, 17, 19 ou 21. O bit de paridade 4 está incorreto, o que significa que um dos bits 4, 5, 6, 7, 12, 13, 14, 15, 20 ou 21 está incorreto. O erro deve ser um dos bits que está em ambas as listas, a saber, 5, 7, 13, 15 ou 21. Contudo, o bit 2 está correto, o que elimina os bits 7 e 15. De modo semelhante, o bit 8 está correto, eliminando o 13. Por fim, o bit 16 está correto, eliminando o 21. O único que sobrou é 5, que é o bit que está com erro. Uma vez que foi lido como um 1, ele deveria ser um 0. Dessa maneira, os erros podem ser corrigidos. Um método simples para achar o bit incorreto é calcular antes todos os bits de paridade. Se todos estiverem corretos, não houve nenhum erro (ou então houve mais de um). Em seguida, somar todos os bits de paridade
  • 83. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 64 incorretos, contando 1 para o bit 1, 2 para o bit 2, 4 para o bit 4 e assim por diante. A soma resultante é a posição do bit incorreto. Por exemplo, se os bits de paridade 1 e 4 estiverem incorretos, mas 2, 8 e 16 estiverem corretos, o bit 5 (1 + 4) foi invertido. 2.2.5 Memo ria cache Historicamente, as CPUs sempre foram mais rápidas do que as memórias. Conforme memórias melhoraram as CPUs também se aperfeiçoaram, mantendo o desequilíbrio. Na verdade, à medida que fica possível colocar cada vez mais circuitos em um chip, os projetistas estão usando essas novas facilidades no paralelismo (pipelining) e em operação superescalar, fazendo as CPUs ficarem ainda mais velozes. Projetistas de memória costumam usar nova tecnologia para aumentar a capacidade de seus chips, e não a velocidade, portanto, parece que os problemas estão piorando com o passar do tempo. Na prática, o significado desse desequilíbrio é que, após emitir uma requisição de memória, a CPU não obterá a palavra de que necessita por muitos ciclos de CPU. Quanto mais lenta a memó- ria, mais ciclos a CPU terá de esperar. Como já destacamos, há duas maneiras de tratar desse problema. O modo mais simples é somente iniciar READs (leituras) de memória quando elas forem encontradas, mas continuar executando e bloquear a CPU se uma instrução tentar usar a palavra de memória antes de ela chegar. Quanto mais lenta a memória, maior será a frequência desse problema e maior será a penalidade quando isso, de fato, ocorrer. Por exemplo, se uma instru- ção em cinco toca na memória e o tempo de acesso à memória for de cinco ciclos, o tempo de execução será o dobro daquele que teria sido na memória instantânea. Mas, se o tempo de acesso for de 50 ciclos, então o tempo de execução será elevado por um fator de 11 (5 ciclos para executar instruções mais 50 ciclos para esperar pela memória). A outra solução é ter máquinas que não ficam bloqueadas, mas, em vez disso, exigem que o compilador não gere código para usar palavras antes que elas tenham chegado. O problema é que é muito mais fácil falar dessa abordagem do que executá-la. Muitas vezes, não há nada mais a fazer após um LOAD (carregar), portanto, o compilador é forçado a inserir instruções NOP (nenhuma operação), que nada mais fazem do que ocupar um intervalo (slot) e gastar tempo. Com efeito, essa abordagem é um bloqueio de software em vez de um bloqueio de hardware, mas a degradação do desempenho é a mesma. Na verdade, o problema não é tecnológico, mas econômico. Os engenheiros sabem como construir memórias tão rápidas quanto as CPUs, mas para que executem a toda velocidade, elas têm de estar localizadas no chip da CPU (porque passar pelo barramento para alcançar a memória é uma operação muito lenta). nstalar uma memó- ria grande no chip da CPU faz com que esta fique maior e, portanto, mais cara. Ainda que o custo não fosse uma questão a considerar, há limites de tamanho para um chip de CPU. Assim, a opção se resume a ter uma pequena quantidade de memória rápida ou uma grande quantidade de memória lenta. O que nós gostaríamos de ter é uma grande quantidade de memória rápida a um preço baixo. O interessante é que há técnicas conhecidas para combinar uma pequena quantidade de memória rápida com uma grande quantidade de memória lenta para obter (quase) a velocidade da memória rápida e a capacidade da memória grande a um preço módico. A memória pequena e rápida é denominada cache (do francês cacher, que significa “esconder” e se pronuncia “késh”). Em seguida, descreveremos brevemente como as caches são usadas e como funcionam. O Capítulo 4 apresenta uma descrição mais detalhada. A ideia básica de uma cache é simples: as palavras de memória usadas com mais frequência são mantidas na cache. Quando a CPU precisa de uma palavra, ela examina em primeiro lugar a cache. Somente se a palavra não estiver ali é que ela recorre à memória principal. Se uma fração substancial das palavras estiver na cache, o tempo médio de acesso pode ser muito reduzido. Assim, o sucesso ou o fracasso depende da fração das palavras que estão na cache. Há anos todos sabemos que programas não acessam suas memórias de forma totalmente aleatória. Se uma dada referência à memória for para o endereço A, é provável que a próxima estará na vizinhança geral de A. Um exemplo simples é o próprio programa. Exceto quando se trata de desvios e de chamadas de procedimento, as instruções são buscadas em localizações consecutivas da memória. Além do mais, grande parte do tempo de execução de um programa é
  • 84. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 65 gasto em laços, nos quais um número limitado de instruções é executado repetidas vezes. De modo semelhante, é provável que um programa de manipulação de matrizes fará muitas referências à mesma matriz antes de passar para outra coisa qualquer. A observação de que referências à memória feitas em qualquer intervalo de tempo curto tendem a usar apenas uma pequena fração da memória total é denominada princípio da localidade, e forma a base de todos os sistemas de cache. A ideia geral é que, quando uma palavra for referenciada, ela e algumas de suas vizinhas sejam trazidas da memória grande e lenta para a cache, de modo que, na próxima vez em que for usada, ela possa ser acessada rapidamente. Um arranjo comum da CPU, cache e memória principal é ilustrado na Figura 2.16. Se uma palavra for lida ou escrita k vezes em um curto intervalo de tempo, o computador precisará de 1 referência à memória lenta e k – 1 referências à memória rápida. Quanto maior for k, melhor será o desem- penho global. Figura 2.16 A localizac a o lo gica da cache e  entre a CPU e a memo ria principal. Em termos f sicos, ha  diversos lugares em que ela poderia estar localizada. Memória principal CPU Cache Barramento Podemos formalizar esse cálculo introduzindo c, o tempo de acesso à cache; m, o tempo de acesso à memória principal; e h, a taxa de acerto, que é a fração de todas as referências que podem ser satisfeitas através da cache. Em nosso pequeno exemplo do parágrafo anterior, h = (k – 1)/k. Alguns autores também definem a taxa de falha (na cache), que é 1 – h. Com essas definições, podemos calcular o tempo de acesso médio como segue: tempo de acesso médio = c + (1 – h) m À medida que h → 1, todas as referências podem ser satisfeitas fora da cache e o tempo de acesso médio se aproxima de c. Por outro lado, à medida que h → 0, toda vez será necessária uma referência à memória, portanto, o tempo de acesso se aproxima de c + m, primeiro um tempo para verificar a cache (sem sucesso) e então um tempo m para fazer a referência à memória. Em alguns sistemas, a referência à memória pode ser iniciada em paralelo com a busca na cache, de modo que, se ocorrer uma falha na cache (cache miss), o ciclo da memória já terá sido iniciado. Contudo, essa estratégia requer que a memória possa ser interrompida se houver uma presença na cache (cache hit), o que torna a implantação mais complicada. Usando o princípio da localidade como guia, memórias principais e caches são divididas em blocos de tama- nho fixo. Ao nos referirmos a esses blocos dentro da cache, eles costumam ser chamados de linhas de cache. Quando a busca na cache falha, toda a linha de cache é carregada da memória principal para a cache, e não apenas a palavra que se quer. Por exemplo, com uma linha de cache de 64 bytes de tamanho, uma referência ao endereço de memória 260 puxará a linha que consiste nos bytes 256 a 319 para uma linha de cache. Com um pouco de sorte, algumas das outras palavras na linha de cache também serão necessárias em breve. Esse tipo de operação é mais eficiente do que buscar palavras individuais porque é mais rápido buscar k palavras de uma vez só do que uma palavra k vezes. Além disso, ter entradas de cache de mais do que uma palavra significa que há menor número delas; por conseguinte, é preciso menos memória auxiliar (overhead). Por fim, muitos computadores podem transferir 64 ou 128 bits em paralelo em um único ciclo do barramento, até mesmo em máquinas de 32 bits.
  • 85. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 66 O projeto de cache é uma questão de importância cada vez maior para CPUs de alto desempenho. Um aspec- to é o tamanho da cache. Quanto maior, melhor seu funcionamento, mas também maior é o custo. Um segundo aspecto é o tamanho da linha de cache. Uma cache de 16 KB pode ser dividida em até 1.024 linhas de 16 bytes, 2.048 linhas de 8 bytes e outras combinações. Um terceiro aspecto é a maneira de organização, isto é, como ela controla quais palavras de memória estão sendo mantidas no momento. Examinaremos caches detalhadamente no Capítulo 4. Um quarto aspecto do projeto é se as instruções e dados são mantidos na mesma cache ou em caches dife- rentes. Ter uma cache unificada (instruções e dados usam a mesma cache) é um projeto mais simples e mantém automaticamente o equilíbrio entre buscas de instruções e buscas de dados. No entanto, a tendência hoje é uma cache dividida, com instruções em uma cache e dados na outra. Esse projeto também é denominado arquitetura Harvard e essa referência volta ao passado até o computador Mark  de Howard Aiken, que tinha memórias diferentes para instruções e dados. A força que impele os projetistas nessa direção é a utilização muito difundida de CPUs com paralelismo (pipelined). A unidade de busca de instrução precisa acessar instruções ao mesmo tempo em que a unidade de busca de operandos precisa de acesso aos dados. Uma cache dividida permite acessos paralelos; uma cache unificada, não. Além disso, como as instruções não são modificadas durante a execução, o conteúdo da cache de instrução nunca tem de ser escrito de volta na memória. Por fim, um quinto aspecto é o número de caches. Hoje em dia não é incomum ter chips com uma cache primária no chip, uma cache secundária fora dele, mas no mesmo pacote do chip da CPU, e uma terceira cache ainda mais distante. 2.2.6 Empacotamento e tipos de memo ria Desde os primeiros dias da memória de semicondutor até o início da década 1990, a memória era fabrica- da, comprada e instalada como chips únicos. As densidades dos chips iam de 1 K bits até 1 M bits e além, mas cada chip era vendido como uma unidade separada. Os primeiros PCs costumavam ter soquetes vazios nos quais podiam ser ligados chips de memória adicionais, se e quando o comprador precisasse deles. Desde o início da década de 1990, usa-se um arranjo diferente. Um grupo de chips, em geral 8 ou 16, é montado em uma minúscula placa de circuito impresso e vendido como uma unidade. Essa unidade é deno- minada SIMM (Single Inline Memory Module  módulo único de memória em linha) ou IMM (ual Inline Memory Module  módulo duplo de memória em linha), dependendo se tem uma fileira de conectores de um só lado ou de ambos os lados da placa. Os SMMs têm um conector de borda com 72 contatos e transferem 32 bits por ciclo de clock. Os DMMs em geral têm conectores de borda com 120 contatos em cada lado da placa, perfazendo um total de 240 contatos e transferem 64 bits por ciclo de clock. Os mais comuns hoje são os DMMs DDR3, que é a terceira versão das memórias de taxa dupla. Um exemplo típico de DMM é ilustrado na Figura 2.17. Figura 2.17 Visa o superior de um DIMM de 4 GB, com oito chips de 256 MB em cada lado. O outro lado tem a mesma apare ncia. 133 mm Conector Chip de memória de 256 MB Uma configuração típica de DMM poderia ter oito chips de dados com 256 MB cada. Então, o módulo intei- ro conteria 2 GB. Muitos computadores têm espaço para quatro módulos, o que dá uma capacidade total de 8 GB se usarem módulos de 2 GB e mais, se usarem módulos maiores.
  • 86. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 67 Um DMM fisicamente menor, denominado SO-IMM (Small Outline IMM  IMM pequeno perfil) é usado em notebooks. Pode-se adicionar um bit de paridade ou correção de erro aos DMMS, porém, visto que a taxa média de erro de um módulo é de um erro a cada dez anos, na maioria dos computadores de uso comum e doméstico, detecção e correção de erros são omitidas. 2.3 Memo ria secunda ria Seja qual for o tamanho da memória principal, ela sempre será muito pequena. As pessoas sempre querem armazenar mais informações do que a memória pode conter, ainda mais porque, à medida que a tecnologia melho- ra, elas começam a pensar em armazenar coisas que antes estavam inteiramente no reino da ficção científica. Por exemplo, como as diretrizes orçamentárias do governo dos Estados Unidos obrigam as agências governamentais a gerar sua própria receita, podemos imaginar a Biblioteca do Congresso decidindo digitalizar e vender todo o seu conteúdo como um artigo de consumo (“Todo o conhecimento humano por apenas US$ 299,95”). Cerca de 50 milhões de livros, cada qual com 1 MB de texto e 1 MB de figuras comprimidas, requerem armazenagem de 1014 bytes ou 100 terabytes. Armazenar todos os 50 mil filmes produzidos até agora também faz parte desse carnaval. Essa quantidade de informação não caberá na memória principal, ao menos por algumas décadas. 2.3.1 Hierarquias de memo ria A solução tradicional para armazenar grandes quantidades de dados é uma hierarquia de memória, como ilustrada na Figura 2.18. No topo, estão os registradores da CPU, que podem ser acessados à velocidade total da CPU. Em seguida, vem a memória cache, que está na faixa de 32 KB a alguns megabytes. A memória vem logo após, hoje com tamanhos que vão de 1 GB para sistemas básicos até centenas de gigabytes na extremidade mais alta. Depois, vêm os discos magnéticos, o atual burro de carga da armazenagem permanente. Por fim, temos fitas magnéticas e discos ópticos para armazenagem de arquivos. À medida que descemos na hierarquia, três parâmetros aumentam. Primeiro, o tempo de acesso fica maior. Os registradores da CPU podem ser acessados em um nanossegundo ou menos. Memórias cache demoram um pequeno múltiplo dos registradores da CPU. Acessos à memória principal normalmente levam 10 nanossegundos. Agora, vem uma grande lacuna, porque tempos de acesso a discos são no mínimo 10 vezes mais lentos para discos em estado sólido e centenas de vezes mais lentos para discos magnéticos. Acessos a fitas ou discos óticos podem ser medidos em segundos se a mídia tiver de ser buscada e inserida no drive. Figura 2.18 Hierarquia de memo ria de cinco n veis. Registradores Cache Memória principal Disco magnético ou de estado sólido Fita Disco ótico
  • 87. Largura de um 1 bit é 0,1 a 0,2 mícron Cabeçote de leitura/escrita A sequência circular de bits escritos quando o disco faz uma rotação completa é denominada trilha. Cada trilha é dividida em algum número de setores de tamanho fixo, que em geral contêm 512 bytes de dados, prece- didos por um preâmbulo que permite a sincronização do cabeçote antes de uma leitura ou escrita. Em seguida aos dados há um código de correção de erros (ECC – Error-Correcting Code), ou um código de Hamming ou, mais comumente, um código que pode corrigir múltiplos erros, denominado código de Reed-Solomon. Entre setores consecutivos há uma pequena lacuna intersetores. Alguns fabricantes citam a capacidade de seus discos no estado sem formatação (como se cada trilha contivesse apenas dados), mas uma medida mais honesta é a capa- cidade no estado formatado, que não conta os preâmbulos, ECCs e lacunas como dados. A capacidade do disco formatado é normalmente 15% menor do que a capacidade sem formatação. O r g a n i z a ç ã o e s t r u t u r a d a d e c o m p u t a d o r e s 68 Segundo, a capacidade de armazenagem aumenta à medida que descemos na hierarquia. Registradores de CPU são bons para, talvez, 128 bytes, caches para algumas dezenas de megabytes, memórias principais para alguns gigabytes, discos em estado sólido para centenas de gigabytes e discos magnéticos para terabytes. Fitas e discos ópticos costumam ser mantidos off-line, portanto, sua capacidade é limitada apenas pelo orçamento do usuário. Terceiro, o número de bits por dólar gasto aumenta descendo a hierarquia. Embora os preços atuais mudem com rapidez, a memória principal é medida em dólares/megabyte, o disco em estado sólido em dólares/gigabyte e a armazenagem em disco magnético e fita em centavos/gigabyte. Já vimos registradores, cache e memória principal. Nas seções seguintes, vamos examinar os discos magnéticos e os discos em estado sólido; depois, estudaremos os discos óticos. Não estudaremos fitas porque são raramente usadas, exceto para cópias de segurança (backup) e, de qualquer forma, não há muita coisa a dizer sobre elas. 2.3.2 Discos magnéticos Um disco magnético é composto de um ou mais pratos de alumínio com um revestimento magnetizável. No início, esses pratos tinham até 50 cm de diâmetro, mas agora têm normalmente de 3 a 9 cm, e discos para notebooks já estão com menos de 3 cm e continuam encolhendo. Um cabeçote de disco que contém uma bobina de indução flutua logo acima da superfície, apoiado sobre um colchão de ar. Quando uma corrente positiva ou negativa passa pelo cabeçote, ele magnetiza a superfície logo abaixo dele, alinhando as partículas magnéticas para a esquerda ou para a direita, dependendo da polaridade da corrente. Quando o cabeçote passa sobre uma área magnetizada, uma corrente positiva ou negativa é induzida nele, o que possibilita a leitura dos bits armazenados antes. Assim, à medida que o prato gira sob o cabeçote, uma corrente de bits pode ser escrita e mais tarde lida. A geometria de uma trilha de disco é mostrada na Figura 2.19. Figura 2.19 Porção de uma trilha de disco. Dois setores são ilustrados. Braço do disco Read/write head Direction of disk rotation 4096 data bits Preamble E C C E C C 1 setor Lacuna de intersecção Direção da rotação do disc o Preâm bulo Preâmbulo Largura da trilha é 1–2 micra 4096
  • 88. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 69 Todos os discos têm braços móveis que podem se mover para dentro e para fora a diferentes distâncias radiais da haste ao redor da qual o prato gira. A cada distância radial pode ser escrita uma trilha diferente. Assim, as trilhas são uma série de círculos concêntricos ao redor da haste. A largura de uma trilha depende da largura do cabeçote e da precisão com que ele pode ser posicionado radialmente. Com tecnologia atual, os discos têm em torno de 50 mil trilhas por centímetro, resultando em larguras de trilha na faixa de 200 nanô- metros (1 nanômetro = 1/1.000.000 mm). Deve-se notar que uma trilha não é um sulco físico na superfície, mas apenas um anel de material magnetizado com pequenas áreas de proteção que o separa das trilhas que estão dentro e fora dele. A densidade linear de bits ao redor da circunferência da trilha é diferente da radial. Em outras palavras, o número de bits por milímetro medida em torno de uma trilha é diferente do número de bits por milímetro a partir do centro em direção à borda externa. A densidade ao redor de uma trilha é determinada em grande parte pela pureza da superfície e pela qualidade do ar. Os discos de hoje atingem densidades de 25 gigabits/cm. A densidade radial é determinada pela precisão que o braço pode ter para chegar a uma trilha. Assim, um bit é muitas vezes maior na direção radial em comparação com a circunferência, conforme sugere a Figura 2.19. Para atingir densidades ainda mais altas, os fabricantes de discos estão desenvolvendo tecnologias nas quais a dimensão “longa” dos bits não está ao longo da circunferência do disco, mas na direção vertical, dentro do óxido de ferro. Essa técnica é denominada gravação perpendicular e demonstrou-se que pode oferecer densidades de dados de até 100 gigabits/cm. É provável que essa se torne a tecnologia dominante nos próximos anos. Para conseguir alta qualidade de superfície e ar, a maioria dos discos é selada na fábrica para evitar a entrada de pó. Esses drives eram denominados discos Winchester, pois os primeiros deles (criados pela BM) tinham 30 MB de armazenagem selada e fixa e 30 MB de armazenagem removível. Conta a história que esses discos 30-30 lembravam às pessoas os rifles Winchester 30-30, que desempenharam um papel importante na abertura das fronteiras norte-americanas, e o nome “Winchester” ficou. Agora, eles são chamados simples- mente de discos rígidos, para diferenciá-los dos antigos disquetes (ou discos flexíveis) usados nos primeiros computadores pessoais. Nessa área, é muito difícil escolher um nome para alguma coisa que não se torne ridículo 30 anos depois. A maioria dos discos é composta de vários pratos empilhados na vertical, como ilustrado na Figura 2.20. Cada superfície tem seu próprio braço e cabeçote. Os braços são agrupados de modo que todos se movimentem para diferentes posições radiais ao mesmo tempo. O conjunto de trilhas em uma dada posição radial é denomi- Figura 2.20 Disco com quatro pratos. Superfície 7 Superfície 6 Superfície 5 Superfície 4 Superfície 3 Superfície 2 Superfície 1 Superfície 0 Cabeçote de leitura/escrita (1 por superfície) Direção do movimento do braço
  • 89. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 70 nado cilindro. Os discos usados hoje em PCs costumam ter de 1 a 12 pratos por drive, o que resulta em 2 a 24 superfícies de gravação. Discos de última geração podem armazenar 1 TB em um único prato, e esse limite cer- tamente crescerá com o tempo. O desempenho do disco depende de vários fatores. Para ler ou escrever um setor, primeiro o braço deve se deslocar até a posição radial correta. Essa ação é denominada busca (seek). Tempos médios de busca (entre trilhas aleatórias) estão na faixa de 5 a 10 ms, embora buscas entre trilhas consecutivas agora já estejam abaixo de 1 ms. Logo que o cabeçote estiver posicionado radialmente, há um atraso, denominado latência rotacional, até que o setor desejado gire sob o cabeçote. A maioria dos discos gira a 5.400 RPM, 7.200 RPM ou 10.800 RPM, portanto, o atraso médio (meia rotação) é de 3 a 6 ms. O tempo de transferência depende da densidade linear e da velocidade de rotação. Com taxas de transferência típicas de 150 MB/s, um setor de 512 bytes demora cerca de 3,5 µs. Por conseguinte, o tempo de busca e a latência rotacional dominam o tempo de transferência. Ler setores aleatórios por todo o disco é claramente um modo ineficiente de operar. ale a pena mencionar que, por conta de preâmbulos, ECCs, lacunas intersetores, tempos de busca e latên- cias rotacionais, há uma grande diferença entre taxa de rajada (burst rate) máxima de um drive e sua taxa máxima sustentada. A taxa máxima de rajada é a taxa de dados, uma vez que o cabeçote está sobre o primeiro bit de dados. O computador deve ser capaz de manipular os dados que estão chegando com essa mesma rapidez. Contudo, o drive só pode manter essa taxa para um único setor. Para algumas aplicações, como multimídia, o que importa é a taxa sustentada média durante um período de segundos, que também tem de levar em conta as necessárias buscas e atrasos rotacionais. Um pouco de raciocínio e a utilização daquela velha fórmula de matemática do colegial para a circunferên- cia de um círculo, c = 2πr, revelarão que a distância linear ao redor das trilhas mais externas é maior do que a das trilhas mais internas. Uma vez que todos os discos magnéticos giram com velocidade angular constante, não importando onde estão os cabeçotes, essa observação cria um problema. Nos drives antigos, os fabricantes usavam a máxima densidade linear possível na trilha mais interna e densidades lineares de bits sucessivamente menores nas trilhas mais externas. Se um disco tivesse 18 setores por trilha, por exemplo, cada uma ocupava 20 graus de arco, não importando em qual cilindro se encontrava. Hoje, usa-se uma estratégia diferente. Os cilindros são divididos em zonas (normalmente, 10 a 30 por drive) e o número de setores por trilha aumenta de zona em zona partindo da trilha mais interna para a mais externa. Essa mudança dificulta o rastreamento de informações mas aumenta a capacidade do drive, que é considerada mais importante. Todos os setores são do mesmo tamanho. A Figura 2.21 mostra um disco com cinco zonas. Figura 2.21 Disco com cinco zonas. Cada zona tem muitas trilhas. Setor
  • 90. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 71 Associado a cada drive há um controlador de disco, um chip que controla o drive. Alguns controladores contêm uma CPU completa. Entre as tarefas do controlador estão: aceitar comandos do software, como READ, WRTE e FORMAT (escrevendo todos os preâmbulos), controlar o movimento do braço, detectar e corrigir erros e converter bytes de 8 bits lidos na memória em uma corrente serial de bits e vice-versa. Alguns controladores também manipulam o buffer de múltiplos setores, fazendo cache de setores lidos para potencial uso futuro e rema- peando setores ruins. Essa última função é causada pela existência de setores que têm um ponto ruim, ou seja, permanentemente magnetizado. Quando descobre um setor ruim, o controlador o substitui por um dos setores sobressalentes reservados para esse fim dentro de cada cilindro ou zona. 2.3.3 Discos IDE Os discos dos modernos computadores pessoais evoluíram daquele usado no BM PC T, que era um disco Seagate de 10 MB controlado por um controlador de disco ebec em um cartão de encaixe (plug-in). O disco Seagate tinha 4 cabeçotes, 306 cilindros e 17 setores por trilha. O controlador conseguia manipular dois drives. O sistema operacional lia e escrevia em um disco colocando parâmetros em registradores da CPU e então chamando o BIOS (Basic Input Output System  sistema básico de entrada e saída) localizado na memória somente de leitura do PC. O BOS emitia as instruções de máquina para carregar os registradores do controlador de disco que iniciava as transferências. A tecnologia evoluiu rapidamente e passou do controlador em uma placa separada para o controlador inte- grado com os drives, começando com drives IE (Integrated rive Electronics  eletrônica integrada ao drive) em meados da década de 1980. Contudo, as convenções de chamada do BOS não foram alteradas por causa da compatibilidade. Essas convenções de chamada endereçavam setores dando seus números de cabeçote, cilindro e setor, sendo que a numeração de cabeçotes e cilindros começava em 0, e de setores, em 1. Essa escolha provavel- mente se deveu a um erro da parte do programador original do BOS, que escreveu sua obra-prima em assembler 8088. Com 4 bits para o cabeçote, 6 bits para o setor e 10 bits para o cilindro, o drive máximo podia ter 16 cabe- çotes, 63 setores e 1.024 cilindros, para um total de 1.032.192 setores. Esse drive máximo tinha uma capacidade de 504 MB, o que devia parecer uma infinidade naquela época, porém, agora, decerto não. (Hoje você criticaria uma nova máquina que não pudesse manipular drives maiores do que 1.000 TB?) nfelizmente, não passou muito tempo e apareceram drives acima de 504 MB, mas com a geometria errada (por exemplo, 4 cabeçotes, 32 setores e 2.000 cilindros totalizam 256.000 setores). O sistema operacional não conseguia endereçá-los de modo algum, por causa das convenções de chamada do BOS há muito cristalizadas. O resultado é que os controladores de disco começaram a mentir, fingindo que a geometria estava dentro dos limites do BOS embora, na verdade, estivesse remapeando a geometria virtual para a geometria real. Embora essa técnica funcionasse, causava grandes estragos nos sistemas operacionais que posicionavam dados cuidadosamente para minimizar tempos de busca. Com o tempo, os drives DE evoluíram para drives EIE (Extended IE  IE estendido), que também suportavam um segundo esquema de endereçamento denominado LB (Logical Block ddressing  endereça- mento de blocos lógicos), que numera os setores começando em 0 até um máximo de 228 – 1. Esse esquema requer que o controlador converta endereços LBA para endereços de cabeçote, setor e cilindro, mas ultrapassa o limite de 504 MB. nfelizmente, ele criava um novo gargalo a 228 × 29 bytes (128 GB). Em 1994, quando foi adotado o padrão EDE, ninguém poderia imaginar discos de 128 GB. Comitês de padronização, assim como os políticos, têm tendência de empurrar problemas para que o próximo comitê os resolva. Drives e controladores EDE também tinham outras melhorias. Por exemplo, controladores EDE podiam ter dois canais, cada um com um drive primário e um secundário. Esse arranjo permitia um máximo de quatro drives por controlador. Drives de CD-ROM e DD também eram suportados, e a taxa de transferência aumentou de 4 MB/s para 16,67 MB/s. Enquanto a tecnologia de disco continuava a melhorar, o padrão EDE continuava a evoluir, mas, por alguma razão, o sucessor do EDE foi denominado -3 ( ttachment), uma referência ao BM PC/AT (onde AT se referia à então “tecnologia avançada” – Advanced Technology – de uma CPU de 16 bits executando em 8 MHz).
  • 91. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 72 Na edição seguinte, o padrão recebeu o nome de PI-4 ( Packet Interface  interface de pacotes ) e a velocidade aumentou para 33 MB/s. Com o ATAP-5, ela alcançou 66 MB/s. Nessa época, o limite de 128 GB imposto pelos endereços LBA de 28 bits estava ficando cada vez mais ameaçador, portanto, o ATAP-6 alterou o tamanho do LBA para 48 bits. O novo padrão entrará em dificuldade quando os discos chegarem a 248 × 29 bytes (128 PB). Com um aumento de capacidade de 50% ao ano, o limite de 48 bits deverá durar até mais ou menos 2035. Para saber como o problema foi resolvido, favor consultar a décima primeira edição deste livro. A melhor aposta é que o tamanho do LBA alcance 64 bits. O padrão ATAP-6 também aumentou a taxa de transferência para 100 MB/s e atacou a questão do ruído do disco pela primeira vez. O padrão ATAP-7 é uma ruptura radical com o passado. Em vez de aumentar o tamanho do conector do drive (para aumentar a taxa de dados), esse padrão usa o que é chamado  serial para transferir 1 bit por vez por um conector de 7 pinos a velocidades que começam em 150 MB/s e que, com o tempo, espera-se que alcancem 1,5 GB/s. Substituir o atual cabo plano de 80 fios por um cabo redondo com apenas alguns milímetros a mais de espessura melhora o fluxo de ar dentro do computador. Além disso, o ATA serial usa 0,5 volt para sinalização (em comparação com os 5 volts dos drives ATAP-6), o que reduz o consumo de energia. É provável que, dentro de alguns anos, todos os computadores usarão ATA serial. A questão do consumo de energia pelos discos é cada vez mais importante, tanto na extremidade mais alta do mercado, onde centrais de dados têm vastas coleções de discos, como na mais baixa, onde os notebooks são limitados em questão de energia (Gurumurthi et al., 2003). 2.3.4 Discos SCSI Discos SCS não são diferentes de discos DE em relação ao modo como seus cilindros, trilhas e setores são organizados, mas têm uma interface diferente e taxas de transferência muito mais elevadas. A história dos SCS remonta a Howard Shugart, o inventor do disco flexível, cuja empresa lançou o disco SAS (Shugart Associates System nterface – interface de sistema da Shugart Associates) em 1979. Após algumas modificações e muita dis- cussão, a ANS o padronizou em 1986 e mudou o nome para SCSI (Small Computer System Interface  interface para sistemas computacionais pequenos). A pronúncia de SCS em inglês é “scâzi”, de scuzzy. Desde então, foram padronizadas versões cada vez mais rápidas sob os nomes de Fast SCS (10 MHz), Ultra SCS (20 MHz), Ultra2 SCS (40 MHz), Ultra3 SCS (80 MHz) e Ultra4 SCS (160 MHz). Cada uma dessas versões também tem uma versão larga (16 bits). As principais combinações são mostradas na Figura 2.22. Figura 2.22 Alguns dos poss veis para metros SCSI. Nome Bits de dados Frequência do barramento (MHz) MB/s SCSI-1 8 5 5 Fast SCSI 8 10 10 Wide Fast SCSI 16 10 20 Ultra SCSI 8 20 20 Wide Ultra SCSI 16 20 40 Ultra2 SCSI 8 40 40 Wide Ultra2 SCSI 16 40 80 Wide Ultra3 SCSI 16 80 160 Wide Ultra4 SCSI 16 160 320 Wide Ultra5 SCSI 16 320 640
  • 92. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 73 Como têm altas taxas de transferência, os discos SCS são o disco padrão de grande parte das estações de trabalho e servidores, em especial aqueles que trabalham na configuração RAD (ver adiante). O SCS é mais do que apenas uma interface de disco rígido. É um barramento ao qual podem ser conectados um controlador SCS e até sete dispositivos. Entre eles, podem estar um ou mais discos rígidos SCS, CD-ROMs, gravadores de CD, scanners, unidades de fita e outros periféricos SCS. Cada dispositivo SCS tem um único D, de 0 a 7 (15 para o SCS largo – wide SCS). Cada dispositivo tem dois conectores: um para entrada e um para saída. Cabos conectam a saída de um dispositivo à entrada do seguinte, em série, como se fosse um cordão de lâmpadas baratas de árvore de Natal. O último dispositivo do cordão deve ser terminado para evitar que reflexões das extremidades do barramento SCS interfiram com outros dados no barramento. Em geral, o controlador está em um cartão de encaixe (plug-in) no início da cadeia de cabos, embora essa configuração não seja uma exigência estrita do padrão. O cabo mais comum para SCS de 8 bits tem 50 fios, 25 dos quais são terras que fazem par com os outros 25 fios para dar excelente imunidade contra ruído, necessária para operação em alta velocidade. Dos 25 fios, 8 são para dados, 1 é para paridade, 9 são para controle e os restantes são para energia elétrica ou reservados para utilização futura. Os dispositivos de 16 bits (e 32 bits) precisam de um segundo cabo para os sinais adicionais. Os cabos podem ter muitos metros de comprimento, o que permite drives externos, scanners etc. Controladores e periféricos SCS podem funcionar como iniciadores ou como alvos. Em geral, o controlador, agindo como iniciador, emite comandos para discos e outros periféricos que agem como alvos. Esses comandos são blocos de até 16 bytes, que dizem ao alvo o que ele tem de fazer. Comandos e respostas ocorrem em fases, usando vários sinais de controle para delinear as fases e arbitrar o acesso ao barramento quando vários dispositi- vos tentam usá-lo ao mesmo tempo. Essa arbitragem é importante porque o SCS permite que todos os disposi- tivos funcionem simultaneamente, o que de modo potencial resulta em grande aumento do desempenho em um ambiente em que há múltiplos processos ativos ao mesmo tempo. DE e EDE permitem apenas um dispositivo ativo por vez. 2.3.5 RAID O desempenho da CPU vem tendo aumento exponencial na última década e dobra a cada 18 meses mais ou menos. O mesmo não acontece com o desempenho do disco. Na década de 1970, os tempos médios de busca em discos de minicomputadores eram de 50 a 100 ms. Agora, são de 10 ms. Na maioria das indústrias técnicas (por exemplo, automóveis ou aviação), um fator de 5 a 10 de melhoria de desempenho em duas décadas seria uma grande notícia, mas na indústria de computadores isso é constrangedor. Assim, a lacuna entre o desempenho da CPU e o do disco ficou cada vez maior com o passar do tempo. Como vimos, muitas vezes é usado processamento paralelo para acelerar o desempenho da CPU. Ao longo dos anos, ocorreu a várias pessoas que a E/S paralela também poderia ser uma boa ideia. Em seu artigo de 1988, Patterson et al. sugeriram seis organizações específicas de disco que poderiam ser usadas para melhorar o desempenho, a confiabilidade do disco, ou ambos (Patterson et al., 1988). Essas ideias logo foram adotadas pela indústria e deram origem a uma nova classe de dispositivos de E/S, denominados RI. Patterson et al. definiram RI como Redundant rray of Inexpensive isks (arranjo redundante de discos baratos), mas a indústria redefiniu o  como “independente” em vez de barato (inexpensive) – talvez para que pudessem usar discos caros? Já que também era preciso ter um vilão (como no caso RSC versus CSC, também devido a Patterson), nesse caso o bandido era o SLE (Single Large Expensive isk  disco único grande e caro). A ideia fundamental de um RAD é instalar uma caixa cheia de discos próxima ao computador, em geral um grande servidor, substituir a placa do controlador de disco por um controlador RAD, copiar os dados para o RAD e então continuar a execução normal. Em outras palavras, um RAD deveria parecer um SLED para o sistema ope- racional, mas ter melhor desempenho e melhor confiabilidade. Uma vez que discos SCS têm bom desempenho,
  • 93. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 74 baixo preço e a capacidade de ter até 7 drives em um único controlador (15 para o wide SCS), é natural que a maioria dos RADs consista em um controlador RAD SCS mais uma caixa de discos SCS que parecem para o sistema operacional como um único disco grande. Portanto, não é preciso alterar software para usar o RAD, um ótimo argumento de venda para muitos administradores de sistemas. Além de parecerem um disco único para o software, há uma propriedade comum a todos os RADs, que é a distribuição dos dados pelos drives para permitir operação paralela. Patterson et al. definiram vários esquemas diferentes para fazer isso e, agora, eles são conhecidos como RAD nível 0 até RAD nível 5. Além disso, há alguns outros níveis menos importantes que não discutiremos. O termo “nível” é, de certa manei- ra, uma denominação imprópria, uma vez que não há nenhuma hierarquia envolvida; há simplesmente seis diferentes organizações possíveis, cada qual com uma mistura diferente de características de confiabilidade e desempenho. O RAD nível 0 é ilustrado na Figura 2.23(a). Consiste em ver o disco virtual simulado pelo RAD como se fosse dividido em tiras de k setores cada: os setores 0 a k – 1 são a tira 0, os setores k a 2k – 1 são a tira 1 e assim por diante. Para k = 1, cada tira é um setor; para k = 2, uma tira são dois setores etc. A organização RAD nível 0 escreve tiras consecutivas nos drives por alternância circular, como demonstrado na Figura 2.23(a) para um RAD com quatro drives de disco. Essa distribuição de dados por múltiplos drives é denominada striping (ou segmentação). Por exemplo, se o software emitir um comando para ler um bloco de dados que consiste em quatro tiras consecutivas e começa na borda da tira, o controlador RAD o subdividirá em quatro comandos separados, um para cada disco, e fará com que eles funcionem em paralelo. Assim, temos E/S paralela sem que o software saiba disso. O RAD nível 0 funciona melhor com requisições grandes; quanto maiores, melhor. Se uma requisição for maior do que o número de drives vezes o tamanho da tira, alguns drives receberão múltiplas requisições, de modo que, quando terminam a primeira, iniciam a segunda. Cabe ao controlador dividir a requisição e alimentar os comandos adequados aos discos adequados na sequência certa e então agrupar os resultados na memória corre- tamente. O desempenho é excelente e a execução é direta. O RAD nível 0 funciona pior com sistemas operacionais que costumam requisitar dados a um setor por vez. Os resultados serão corretos, mas não há paralelismo e, por conseguinte, nenhum ganho de desempenho. Outra desvantagem dessa organização é que a confiabilidade é potencialmente pior do que ter um SLED. Se um RAD consistir em quatro discos, cada um com um tempo médio de falha de 20 mil horas, mais ou menos uma vez a cada 5 mil horas um drive falhará e haverá perda total de dados. Um SLED com um tempo médio de falha de 20 mil horas seria quatro vezes mais confiável. Como não há nenhuma redundância presente nesse projeto, na realidade ele não é um RAD verdadeiro. A próxima opção, RAD nível 1, mostrada na Figura 2.23(b), é um RAD verdadeiro. Ele duplica todos os discos, portanto, há quatro discos primários e quatro de backup. Para uma escrita, cada tira é escrita duas vezes. Para uma leitura, qualquer das duas cópias pode ser usada, distribuindo a carga por mais drives. Por conseguinte, o desempenho da escrita não é melhor do que o de um único drive, mas o de leitura pode ser duas vezes melhor. A tolerância a falhas é excelente: se um drive falhar, basta usar a outra cópia em seu lugar. A recuperação consiste na simples instalação de um novo drive e em copiar todo o drive de backup para ele. Ao contrário dos níveis 0 e 1, que trabalham com tiras de setores, o RAD nível 2 trabalha por palavra, pos- sivelmente até por byte. magine dividir cada byte do disco virtual único em um par de nibbles de 4 bits e então acrescentar um código de Hamming a cada um para formar uma palavra de 7 bits, dos quais os bits 1, 2 e 4 fos- sem de paridade. magine ainda que a posição do braço e a posição rotacional dos sete drives da Figura 2.23(c) fossem sincronizadas. Então, seria possível escrever a palavra de 7 bits codificada por Hamming nos sete drives, um bit por drive.
  • 94. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 75 Figura 2.23 RAIDs n veis 0 a 5. Os drives de backup e paridade esta o sombreados. (a) (b) (c) (d) (e) (f) RAID nível 0 RAID nível 1 RAID nível 2 RAID nível 3 RAID nível 4 RAID nível 5 Tira 0 Tira 1 Tira 2 Tira 3 Tira 4 Tira 5 Tira 6 Tira 7 Tira 8 Tira 9 Tira 10 Tira 11 Tira 0 Tira 1 Tira 2 Tira 3 Tira 4 Tira 5 Tira 6 Tira 7 Tira 8 Tira 9 Tira 10 Tira 11 Tira 0 Tira 1 Tira 2 Tira 3 Tira 4 Tira 5 Tira 6 Tira 7 Tira 8 Tira 9 Tira 10 Tira 11 Bit 1 Bit 2 Bit 3 Bit 4 Bit 5 Bit 6 Bit 7 Bit 1 Bit 2 Bit 3 Bit 4 Paridade Tira 0 Tira 1 Tira 2 Tira 3 P0-3 Tira 4 Tira 5 Tira 6 Tira 7 P4-7 Tira 8 Tira 9 Tira 10 Tira 11 P8-11 Tira 0 Tira 1 Tira 2 Tira 3 P0-3 Tira 4 Tira 5 Tira 6 P4-7 Tira 7 Tira 8 Tira 9 P8-11 Tira 10 Tira 11 Tira 12 P12-15 Tira 13 Tira 14 Tira 15 P16-19 Tira 16 Tira 17 Tira 18 Tira 19 O computador Thinking Machine CM-2 usava esse esquema, pegando palavras de 32 bits de dados e adicio- nando 6 bits de paridade para formar uma palavra de Hamming de 38 bits, mais um bit extra para paridade de palavra, e distribuindo cada palavra em 39 drives de disco. O rendimento total era imenso porque em um tempo de setor ele podia escrever o equivalente a 32 setores de dados. Além disso, perder um drive não causava problemas,
  • 95. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 76 porque essa perda equivaleria a perder 1 bit em cada palavra de 39 bits lida, algo que o código de Hamming poderia manipular facilmente. Uma desvantagem é que esse esquema requer que as rotações de todos os drives sejam sincronizadas, e isso só faz sentido com um número substancial de drives (mesmo com 32 drives de dados e 6 drives de paridade, a sobrecarga seria de 19%). O esquema também exige muito do controlador, uma vez que ele deve efetuar uma soma de verificação (checksum) de Hamming a cada tempo de bit. O RAD nível 3, ilustrado na Figura 2.23(d), é uma versão simplificada do RAD nível 2. Nesse arranjo, um único bit de paridade é computado para cada palavra de dados e escrito em um drive de paridade. Como no RAD nível 2, os drives devem estar em exata sincronia, uma vez que palavras de dados individuais estão distribuídas por múltiplos drives. À primeira vista, pode parecer que um único bit de paridade dá somente detecção de erro, e não correção de erro. Para o caso de erros aleatórios não detectados, essa observação é verdadeira. Todavia, para o caso de uma falha de drive, ela provê correção total de erros de 1 bit, uma vez que a posição do bit defeituoso é conhecida. Se um drive falhar, o controlador apenas finge que todos os seus bits são 0s. Se uma palavra tiver um erro de parida- de, o bit que vem de um drive extinto deve ter sido um 1, portanto, é corrigido. Embora ambos os RADs níveis 2 e 3 ofereçam taxas de dados muito altas, o número de requisições separadas de E/S por segundo que eles podem manipular não é melhor do que o de um único drive. RADs níveis 4 e 5 de novo trabalham com tiras, e não com palavras individuais com paridade, e não reque- rem drives sincronizados. O RAD nível 4 [veja a Figura 2.23(e)] é como o RAD nível 0, com paridade tira por tira escrita em um drive extra. Por exemplo, se cada tira tiver k bytes de comprimento, todas as tiras passam por uma operação de ECLUSE OR, resultando em uma tira de paridade de k bytes de comprimento. Se um drive falhar, os bytes perdidos podem ser recalculados com base no drive de paridade. Esse projeto protege contra a perda de um drive, mas seu desempenho é medíocre para pequenas atualiza- ções. Se um setor for alterado, é necessário ler todos os drives para recalcular a paridade que, então, precisará ser reescrita. Como alternativa, ele pode ler os velhos dados de usuário e os velhos dados de paridade e recalcular nova paridade, e partir deles. Mesmo com essa otimização, uma pequena atualização requer duas leituras e duas escritas, o que é, claramente, um mau arranjo. Como consequência da carga pesada sobre o drive de paridade, ele pode se tornar um gargalo. Esse gargalo é eliminado no RAD nível 5 distribuindo os bits de paridade uniformemente por todos os drives, por alternância circular, conforme mostra a Figura 2.23(f). Contudo, no evento de uma falha de drive, a reconstrução do drive danificado é um processo complexo. 2.3.6 Discos em estado so lido Discos feitos de memória flash não volátil, geralmente denominados discos em estado sólido (SSs – Solid- -State isks), estão ganhando mais popularidade como uma alternativa de alta velocidade às tecnologias tradicio- nais em disco magnético. A invenção do SSD é uma história clássica de “Quando lhe oferecem limões, faça uma limonada”. Embora a eletrônica moderna possa parecer totalmente confiável, a realidade é que os transistores se desgastam lentamente à medida que são usados. Toda vez que eles comutam, se desgastam um pouco e ficam mais perto de não funcionarem mais. Um modo provável de falha de um transistor é pela “injeção de portadora quente”, um mecanismo de falha em que uma carga elétrica é embutida dentro de um transistor que funcionava, deixando-o em um estado onde fica permanentemente ligado ou desligado. Embora em geral considerado senten- ça de morte para um transistor (provavelmente) inocente, Fujio Masuoka, enquanto trabalhava para a Toshiba, descobriu um modo de aproveitar esse mecanismo de falha para criar uma nova memória não volátil. No início da década de 1980, ele inventou a primeira memória flash. Os discos flash são compostos de muitas células de memória flash em estado sólido. As células da memó- ria flash são feitas de um único transistor flash especial. Uma célula de memória flash aparece na Figura 2.24. Embutido no transistor há uma porta flutuante que pode ser carregada e descarregada usando altas voltagens.
  • 96. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 77 Antes de ser programada, a porta flutuante não afeta a operação do transistor, atuando como um isolador extra entre a porta de controle e o canal do transistor. Se a célula flash for testada, ela atuará como um transistor simples. Figura 2.24 Uma ce lula de memo ria flash. 12 V Tensão de programação Porta de controle Isolador Porta flutuante Isolador Carga negativa interceptada Ponta de teste Origem Canal Dreno Semicondutor Terra Para programar uma célula de bit flash, uma alta tensão (no mundo dos computadores, 12  é uma alta tensão) é aplicada à porta de controle, que acelera o processo de injeção de portadora quente na porta flutuante. Os elétrons são embutidos na porta flutuante, que coloca uma carga negativa interna no transistor flash. A carga negativa embutida aumenta a tensão necessária para ligar o transistor flash e, testando se o canal liga ou não com uma tensão alta ou baixa, é possível determinar se a porta flutuante está carregada ou não, resultando em um valor 0 ou 1 para a célula flash. A carga embutida permanece no transistor, mesmo que o sistema perca a alimentação, tornando a célula de memória flash não volátil. isto que os SSDs são basicamente memória, eles possuem desempenho superior aos discos giratórios, com tempo de busca zero. Enquanto um disco magnético típico pode acessar dados em até 100 MB/s, um SSD pode operar duas a três vezes mais rápido. E como o dispositivo não possui partes móveis, ele é muito adequado para uso em notebooks, onde trepidações e movimentos não afetarão sua capacidade de acessar dados. A desvantagem dos SSDs, em comparação com discos magnéticos, é o seu custo. Enquanto os discos magnéticos custam centa- vos de dólar por gigabyte, um SSD típico custará de um a três dólares por gigabyte, tornando seu uso apropriado apenas para aplicações com drive menor ou em situações em que o custo não é um problema. O custo dos SSDs está caindo, mas ainda há um longo caminho até que alcancem os discos magnéticos baratos. Assim, embora os SSDs estejam substituindo os discos magnéticos em muitos computadores, talvez ainda leve um bom tempo antes que o disco magnético siga o caminho dos dinossauros (a menos que outro grande meteoro atinja a Terra, mas nesse caso nem os SSDs sobreviveriam).
  • 97. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 78 Outra desvantagem dos SSDs em comparação com os discos magnéticos é sua taxa de falha. Uma célula flash típica pode ser escrita somente por cerca de 100 mil vezes antes que não funcione mais. O processo de injetar elé- trons na porta flutuante a danifica aos poucos, bem como seus isoladores ao redor, até que não funcione mais. Para aumentar o tempo de vida dos SSDs, é usada uma técnica denominada nivelamento de desgaste, para espalhar as escritas por todas as células flash no disco. Toda vez que um novo bloco de disco é escrito, o bloco de destino é rea- tribuído a um novo bloco do SSD, que não foi escrito recentemente. sso exige o uso de um mapa de blocos lógicos dentro do drive flash, que é um dos motivos pelos quais os drives flash possuem altos overheads de armazenamento interno. Usando o nivelamento de desgaste, um drive flash pode dar suporte a uma quantidade de escritas igual ao número de escritas que uma célula pode sustentar multiplicado pelo número de blocos no disco. Alguns SSDs são capazes de codificar vários bits por byte, usando células flash multiníveis. A tecnologia controla cuidadosamente a quantidade de carga colocada na porta flutuante. Uma sequência cada vez maior de voltagens é então aplicada à porta de controle para determinar quanta carga é armazenada na flutuante. As células multiníveis típicas admitem quatro níveis de carga, resultando em dois bits por célula flash. 2.3.7 CD-ROMs Discos ópticos foram desenvolvidos na origem para gravar programas e televisão, mas podem ser utilizados para uma função mais estética como dispositivos de armazenagem de computadores. Por sua grande capacidade e baixo preço, discos óticos são muito usados para distribuir software, livros, filmes e dados de todos os tipos, bem como para fazer backup de discos rígidos. A primeira geração de discos óticos foi inventada pela Philips, conglomerado holandês de eletrônica, para conter filmes. Tinham 30 cm de diâmetro e eram comercializados com a marca Laserision, mas não se estabe- leceram, exceto no Japão. Em 1980, a Philips, junto com a Sony, desenvolveu o CD (Compact Disc), que logo substituiu os discos de vinil de 33 1/3 RPM usados para gravar música. Os dados técnicos exatos do CD foram publicados em um Padrão nternacional (S 10149), popularmente conhecido como Red Book (livro vermelho) por causa da cor de sua capa. (Padrões nternacionais são emitidos pela nternational Organization for Standardization, que é a contraparte internacional de grupos de padronização nacionais como ABNT, ANS etc. Cada um tem um número S.) O motivo da publicação das especificações do disco e do drive como um Padrão nternacional é permitir que CDs de diferentes gravadoras e aparelhos de reprodução de diferentes fabricantes funcionem em conjunto. Todos os CDs têm 120 mm de diâmetro 1,2 mm de espessura, com um orifício de 15 mm no meio. O CD de áudio foi o primeiro meio de armazenagem digital a ter sucesso no mercado de massa. Supõe-se que devam durar cem anos. Favor verificar em 2080 um relatório sobre como se saiu o primeiro lote. Um CD é preparado com a utilização de um laser infravermelho de alta potência para queimar orifícios de 0,8 mícron de diâmetro em um disco mestre revestido de vidro. Com base nesse mestre é fabricado um molde, com saliências onde estavam os orifícios de laser. Então, injeta-se policarbonato fundido nesse molde para for- mar um CD com o mesmo padrão de orifícios do disco mestre revestido de vidro. Em seguida, é depositada uma fina camada de alumínio refletivo sobre o policarbonato, coberta por um verniz de proteção e, por fim, vem uma etiqueta. As marcas no substrato de policarbonato são denominadas depressões (pits) e as áreas entre elas são denominadas planos (lands). Quando o disco é tocado, um diodo a laser de baixa potência emite luz infravermelha de comprimento de onda de 0,78 mícron sobre as depressões e planos quando estes passam pela luz. O laser está no lado do policarbo- nato, portanto, as depressões estão invertidas na direção do laser e aparecem como saliências sobre uma superfície que, caso contrário, seria plana. Como as depressões têm uma altura de um quarto do comprimento de onda da luz de laser, a luz que se reflete de uma depressão tem uma defasagem de meio comprimento de onda em relação à que se reflete das superfícies que a circundam. O resultado é que as duas partes interferem uma com a outra de modo destrutivo e devolvem menos luz ao fotodetector do aparelho de reprodução do que a luz que se reflete de um plano. É assim que o aparelho distingue uma depressão de um plano. Embora talvez pareça mais simples
  • 98. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 79 usar uma depressão para gravar um 0 e um plano para gravar um 1, é mais confiável usar uma transição depressão/ plano ou plano/depressão para um 1 e sua ausência para um 0; portanto, esse é o esquema usado. As depressões e os planos são escritos em uma única espiral contínua que começa perto do orifício central e continua por uma distância de 32 mm em direção à borda. A espiral faz 22.188 rotações ao redor do disco (cerca de 600 por mm). Se fosse desenrolada, teria 5,6 km de comprimento. A espiral é ilustrada na Figura 2.25. Figura 2.25 Estrutura de gravac a o de um disco compacto ou CD-ROM. Sulco em espiral Bloco de 2 K de dados de usuário Depressão Plano Para fazer a música ser tocada a uma taxa uniforme, é preciso que as depressões e os planos passem sob a luz a uma velocidade linear constante. Em consequência, a taxa de rotação deve ser continuamente reduzida à medida que o cabeçote de leitura se move da parte interna para a externa do CD. Na parte interna, a taxa de rotação é de 530 RPM para conseguir a taxa de reprodução regular de 120 cm/s; na parte mais externa, tem de cair para 200 RPM para dar a mesma velocidade linear no cabeçote. Um drive de velocidade linear constante é bem diferente de um drive de disco magnético, que funciona a uma velocidade angular constan- te, independente de onde o cabeçote esteja posicionado naquele momento. Além disso, 530 RPM estão bem longe das 3.600 a 7.200 RPM com as quais gira a maioria dos discos magnéticos. Em 1984, a Philips e a Sony perceberam o potencial para usar CDs como meio de armazenagem de dados de computadores, então, publicaram o Yellow Book (livro amarelo) definindo um padrão exato para o que agora conhecemos como C-ROMs (Compact isc-Read Only Memory  disco compacto com memória somente de leitura). Para pegar carona no mercado de CDs de áudio, que já era substancial na época, os CD-ROMs tinham o mesmo tamanho físico dos CDs de áudio, guardavam compatibilidade mecânica e ótica com eles e eram produzi- dos usando as mesmas máquinas de moldagem por injeção. As consequências dessa decisão foram a necessidade de motores lentos de velocidade variável mas também que o custo de manufatura de um CD-ROM estivesse bem abaixo de um dólar para um volume moderado. O Yellow Book definiu a formatação dos dados de computador. Também melhorou as capacidades de cor- reção de erro do sistema, um passo essencial porque, embora os apreciadores de música não se importassem em perder um bit aqui, outro ali, os apreciadores de computadores tendiam a ser muito exigentes com isso. O formato básico de um CD-ROM consiste em codificar cada byte em um símbolo de 14 bits. Como já vimos, 14 bits são suficientes para codificar com Hamming um byte de 8 bits e ainda sobram 2. Na verdade, é usado um sistema de codificação mais poderoso. O mapeamento 14 para 8 para leitura é realizado em hardware por consulta de tabela. Do nível seguinte para cima, um grupo de 42 símbolos consecutivos forma um quadro de 588 bits. Cada quadro contém 192 bits de dados (24 bytes). Os 396 bits restantes são usados para correção e controle de erro. Até aqui, esse esquema é idêntico para CDs e CD-ROMs.
  • 99. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 80 O que o Yellow Book acrescenta é o agrupamento de 98 quadros em um setor de C-ROM, conforme mostra a Figura 2.26. Cada setor de CD-ROM começa com um preâmbulo de 16 bytes, sendo os 12 primeiros 00FFFFFFFFFFFFFFFFFFFF00 (hexadecimal), para permitir que o aparelho de reprodução reconheça o início de um setor de CD-ROM. Os 3 bytes seguintes contêm o número do setor, necessário porque fazer busca em um CD-ROM com sua única espiral de dados é muito mais difícil do que em um disco magnético com suas trilhas concêntricas uniformes. Para buscar, o software no drive calcula mais ou menos aonde ir, leva o cabeçote até lá e então começa a procurar um preâmbulo para verificar a precisão do cálculo. O último bit do preâmbulo é o modo. Figura 2.26 Layout lo gico de dados em um CD-ROM. … … Símbolos de 14 bits cada 42 símbolos formam 1 quadro Quadros de 588 bits, cada um contendo 24 bytes de dados Preâmbulo 98 quadros formam 1 setor Dados ECC Bytes 16 2.048 288 Setor do modo 1 (2.352 bytes) O Yellow Book define dois modos. O modo 1 usa o layout da Figura 2.26, com um preâmbulo de 16 bytes, 2.048 bytes de dados e um código de correção de erro de 288 bytes (um código de Reed-Solomon de intercalação cruzada). O modo 2 combina os dados e campos ECC em um campo de dados de 2.336 bytes para as aplicações que não precisam de correção de erro (ou não dispõem de tempo para executá-la), como áudio e vídeo. Note que, para oferecer excelente confiabilidade, são usados três esquemas separados de correção de erros: dentro de um símbolo, dentro de um quadro e dentro de um setor de CD-ROM. Erros de único bit são corrigidos no nível mais baixo, erros em rajada curtos são corrigidos no nível de quadro e quaisquer erros residuais são apanhados no nível de setor. O preço pago por essa confiabilidade é que são necessários 98 quadros de 588 bits (7.203 bytes) para transportar uma única carga útil de 2.048 bytes, uma eficiência de apenas 28%. Drives de CD-ROM de uma velocidade operam a 75 setores/s, o que dá uma taxa de dados de 153.600 bytes/s em modo 1 e 175.200 bytes/s em modo 2. Drives de dupla velocidade são duas vezes mais rápidos e assim por diante, até a velocidade mais alta. Um CD padrão de áudio tem espaço para 74 minutos de música que, se usado para dados do modo 1, dá uma capacidade de 681.984.000 bytes. Esse número costuma ser informado como 650 MB, pois 1 MB é igual a 220 bytes (1.048.576 bytes), e não 1 milhão de bytes. Como é muito comum, sempre que surge uma nova tecnologia, algumas pessoas tentam desafiar os limites. Ao projetar o CD-ROM, a Philips e a Sony foram cuidadosas e fizeram o processo de escrita parar bem antes que a borda externa do disco fosse alcançada. Não levou muito tempo para que alguns fabricantes permitissem que seus drives fossem além do limite oficial e chegassem perigosamente perto da borda física da mídia, gerando cerca de 700 MB em vez de 650 MB. Porém, quando a tecnologia foi aperfeiçoada e os discos vazios foram fabricados com um padrão mais alto, 703,12 MB (360 mil setores de 2.048 bytes, em vez de 333 mil setores) se tornaram a nova norma.
  • 100. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 81 Note que mesmo um drive de CD-ROM 32x (4.915.200 bytes/s) não é páreo para o drive de disco magnético Fast SCS-2 a 10 MB/s. Quando você se der conta de que o tempo de busca muitas vezes é de várias centenas de milissegundos, deve ficar claro que os drives de CD-ROM não estão de forma alguma na mesma categoria de desempenho dos drives de disco magnético, a despeito de sua grande capacidade. Em 1986, a Philips atacou mais uma vez com o Green Book (livro verde), acrescentando recursos gráficos e a capacidade de intercalar áudio, vídeo e dados no mesmo setor, uma característica essencial para CD-ROMs multimídia. A última peça do quebra-cabeça do CD-ROM é o sistema de arquivos. Para possibilitar a utilização do mesmo CD-ROM em diferentes computadores, era preciso chegar a um acordo quanto aos sistemas de arquivos em CD-ROM. Para conseguir esse acordo, representantes de muitas empresas fabricantes de com- putadores se reuniram em Lake Tahoe, nas High Sierras, na fronteira Califórnia-Nevada, e arquitetaram um sistema de arquivos que denominaram High Sierra. Mais tarde, ele evoluiu para um Padrão nternacional (S 9660). O sistema tem três níveis. O nível 1 usa nomes de arquivo de até 8 caracteres e podem ser seguidos de uma extensão de até 3 caracteres (a convenção de nomeação de arquivos do MS-DOS). Nomes de arquivos só podem conter letras maiúsculas, dígitos e o caractere de sublinhado. Diretórios podem ser aninhados até oito, mas nomes de diretórios não podem conter extensões. O nível 1 requer que todos os arquivos sejam contíguos, o que não é problema para um meio que é escrito apenas uma vez. Qualquer CD-ROM que obe- deça ao S 9660 nível 1 pode ser lido usando MS-DOS, um computador Apple, um computador UN ou praticamente qualquer outro computador. Os fabricantes de CD-ROMs consideram essa propriedade uma grande vantagem. O S 9660 nível 2 permite nomes de até 32 caracteres e o nível 3 permite arquivos não contíguos. As exten- sões Rock Ridge (o nome extravagante se deve à cidade em que Mel Brooks filmou Blazing Saddles [Banzé no Oeste]) permitem nomes muito longos (para UN), UDs, GDs, e enlaces simbólicos, mas os CD-ROMs que não obedecem ao nível 1 não poderão ser lidos em todos os computadores. 2.3.8 CDs grava veis De início, o equipamento necessário para produzir um CD-ROM mestre (ou CD de áudio, por falar nisso) era muito dispendioso. Mas, como sempre acontece na indústria de computadores, nada permanece caro por muito tempo. Em meados da década de 1990, gravadores de CD não maiores do que um reprodutor de CD eram um periférico comum disponível na maioria das lojas de computadores. Esses dispositivos ainda eram diferentes dos discos magnéticos porque, uma vez gravados, os CD-ROMs não podiam ser apagados. Ainda assim, eles logo encontraram um nicho como um meio de backup para grandes discos rígidos magnéticos e também permitiram que indivíduos ou novas empresas fabricassem seus próprios CD-ROMs em pequena escala ou produzissem mes- tres para fornecer a empresas comerciais de reprodução de grandes volumes de CDs. Esses drives são conhecidos como C-Rs (C-Recordables  Cs graváveis). Os CD-Rs começaram com discos em branco de policarbonato de 120 mm de diâmetro que são como CD-ROMs, exceto por conterem um sulco de 0,6 mm de largura para guiar o laser durante a escrita (gravação). O sulco tem um desvio senoidal de 0,3 mm a uma frequência de exatos 22,05 kHz para prover realimentação contí- nua, de modo que a rotação possa ser monitorada e ajustada com precisão, caso necessário. Os primeiros CD-Rs pareciam CD-ROMs normais, exceto por terem a superfície superior dourada, e não prateada. Essa cor vinha da utilização de ouro verdadeiro em vez de alumínio na camada refletiva. Diferente dos CDs prateados que conti- nham depressões físicas, nos CD-Rs as diferentes refletividades das depressões e dos planos têm de ser simuladas. sso é feito com a adição de uma camada de corante entre o policarbonato e a superfície refletiva, como mostra a Figura 2.27. São usadas duas espécies de corantes: cianina, que é verde, e ftalocianina, que é amarelo-alaranjada. Os químicos podem discutir eternamente sobre qual das duas é melhor. Com o tempo, a camada refletiva dourada foi substituída por uma camada de alumínio.
  • 101. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 82 Figura 2.27 Sec a o transversal de um disco CD-R e laser (na o esta  em escala). Um CD-ROM tem estrutura semelhante, exceto por na o ter a camada de corante e por ter uma camada de alum nio cheia de depresso es em vez de uma camada refletiva. Etiqueta impressa Verniz protetor Camada refletiva Ponto escuro na camada de corante queimado pelo laser durante a escrita Camada de corante Policarbonato Substrato Direção de movimento Lente Fotodetector Prisma Diodo de laser infravermelho Em seu estágio inicial, a camada de corante é transparente e permite que a luz do laser que a atravessa seja refletida pela camada refletiva. Para gravar (escrever), o laser CD-R é ligado em alta potência (8–16 mW). Quando o feixe atinge uma porção do corante, ele o aquece e rompe a ligação química. Essa alteração da estrutura mole- cular cria um ponto escuro. Quando o CD-R é lido (a 0,5 mW), o fotodetector vê uma diferença entre os pontos escuros onde o corante foi atingido e as áreas transparentes onde o disco está intacto. Essa diferença é interpretada como a diferença entre depressões e planos, mesmo quando lidas por um leitor de CD-ROM normal ou até mesmo por um reprodutor de CD de áudio. Nenhum tipo novo de CD poderia se firmar com orgulho sem ter um livro colorido, portanto, o CD-R tem o Orange Book (livro laranja), publicado em 1989. Esse documento define o CD-R e também um novo formato, o C-ROM X, que permite que os CD-Rs sejam gravados por incrementos, alguns setores hoje, outros amanhã e mais alguns no próximo mês. Um grupo de setores consecutivos escritos de uma só vez é denominado trilha de C-ROM. Um dos primeiros usos do CD-R foi no PhotoCD da Kodak. Nesse sistema, o cliente leva ao processador de fotos um rolo de filme exposto e seu velho PhotoCD, e recebe de volta o mesmo PhotoCD com novas fotos acrescentadas às antigas. O novo lote, que é criado por digitalização dos negativos, é gravado no PhotoCD como uma trilha de CD-ROM separada. A gravação incremental é necessária porque os CD-Rs virgens são muito caros para se ter um novo para cada rolo de filme. Contudo, a gravação incremental cria um novo problema. Antes do Orange Book, todos os CD-ROMs tinham, no início, uma única VOC (Volume able of Contents – sumário de conteúdo de volumes). Esse esquema não funciona com escritas incrementais (isto é, multitrilhas). A solução do Orange Book é dar a cada trilha de CD-ROM sua própria TOC. Os arquivos listados na TOC podem incluir alguns ou todos os arquivos de trilhas anteriores. Após a inserção do CD-R no drive, o sistema operacional faz uma busca em todas as trilhas do CD-ROM para localizar a TOC mais recente, que dá o estado atual do disco. Por incluir alguns, mas não todos os arquivos de trilhas anteriores na TOC corrente, é possível dar uma ilusão de que os arquivos foram apagados. As trilhas podem ser agrupadas em sessões, o que resulta em CD-ROMs multissessões. Reprodutores de CD de áudio padrão não podem manipular CDs multissessões, já que esperam uma única TOC no início. 1,2 mm
  • 102. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 83 O CD-R possibilita que indivíduos e empresas copiem CD-ROMs (e CDs de áudio) com facilidade, em geral com a violação dos direitos autorais do editor. ários esquemas já foram inventados para dificultar esse tipo de pirataria e também a leitura de um CD-ROM usando qualquer outra coisa que não seja o software do editor. Um deles envolve gravar todos os comprimentos de arquivos do CD-ROM como multigigabyte, frustrando quaisquer tentativas de copiar os arquivos para disco rígido com a utilização de software de cópia padrão. Os verdadeiros comprimentos estão embutidos no software do editor ou ocultos (possivelmente criptografados) no CD-ROM em um lugar não esperado. Outro esquema usa intencionalmente ECCs incorretos em setores selecionados, na esperança de que o software de cópia de CDs “corrija” os erros. O software de aplicação verifica os ECCs e se recusa a funcionar se estiverem “corri- gidos”. Usar lacunas não padronizadas entre trilhas e outros “defeitos” físicos também são possibilidades. 2.3.9 CDs regrava veis Embora todos estejam acostumados com outras mídias que aceitam apenas uma escrita, como papel fotográfico, existe uma demanda por CD-ROMs regraváveis. Uma tecnologia disponível agora é o C-RW (C-ReWritable  Cs regraváveis), que usa um meio do mesmo tamanho do CD-R. Contudo, em vez dos corantes cianina ou ftalocianina, o CD-RW usa uma liga de prata, índio, antimônio e telúrio para a camada de gravação. Essa liga tem dois estados estáveis: cristalino e amorfo, com diferentes refletividades. Os drives de CD-RW usam lasers com três potências diferentes. Em alta potência, o laser funde a liga fazendo- -a passar do estado cristalino de alta refletividade para o estado amorfo de baixa refletividade, para representar uma depressão. Em potência média, a liga se funde e volta a seu estado natural cristalino para se tornar novamente um plano. Em baixa potência, o estado do material é sondado (para leitura), mas não ocorre qualquer transição de fase. A razão por que o CD-RW não substituiu completamente o CD-R é que os CD-RWs em branco são mais caros do que os CD-Rs em branco. Além disso, para aplicações de backup de discos rígidos, o fato de que, uma vez escrito, o CD não possa ser apagado acidentalmente, é uma grande vantagem, e não um bug. 2.3.10 DVD O formato básico do CD/CD-ROM está na praça desde 1980. Em meados da década de 1990, a tecnologia melhorou bastante, de modo que discos ópticos de capacidade mais alta se tornaram economicamente viáveis. Ao mesmo tempo, Hollywood estava procurando um meio de substituir as fitas analógicas de videoteipe por discos digitais, pois estes têm qualidade mais alta, são mais baratos de fabricar, duram mais, ocupam menos espaço nas prateleiras das locadoras de vídeo e não precisam ser rebobinados. Estava parecendo que a roda do progresso para os discos óticos estava para girar mais uma vez. Essa combinação de tecnologia e demanda por três indústrias imensamente ricas e poderosas resultou no V, na origem um acrônimo para igital Video isk (disco de vídeo digital), mas agora oficialmente igital Versatile isk (disco versátil digital). DDs usam o mesmo desenho geral dos CDs, com discos de policarbonato de 120 mm moldados por injeção que contêm depressões e planos iluminados por um diodo de laser e lidos por um fotodetector. A novidade é o uso de 1. Depressões menores (0,4 mícron versus 0,8 mícron para CDs). 2. Uma espiral mais apertada (0,74 mícron entre trilhas versus 1,6 mícron para CDs). 3. Um laser vermelho (a 0,65 mícron versus 0,78 mícron para CDs). Juntas, essas melhorias aumentam sete vezes a capacidade, passando para 4,7 GB. Um drive de DD 1x funciona a 1,4 MB/s (versus 150 KB/s para CDs). nfelizmente, a troca para lasers vermelhos usados em supermer- cados significa que os reprodutores de DD precisarão de um segundo laser para poder ler os CDs e CD-ROMs existentes, aumentando um pouco de complexidade e custo.
  • 103. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 84 Uma capacidade de 4,7 GB é suficiente? Talvez. Usando compressão MPEG-2 (padronizada no S 13346), um disco DD de 4,7 GB pode conter 133 minutos de vídeo de tela cheia com imagens em movimento em alta resolução (720 × 480), bem como trilhas sonoras em até oito idiomas e legendas em mais 32. Cerca de 92% de todos os filmes que Hollywood já produziu têm menos de 133 minutos. Não obstante, algumas aplicações, como jogos multimídia ou obras de referência, talvez precisem mais, e Hollywood gostaria de gravar vários filmes em um mesmo disco, portanto, quatro formatos foram definidos: 1. Uma face, uma camada (4,7 GB). 2. Uma face, duas camadas (8,5 GB). 3. Duas faces, uma camada (9,4 GB). 4. Duas faces, duas camadas (17 GB). Por que tantos formatos? Em uma palavra: política. A Philips e a Sony queriam discos de uma única face com duas camadas para a versão de alta capacidade, mas a Toshiba e a Time Warner queriam discos de duas faces, com uma camada. A Philips e a Sony não imaginaram que as pessoas estariam dispostas a virar os discos, e a Time Warner não acreditava que colocar duas camadas em uma face poderia funcionar. A solução de conciliação: todas as combinações, mas o mercado determinará quais sobreviverão. Bem, o mercado falou. A Philips e a Sony estavam certas. Nunca aposte contra a tecnologia. A tecnologia da camada dupla tem uma camada refletiva embaixo, coberta por uma semirrefletiva. Dependendo de onde o laser for focalizado, ele se reflete de uma camada ou da outra. A camada inferior precisa de depressões e planos um pouco maiores, para leitura confiável, portanto, sua capacidade é um pouco menor do que a da superior. Discos de dupla face são fabricados colando dois discos de uma face de 0,6 mm. Para que todas as versões tenham a mesma espessura, um disco de uma face consiste em um disco de 0,6 mm colado a um substrato em branco (ou, talvez, no futuro, contendo 133 minutos de propaganda, na esperança de que as pessoas ficarão curio- sas de saber o que existe lá dentro). A estrutura do disco de dupla face, dupla camada, é ilustrada na Figura 2.28. Figura 2.28 Disco de DVD de dupla face, dupla camada. Camada semirrefletiva Refletor de alumínio Refletor de alumínio Camada semirrefletiva Disco de uma face de 0,6 mm Disco de uma face de 0,6 mm Substrato de policarbonato 1 Camada adesiva Substrato de policarbonato 2 O DD foi arquitetado por um consórcio de dez fabricantes de eletrônicos de consumo, sete deles japone- ses, em estreita colaboração com os principais estúdios de Hollywood (alguns dos quais são de propriedade dos fabricantes de eletrônicos japoneses pertencentes ao consórcio). As empresas de computadores e telecomunica- ções não foram convidadas para o piquenique e o foco resultante foi o uso do DD para locação de filmes. Por exemplo, entre as características padrão está a capacidade de saltar cenas impróprias em tempo real (o que per- mite que os pais transformem um filme proibido para menores de 18 anos em um filme que possa ser visto por criancinhas), seis canais de som e suporte para Pan-and-Scan. Essa última característica permite que o tocador de DD decida dinamicamente como recortar as extremidades direita e esquerda dos filmes (cuja relação largura/ altura é 3:2) para que se ajustem aos tamanhos das telas de aparelhos de televisão atuais (cuja relação é 4:3).
  • 104. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 85 Outro item em que a indústria de computadores provavelmente não teria pensado é uma incompatibilidade intencional entre discos destinados aos Estados Unidos e discos destinados à Europa, e ainda outros padrões para outros continentes. Hollywood exigiu essa “característica” porque filmes novos são sempre lançados antes nos Estados Unidos e então despachados para a Europa quando os vídeos começam a sair do circuito comercial nos Estados Unidos. A ideia era garantir que as locadoras de vídeo não pudessem comprar vídeos nos Estados Unidos muito cedo, o que reduziria as receitas de filmes novos nos cinemas da Europa. Se Hollywood estivesse no con- trole na indústria de computadores, teríamos disquetes de 3,5 polegadas nos Estados Unidos e disquetes de 9 cm na Europa. 2.3.11 Blu-ray Nada fica parado no negócio de computadores, certamente não na tecnologia de armazenagem. O DD mal acabara de ser lançado e seu sucessor já ameaçava torná-lo obsoleto. O sucessor do DD é o Blu-ray (raio azul), assim chamado porque usa um laser azul, em vez do vermelho usado por DDs. Um laser azul tem comprimento de onda mais curto do que o laser vermelho, o que permite um foco mais preciso e, portanto, depressões e pla- nos menores. Discos Blu-ray de uma face contêm cerca de 25 GB de dados; os de dupla face contêm cerca de 50 GB. A taxa de dados é mais ou menos 4,5 MB/s, o que é bom para um disco óptico, mas ainda insignificante em comparação com discos magnéticos (cf. ATAP-6 a 100 MB/s e wide Ultra5 SCS a 640 MB/s). Espera-se que, com o tempo, o Blu-ray substitua CD-ROMs e DDs, mas essa transição ainda levará alguns anos. 2.4 Entrada/Sa da Como mencionamos no início deste capítulo, um sistema de computador tem três componentes principais: a CPU, as memórias (primária e secundária) e os equipamentos de E/S (entrada/saída), ou I/O (nput/Output), como impressoras, scanners e modems. Até aqui, só examinamos CPU e as memórias. Agora, é hora de examinar os equipamentos de E/S e como eles estão conectados ao restante do sistema. 2.4.1 Barramentos A maioria dos computadores pessoais e estações de trabalho tem uma estrutura semelhante à mostrada na Figura 2.29. O arranjo comum é um gabinete de metal que contém uma grande placa de circuito impresso na parte inferior, denominada placa-mãe (ou placa-pai, para os que preferirem). A placa-mãe contém o chip da CPU, alguns encaixes para os módulos DMM e vários chips de suporte. Contém também um barramento ao longo do comprimento e soquetes nos quais os conectores de borda das placas de E/S podem ser inseridos. Figura 2.29 Estrutura f sica de um computador pessoal. Controlador SCSI Placa de som Modem Gabinete Conector de borda
  • 105. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 86 A estrutura lógica de um computador pessoal simples pode ser vista na Figura 2.30. Esse computador tem um único barramento para conectar a CPU, a memória e os equipamentos de E/S; a maioria dos sistemas tem dois ou mais barramentos. Cada dispositivo de E/S consiste em duas partes: uma que contém grande parte da eletrônica, denominada controlador, outra que contém o dispositivo de E/S em si, tal como um drive de disco. O controlador está em geral contido em uma placa que é ligada a um encaixe livre. Mesmo o monitor não sendo opcional, o con- trolador de vídeo às vezes está localizado em uma placa de encaixe (plug-in) para permitir que o usuário escolha entre placas com ou sem aceleradores gráficos, memória extra e assim por diante. O controlador se conecta com seu dispositivo por um cabo ligado ao conector na parte de trás do gabinete. Figura 2.30 Estrutura lo gica de um computador pessoal simples. Monitor Teclado Drive de CD-ROM Drive de disco rígido CPU Memória Controlador de vídeo Controlador de teclado Controlador de CD-ROM Controlador de disco rígido Barramento A função de um controlador é controlar seu dispositivo de E/S e manipular para ele o acesso ao barramento. Quando um programa quer dados do disco, por exemplo, ele envia um comando ao controlador de disco, que então emite comandos de busca e outros comandos para o drive. Quando a trilha e o setor adequados forem loca- lizados, o drive começa a entregar dados ao controlador como um fluxo serial de bits. É função do controlador dividir o fluxo de bits em unidades e escrever cada uma delas na memória, à medida que seja montada. Uma unidade típica é composta de uma ou mais palavras. Quando um controlador lê ou escreve dados de ou para a memória sem intervenção da CPU, diz-se que ele está executando acesso direto à memória (irect Memory ccess), mais conhecido por seu acrônimo M. Concluída a transferência, o controlador normalmente causa uma interrupção, forçando a CPU a suspender de imediato o programa em execução e começar a rodar um proce- dimento especial, denominado rotina de interrupção, para verificar erros, executar qualquer ação especial neces- sária e informar ao sistema operacional que a E/S agora está concluída. Quando a rotina de interrupção conclui sua tarefa, a CPU continua com o programa que foi suspenso quando ocorreu a interrupção. O barramento não é usado apenas pelos controladores de E/S, mas também pela CPU para buscar instruções e dados. O que acontece se a CPU e um controlador de E/S quiserem usar barramento ao mesmo tempo? A res- posta é que um chip, denominado árbitro de barramento, decide o que acontece em seguida. Em geral, é dada a preferência aos dispositivos de E/S sobre a CPU, porque discos e outros dispositivos que estão em movimento não podem ser interrompidos, e obrigá-los a esperar resultaria em perda de dados. Quando não há nenhuma E/S em curso, a CPU pode ficar com todos os ciclos do barramento para si própria, para referenciar a memória. Contudo, quando algum dispositivo de E/S também estiver executando, ele requisitará e terá acesso ao barramento sempre que precisar. Esse processo é denominado roubo de ciclo, e reduz a velocidade do computador. Esse projeto funcionou bem para os primeiros computadores pessoais, já que todos os componentes estavam em certo equilíbrio. Contudo, à medida que CPUs, memórias e dispositivos de E/S ficavam mais rápidos, surgiu um problema: o barramento não dava mais conta da carga apresentada. Em um sistema fechado, tal como uma estação de trabalho de engenharia, a solução foi projetar um novo barramento mais rápido para o próximo modelo.
  • 106. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 87 Como ninguém nunca passava dispositivos de E/S de um modelo antigo para um novo, essa abordagem funcionou bem. Todavia, no mundo do PC, quem passava para uma CPU mais potente muitas vezes queria levar sua impres- sora, scanner e modem para o novo sistema. Além disso, tinha-se desenvolvido uma imensa indústria destinada a fornecer uma ampla gama de dispositivos de E/S para o barramento do BM PC, e essa indústria não estava nem um pouco interessada em perder todo seu investimento e começar de novo. A BM aprendeu isso do modo mais difícil quando lançou o sucessor do BM PC, a linha PS/2. O PS/2 tinha um barramento novo e mais rápido, mas a maioria dos fabricantes de clones continuava a usar o antigo barramento do PC, agora denominado barramento IS (Industry Standard rchitecture). A maioria dos fabricantes de discos e dispositivos de E/S continuou a fabricar controladores para ele, e a BM se viu enfrentando a peculiar situação de ser a única fabricante de PCs que não eram mais compatíveis com o PC da BM. Com o tempo, a empresa foi forçada a dar suporte ao barra- mento SA. Hoje, o barramento SA é usado em sistemas legados e em museus de computador, pois foi substitu- ído por arquiteturas de barramento padrão mais novas e mais rápidas. Como um comentário à parte, favor notar que SA quer dizer nstruction Set Architecture (arquitetura do conjunto de instruções) no contexto de níveis de máquina, ao passo que no contexto de barramentos quer dizer ndustry Standard Architecture (arquitetura padrão da indústria). Os barramentos PCI e PCIe Não obstante, a despeito da pressão do mercado para que nada mudasse, o antigo barramento era mesmo muito lento, portanto, era preciso fazer algo. Essa situação levou outras empresas a desenvolver máquinas com múltiplos barramentos, um dos quais era o antigo barramento SA, ou seu sucessor compatível, o EIS (Extended IS  IS estendido). Agora, o mais popular deles é o barramento PCI (Peripheral Component Interconnect  interconexão de componentes periféricos). Esse barramento foi projetado pela ntel, mas a empresa decidiu passar todas as patentes para domínio público, a fim de incentivar toda a indústria (incluindo seus concorrentes) a adotá-lo. O barramento PC pode ser usado em muitas configurações, mas a Figura 2.31 ilustra uma configuração típica. Nesse caso, a CPU se comunica com um controlador de memória por meio de uma conexão dedicada, de alta velocidade. O controlador se comunica diretamente com a memória e com o barramento PC, de modo que o tráfego CPU-memória não passa pelo barramento PC. Outros periféricos podem ser conectados diretamente ao barramento PC. Uma máquina com esse projeto teria dois ou três conectores PC vazios, permitindo que os clientes conectem placas de E/S PC para novos periféricos. Qualquer que seja a velocidade de algo no mundo da computação, muita gente acha que ela é baixa. Esse destino também caiu sobre o barramento PC, que está sendo substituído pelo PCI Express, abreviado como PCIe. A maior parte dos computadores modernos tem suporte para ele, de modo que os usuários podem conectar dispositivos novos e velozes ao barramento PCe e os mais antigos e mais lentos ao barramento PC. Figura 2.31 PC t pico montado em torno do barramento PCI. O controlador SCSI e  um dispositivo PCI. cache CPU Cache Ponte para PCI Barramento PCI Controlador de rede Controlador de vídeo Controlador SCSI Disco SCSI Scanner SCSI Barramento SCSI Memória principal Barramento de memória
  • 107. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 88 Enquanto o barramento PC foi apenas uma atualização para o SA mais antigo, com velocidades mais altas e mais bits transferidos em paralelo, o PCe representa uma mudança radical do PC. Na verdade, ele sequer é um barramento. É uma rede ponto a ponto usando linhas de bits seriais e troca de pacotes, mais parecido com a nternet do que com um barramento tradicional. Sua arquitetura aparece na Figura 2.32. Figura 2.32 Exemplo de arquitetura de um sistema PCIe com tre s portas PCIe. CPU Cache Memória Complexo raiz Porta 1 Porta 2 Porta 3 Dispositivo PCIe Switch Dispositivo PCIe Ponte para PCI Barramento PCI Dispositivo PCIe Dispositivo PCIe Dispositivo PCIe Dispositivo PCIe árias coisas se destacam de imediato sobre o PCe. Primeiro, as conexões entre os dispositivos são seriais, ou seja, 1 bit de largura em vez de 8, 16, 32 ou 64 bits. Embora se possa pensar que uma conexão de 64 bits teria uma largura de banda mais alta do que uma conexão de 1 bit, na prática, as diferenças no tempo de propagação dos 64 bits, chamadas de skew (distorção), significa que precisam ser usadas velocidades relativamente baixas. Com uma conexão serial, velocidades muito mais altas podem ser usadas, e isso compensa bastante a perda de paralelismo. Os barramentos PC trabalham com uma taxa de clock máxima de 66 MHz. Com 64 bits transferidos por ciclo, a taxa de dados é de 528 MB/s. Com uma taxa de clock de 8 GHz, até mesmo com transferência serial, a taxa de dados do PCe é de 1 GB/s. Além do mais, os dispositivos não estão limitados a um único par de fios para se comunicarem com o complexo raiz ou com um switch. Um dispositivo pode ter até 32 pares de fios, chamados de lanes (pistas). Essas pistas não são síncronas, de modo que a distorção não é importante aqui. A maioria das placas-mãe tem um encaixe de 16 pistas para a placa gráfica, que no PCe 3.0 dará à placa gráfica uma largura de banda de 16 GB/s, cerca de 30 vezes mais rápida do que uma placa gráfica PC pode oferecer. Essa largura de banda é necessária para aplicações cada vez mais exigentes, como gráficos em 3D. Segundo, toda a comunicação é ponto a ponto. Quando a CPU quer falar com um dispositivo, ela lhe envia um pacote e, em geral, recebe uma resposta depois. O pacote passa pelo complexo raiz, que está na placa-mãe, e depois para o dispositivo, possivelmente por um switch (ou, se o dispositivo for um PC, por uma ponte para PC). Essa evolução de um sistema em que todos os dispositivos escutavam o mesmo barramento para um que utiliza comunicações ponto a ponto é semelhante ao desenvolvimento das redes Ethernet (uma rede local muito popular), que também começou com um canal de broadcast, mas agora utiliza switches para permitir a comuni- cação ponto a ponto. 2.4.2 Terminais Há muitos tipos de dispositivos de E/S disponíveis. Alguns dos mais comuns são discutidos a seguir. Terminais de computador consistem em duas partes: um teclado e um monitor. No mundo dos mainframes, essas partes
  • 108. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 89 costumam ser integradas em um único dispositivo ligado ao computador principal por uma linha serial ou por uma linha telefônica. Nos setores de reserva de passagens aéreas, bancário e em outros setores que usam mainfra- mes, esses dispositivos ainda estão sendo usados. No mundo dos computadores pessoais, o teclado e o monitor são dispositivos independentes. Qualquer que seja o caso, a tecnologia das duas partes é a mesma. Teclados Há uma grande variedade de teclados. O BM PC original vinha com um teclado munido de um contato mecânico sob cada tecla, que dava retorno tátil e emitia um clique quando a tecla era apertada corretamente. Hoje, os teclados mais baratos têm teclas que fazem apenas contato mecânico quando acionados. Os melhores têm uma lâmina de material elastométrico – espécie de borracha – entre as teclas e a placa de circuito impresso que está por baixo. Sob cada tecla há uma pequena saliência que cede quando pressionada corretamente. Um pontinho de material condutor dentro da saliência fecha o circuito. Alguns teclados têm um ímã sob cada tecla, que passa por uma bobina quando pressionado, induzindo assim a uma corrente que pode ser detectada. Também há vários outros métodos em uso, mecânicos e eletromagnéticos. Em computadores pessoais, quando uma tecla é pressionada, uma interrupção é gerada e a rotina de inter- rupções do teclado (uma parte do software do sistema operacional) é executada. A rotina de interrupções lê um registrador de hardware dentro do controlador de teclado para pegar o número da tecla (1 a 102) que acabou de ser pressionada. Quando a tecla é solta, ocorre uma segunda interrupção. Assim, se um usuário pressionar SHFT, e em seguida pressionar e soltar M, e depois soltar SHFT, o sistema operacional pode ver que o usuário quer um “M”, e não um “m”. O tratamento de sequências de várias teclas envolvendo SHFT, CTRL e ALT é todo feito em software (incluindo a abominável sequência CTRL-ALT-DEL, que é usada para reiniciar PCs). Touch screens Embora os teclados não ofereçam perigo de atrapalhar a máquina de escrever manual, há um novo sujeito na praça quando se trata de entrada do computador: uma touch screen (tela sensível ao toque). Embora esses dispositivos só tenham se tornado itens do mercado de massa com a introdução do iPhone da Apple em 2007, eles são muito mais antigos. A primeira tela sensível ao toque foi desenvolvida no Royal Radar Establishment, em Malvern, Grã-Bretanha, em 1965. Até mesmo a capacidade de encolhimento na tela, tão anunciada pelo iPhone, vem do trabalho inicial na Universidade de Toronto em 1982. Desde então, muitas tecnologias diferentes foram desenvolvidas e comercializadas. Dispositivos de toque podem ser encontrados em duas categorias: opacos e transparentes. Um dispositivo sensível ao toque opaco é o touchpad de um notebook. Um dispositivo transparente típico é a tela de um smart- phone ou tablet. amos analisar apenas o segundo. Eles costumam ser chamados de touch screens. Os principais tipos de touch screens são infravermelho, resistivo e capacitivo. As telas infravermelhas são transmissores de infravermelho, como os diodos ou lasers emissores de luz infravermelha (por exemplo) nas bordas esquerda ou superior do engaste em torno da tela e detectores nas bordas direita e inferior. Quando um dedo, caneta ou qualquer objeto opaco bloqueia um ou mais raios, o detector correspondente sente a queda no sinal e o hardware do dispositivo pode dizer ao sistema operacional quais raios foram bloqueados, permitindo que ele calcule a coordenadas (x, y) do dedo ou caneta. Embora esses dispositivos já tenham sido usados há algum tempo em quiosques e outras aplicações, eles não usados para dispositivos móveis. Outra tecnologia antiga consiste em touch screens resistivas. Estas consistem em duas camadas, sendo a superior flexível. Ela contém uma grande quantidade de fios horizontais. A inferior contém fios verticais. Quando um dedo ou outro objeto pressiona um ponto na tela, um ou mais dos fios entra em contato com os fios perpen- diculares na camada inferior. Os circuitos eletrônicos do dispositivo possibilitam a leitura de qual área foi pres- sionada. Essas telas não são caras para se montar, e são muito usadas em aplicações mais simples. As duas tecnologias são boas quando a tela é pressionada por um dedo, mas têm um problema quando dois dedos são usados. Para descrever a questão, usaremos a terminologia da touch screen infravermelha, mas a resistiva
  • 109. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 90 tem a mesma dificuldade. magine que os dois dedos estejam em (3, 3) e (8, 8). Como resultado, os feixes verti- cais x = 3 e x = 8 são interrompidos, assim como os feixes horizontais y = 3 e y = 8. Agora, imagine um cenário diferente, com os dedos em (3, 8) e (8, 3), que são os cantos opostos do retângulo cujos ângulos são (3, 3), (8, 3), (8, 8) e (3, 8). Exatamente os mesmos feixes são bloqueados, de modo que o software não sabe qual dos dois cenários é o correto. Esse problema é conhecido como ghosting. Para poder detectar vários dedos ao mesmo tempo – uma propriedade exigida para os gestos de encolhimento e expansão –, uma nova tecnologia foi necessária. Aquela usada na maioria dos smartphones e tablets (mas não em câmeras digitais e outros dispositivos) é a touch screen capacitiva projetada. Existem vários tipos, mas o mais comum é o tipo de capacitância mútua. Todas as touch screens que podem detectar dois ou mais pontos de contato ao mesmo tempo são conhecidas como telas multitoque. ejamos rapidamente como elas funcionam. Para os leitores que estão meio enferrujados em sua física do colégio, um capacitor é um dispositivo que pode armazenar carga elétrica. Um capacitor simples tem dois condutores separados por um isolador. Nas touch screens modernas, um padrão tipo grande com “fios” finos correndo verticalmente é separado de uma grade horizontal por uma camada isolante fina. Quando um dedo toca na tela, ela muda a capacitância em todas as intersecções tocadas (possivelmente afastadas). Essa mudança pode ser medida. Como uma demonstração de que uma touch screen moderna não é como as antigas telas infravermelhas e resistivas, tente tocar em uma com uma caneta, lápis, clipe de papel ou dedo com luva e você verá que nada acontece. O corpo humano é bom para arma- zenar carga elétrica, como pode ser comprovado dolorosamente por qualquer um que já tenha se arrastado por um tapete em um dia frio e seco e depois tocado em uma maçaneta de metal. nstrumentos de plástico, madeira e metal não são tão bons quanto pessoas em termos de sua capacitância. Os “fios” em uma touch screen não são os fios de cobre comuns, encontrados nos dispositivos elétricos normais, pois bloqueariam a luz da tela. Em vez disso, eles são tiras finas (em geral, com 50 micra) de óxido de índio-estanho condutor, ligadas em lados opostos de uma placa fina de vidro, que juntos formam os capacitores. Em alguns dispositivos mais novos, a placa de vidro isolante é substituída por uma fina camada de dióxido de silício (areia!), com as três camadas salpicadas (átomo por átomo) em algum substrato. De qualquer forma, os capacitores são protegidos contra poeira e arranhões por uma placa de vidro acima disso, para formar a superfície da tela a ser tocada. Quanto mais fina a placa de vidro superior, mais sensível é o desempenho, porém, mais frágil é o dispositivo. Em operação, tensões são aplicadas alternadamente aos “fios” horizontal e vertical, enquanto os valores de tensão, que são afetados pela capacitância de cada intersecção, são lidos dos outros. Essa operação é repetida muitas vezes por segundo, com as coordenadas tocadas sendo alimentadas no controlador do dispositivo como um fluxo de pares (x, y). Mais processamento, como determinar se ocorre apontamento, compressão, expressão ou toque, é feito pelo sistema operacional. Se você usar todos os 10 dedos e pedir a um amigo para usar os dele, o sistema operacional terá mais trabalho, mas o hardware de toque múltiplo poderá realizar essa tarefa. Monitores de tela plana Os primeiros monitores de computador usavam tubos de raios catódicos (CRs – cathode ray tubes), assim como os antigos aparelhos de televisão. Eles eram muito volumosos e pesados para serem usados em notebooks, portanto, era preciso uma tecnologia completamente diferente para suas telas. O desenvolvimento de telas planas ofereceu um tamanho físico necessário para os notebooks, e esses dispositivos também usavam menos potência. Hoje, os benefícios em tamanho e potência do monitor de tela plana quase eliminaram o uso de monitores CRT. A mais comum tecnologia de monitor de tela plana é o LC (Liquid Crystal isplay  monitor de cristal líquido). É uma tecnologia de alta complexidade, tem muitas variações e está mudando com grande rapidez, de modo que esta descrição será necessariamente breve e muito simplificada. Cristais líquidos são moléculas orgânicas viscosas que fluem como um líquido, mas também têm estru- tura espacial, como um cristal. Foram descobertos por um botânico austríaco, Friedrich Reinitzer, em 1888 e aplicados pela primeira vez em visores (por exemplo, de calculadoras e relógios) na década de 1960. Quando todas as moléculas estão alinhadas na mesma direção, as propriedades óticas do cristal dependem da direção e
  • 110. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 91 polarização da luz incidente. Usando um campo elétrico aplicado, o alinhamento molecular e, por conseguinte, as propriedades óticas, podem ser mudadas. Em particular, fazendo passar luz através de um cristal líquido, a intensidade da luz que sai dele pode ser controlada por meios elétricos. Essa propriedade pode ser explorada para construir monitores de tela plana. Uma tela de monitor de LCD consiste em duas placas de vidro paralelas entre as quais há um volume selado que contém um cristal líquido. Eletrodos transparentes são ligados a ambas as placas. Uma luz atrás da placa traseira, natural ou artificial, ilumina a tela por trás. Os eletrodos transparentes ligados a cada placa são usados para criar campos elétricos no cristal líquido. Diferentes partes da tela recebem tensões elétricas dife- rentes para controlar a imagem apresentada. Colados às partes frontal e traseira da tela há filtros de polarização (polaroides), pois a tecnologia do monitor requer a utilização de luz polarizada. A montagem geral é mostrada na Figura 2.33(a). Figura 2.33 (a) Construc a o de uma tela de LCD. (b) Os sulcos nas placas traseira e frontal sa o perpendiculares uns aos outros. (a) (b) y z Cristal líquido Placa de vidro traseira Eletrodo traseiro Polaroide traseiro Placa de vidro frontal Eletrodo frontal Polaroide frontal Fonte de luz Escura Brilhante Notebook Embora muitos tipos de monitores de LCD estejam em uso, agora vamos considerar um tipo particular de visor, o N (wisted Nematic  nemático torcido), como exemplo. Nesse monitor, a placa traseira contém minúsculos sulcos horizontais, e a frontal, minúsculos sulcos verticais, como ilustrado na Figura 2.33(b). Na ausência de um campo elétrico, as moléculas do LCD tendem a se alinhar com os sulcos. Uma vez que os alinha- mentos frontal e traseiro estão a 90 graus entre si, as moléculas (e, portanto, a estrutura cristalina) ficam torcidas entre as placas traseira e frontal. Na parte de trás do monitor há um polaroide horizontal que permite apenas a passagem de luz polarizada horizontalmente. Na parte da frente do visor há um polaroide vertical que permite apenas a passagem de luz polarizada verticalmente. Se não houvesse nenhum líquido presente entre as placas, a luz polarizada hori- zontalmente que entrasse pelo polaroide traseiro seria bloqueada pelo polaroide frontal, produzindo uma tela uniformemente negra. Contudo, a estrutura cristalina torcida das moléculas do LCD guia a luz na passagem e gira sua polarização, fazendo com que ela saia na vertical. Portanto, na ausência de um campo elétrico, a tela de LCD é uniformemente brilhante. Aplicando uma tensão elétrica em partes selecionadas da placa, a estrutura torcida pode ser destruída, bloqueando a luz nesses locais.
  • 111. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 92 Há dois esquemas que podem ser usados para aplicar a tensão elétrica. Em um monitor de matriz passiva (de baixo custo), ambos os eletrodos contêm fios paralelos. Em um monitor de 1.920 × 1.080, por exemplo, o eletrodo traseiro poderia ter 1.920 fios verticais e o frontal poderia ter 1.080 horizontais. Aplicando-se uma tensão elétrica em um dos fios verticais e em seguida fazendo-se pulsar um dos horizontais, a tensão em uma posição de pixel sele- cionada pode ser mudada, fazendo-a escurecer por um curto espaço de tempo. Um pixel (aglutinação das palavras “picture” e “element”) é um ponto colorido a partir do qual todas as imagens digitais são construídas. Repetindo-se esse pulso para o próximo pixel e então para o seguinte, pode-se pintar uma linha escura de varredura. Em geral, a tela inteira é pintada 60 vezes por segundo, para enganar o olho e fazê-lo pensar que ali há uma imagem constante. O outro esquema de ampla utilização é o monitor de matriz ativa. É mais caro, mas produz melhor imagem. Em vez de apenas dois conjuntos de fios perpendiculares, ele tem um minúsculo elemento comutador em cada posição de pixel em um dos eletrodos. Desligando e ligando esses elementos, pode-se criar um padrão de tensão elétrica arbitrário na tela, o que permite um padrão de bits também arbitrário. Os elementos comutadores são denominados transistores de película fina (F  hin Film ransistors) e os monitores de tela plana que os utilizam costumam ser denominados monitores F. Agora, a maioria dos notebooks e monitores de tela plana para desktops utiliza a tecnologia TFT. Até aqui, descrevemos como funciona um monitor monocromático. Basta dizer que monitores coloridos usam os mesmos princípios gerais dos monocromáticos, mas os detalhes são muito mais complicados. Filtros ópticos são usados para separar a luz branca em componentes vermelha, verde e azul em cada posição de pixel, de modo que estes possam ser exibidos independentemente. Toda cor pode ser obtida por uma superposição dessas três cores primárias. Outras tecnologias de tela estão surgindo. Uma das mais promissoras é a tela OLE (Organic Light Emitting iode – diodo orgânico emissor de luz). Ela consiste em camadas de moléculas orgânicas carregadas eletrica- mente, dispostas entre dois eletrodos em forma de sanduíche. As mudanças de tensão fazem com que as molécu- las sejam excitadas e se movam para estados de energia mais altos. Quando elas retornam ao seu estado normal, emitem luz. Outros detalhes estão fora do escopo deste livro (e de seus autores). RAM de v deo Quase todos os monitores são renovados de 60 a 100 vezes por segundo por uma memória especial, denominada RM de vídeo (memória de acesso aleatório de vídeo), embutida na placa controladora do monitor. Essa memória tem um ou mais mapas de bits que representam a imagem da tela. Em uma tela com, por exemplo, 1.920 × 1.080 elementos de imagem, denominados pixels, uma RAM de vídeo conteria 1.920 × 1.080 valores, um para cada pixel. Na verdade, ela poderia conter muitos desses mapas de bits, para permitir a passagem rápida de uma imagem para outra. Em um monitor comum, cada pixel seria representado como um valor RGB (red/green/blue) de 3 bytes, um para cada intensidade das componentes vermelha, verde e azul da cor do pixel (monitores de primeira linha usam 10 ou mais bits por cor). Pelas leis da física, sabe-se que qualquer cor pode ser obtida por uma superposição linear de luzes vermelha, verde e azul. Uma RAM de vídeo com 1.920 × 1.080 pixels a 3 bytes/pixel requer mais de 6,2 MB para armazenar a imagem e uma boa quantidade de tempo de CPU para fazer qualquer coisa com ela. Por essa razão, alguns computadores adotam uma solução de conciliação usando um número de 8 bits para indicar a cor desejada. Então, esse número é usado como um índice para uma tabela de hardware denominada paleta de cores, que contém 256 entradas, cada uma com um valor RGB de 24 bits. Esse projeto, denominado cor indexada, reduz em dois terços o tamanho de memória da RAM de vídeo, mas permite somente 256 cores na tela ao mesmo tempo. Em geral, cada janela na tela tem seu próprio mapeamento. Porém, com apenas uma paleta de cores em hardware, quando há várias janelas presentes, muitas vezes apenas a janela corrente apresenta suas cores corretamente. Paletas de cores com 216 entradas também são usadas, mas o ganho aqui é de apenas 1/3. Monitores de vídeo com mapas de bits requerem grande quantidade de largura de banda. Para apresentar multimídia em tela cheia, com todas as cores em um monitor de 1.920 × 1.080, é preciso copiar 6,2 MB de dados para a RAM de vídeo para cada quadro. Quando o vídeo é de movimento total, é preciso uma taxa de no mínimo
  • 112. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 93 25 quadros por segundo, o que resulta uma taxa total de dados de 155 MB/s. Essa carga é mais do que o barra- mento PC original podia manipular (132 MB/s), mas o PCe pode tratar disso com facilidade. 2.4.3 Mouses À medida que o tempo passa, os computadores estão sendo usados por pessoas menos versadas sobre o modo de funcionamento desses equipamentos. Máquinas da geração ENAC só eram empregadas pelas pessoas que as construíram. Na década de 1950, computadores eram utilizados apenas por programadores profissionais altamente treinados. Agora, são amplamente usados por pessoas que precisam fazer algum trabalho e não sabem muito (ou nem querem saber) sobre como funcionam os computadores ou como são programados. Antigamente, a maioria dos computadores tinha interfaces de linha de comando, para as quais os usuários digi- tavam comandos. isto que quem não é especialista quase sempre acha que interfaces de linha de comando não são amigáveis ao usuário – se não absolutamente hostis –, muitos fabricantes desenvolveram interfaces do tipo “apontar e clicar”, tais como as do Macintosh e do Windows. Usar esse modelo pressupõe que haja um modo de apontar algo na tela. O meio mais comum de permitir que usuários apontem algo na tela é um mouse. Um mouse é um caixinha de plástico que fica sobre a mesa, ao lado do teclado. Quando ela é movimentada sobre a mesa, um pequeno ponteiro também se movimenta na tela, permitindo que os usuários apontem itens. O mouse tem um, dois ou três botões na parte de cima, que possibilitam aos usuários selecionar itens apresentados em menus. Muita polêmica já se levantou por causa de discussões sobre o número de teclas que um mouse deve ter. Usuários ingênuos preferem uma só (não há como apertar a tecla errada se houver apenas uma), mas os sofis- ticados gostam do poder conferido por várias teclas para fazer coisas imaginativas. Três tipos de mouses foram produzidos: mecânicos, ópticos e óptico-mecânicos. Os primeiros tinham duas rodinhas de borracha para fora da parte inferior do corpo com eixos perpendiculares entre si. Quando o mouse era movimentado em paralelo com seu eixo principal, uma roda girava. Quando ele era movimentado ao longo da perpendicular de seu eixo principal, a outra roda girava. Cada rodinha comandava um resistor variável (poten- ciômetro). Medindo as alterações na resistência era possível ver como cada roda tinha girado e assim calcular a distância que o mouse tinha percorrido em cada direção. Depois, esse projeto foi substituído em grande parte por outro, no qual, em vez de rodinhas, era usada uma pequena esfera projetada um pouco para fora do fundo do mouse. Ele é mostrado na Figura 2.34. Figura 2.34 Utilizac a o do mouse para apontar itens de menu. Ponteiro controlado por mouse Janela Menu Recortar Colar Copiar Botões do mouse Mouse Bola de borracha
  • 113. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 94 O segundo tipo de mouse é o óptico. Esse tipo não tem rodinhas nem esferas. Em vez delas, tem um LE (Light Emitting iode  diodo emissor de luz) e um fotodetector na parte de baixo. Os primeiros mouses ópticos exigiam uma almofada plástica especial que continha uma grade retangular de linhas espaçadas muito próximas umas das outras para detectar quantas linhas tinham sido atravessadas e, assim, a que distância o mouse se movimentou. Os mouses ópticos modernos contêm um LED que ilumina as imperfeições da superfí- cie, junto com uma pequena câmera de vídeo que registra uma pequena imagem (em geral, 18 × 18 pixels) até 1.000 vezes por segundo. magens consecutivas são comparadas para ver a que distância o mouse se moveu. Alguns mouses ópticos utilizam um laser no lugar de um LED para iluminação. Eles são mais precisos, mas também mais caros. O terceiro tipo de mouse é o óptico-mecânico. Assim como o mouse mecânico mais novo, ele tem uma esfera que gira dois eixos alinhados a 90 graus em relação um ao outro. Os eixos estão conectados a decodificadores com fendas que permitem a passagem da luz. Quando o mouse se movimenta, os eixos giram e pulsos de luz atingem os detectores sempre que aparece uma fenda entre um LED e seu detector. O número de pulsos detectados é pro- porcional à quantidade de movimento. Embora mouses possam ser montados de várias maneiras, um arranjo comum é enviar uma sequência de 3 bytes ao computador toda vez que o mouse se movimenta a uma distância mínima (por exemplo, 0,01 polegada), às vezes denominada mickey. Em geral, esses caracteres vêm em uma linha serial, um bit por vez. O primeiro byte contém um inteiro com sinal que informa quantas unidades o mouse se moveu na direção x desde a última vez. O segundo dá a mesma informação para movimento na direção y. O terceiro contém o estado corrente das teclas do mouse. Às vezes, são usados 2 bytes para cada coordenada. No computador, um software de baixo nível aceita essas informações à medida que chegam e converte os movimentos relativos enviados pelo mouse em uma posição absoluta. Em seguida, ele apresenta na tela uma seta correspondente à posição onde o mouse está. Quando a seta indicar o item adequado, o usuário clica no botão do mouse e então o computador pode interpretar qual item foi selecionado, por saber onde a seta está posicionada na tela. 2.4.4 Controladores de jogos Os videogames costumam ter exigências muito altas de E/S do usuário e, no mercado de console de vídeo, dispositivos de entrada especializados têm sido desenvolvidos. Nesta seção, veremos dois desenvolvimentos recentes em controladores para videogame, o Nintendo Wiimote e o Microsoft Kinect. Controlador Wiimote Lançado em 2006 com o console de jogos Nintendo Wii, o controlador Wiimote contém botões tradicionais para jogos e mais uma capacidade de sensibilidade dupla ao movimento. Todas as interações com o Wiimote são enviadas em tempo real ao console de jogos, usando um rádio Bluetooth interno. Os sensores de movimento no Wiimote permitem que ele sinta seu próprio movimento nas três dimensões e mais; quando apontado para a televisão, ele oferece uma capacidade minuciosa para apontar. A Figura 2.35 ilustra como o Wiimote executa essa função de sensibilidade ao movimento. O rastrea- mento do movimento do Wiimote em três dimensões é realizado com um acelerômetro interno de 3 eixos. Esse dispositivo contém três massas pequenas, cada qual podendo se mover nos eixos x, y e z (com relação ao chip do acelerômetro). Elas se movem em proporção ao grau de aceleração em seu eixo particular, o que muda a capacitância da massa em relação a uma parede fixa de metal. Medindo as três capacitâncias variáveis, é possível sentir a aceleração em três dimensões. Usando essa tecnologia e algum cálculo clássico, o console Wii pode rastrear o movimento do Wiimote no espaço. Ao movimentar o Wiimote para atingir uma bola de tênis virtual, esse movimento é rastreado enquanto você se desloca em direção à bola e, se você virou o pulso no último momento para atingir a bola por cima, os acelerômetros do Wiimote também notarão esse movimento.
  • 114. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 95 Figura 2.35 Sensores de movimento do controlador de videogame Wiimote. z y x Barra de sensor Câmera Acelerômetro de 3 eixos Embora os acelerômetros funcionem bem para acompanhar o movimento do Wiimote enquanto ele se deslo- ca em três dimensões, eles não podem oferecer a sensibilidade de movimento detalhada necessária para controlar um ponteiro na tela da televisão. Os acelerômetros sofrem com pequenos erros inevitáveis em suas medições de aceleração, de modo que, com o tempo, o local exato do Wiimote (com base na integração de suas acelerações) se tornará cada vez menos preciso. Para oferecer a sensibilidade de movimento com precisão, o Wiimote utiliza uma tecnologia de visão de computador inteligente. Acima da televisão há uma “barra de sensor” que contém LEDs a uma distância fixa. No Wiimote há uma câmera que, quando apontada na barra de sensor, pode deduzir a distância e orientação em relação à televisão. Como os LEDs da barra de sensor estão afastados a certa distância, sua distância vista pelo Wiimote é proporcional àquela entre o Wiimote e a barra de sensor. O local da barra de sensor no campo de visão do Wiimote indica a direção que este aponta em relação à televisão. Observando essa orientação continuamente, é possível dar suporte a uma capacidade de apontamento minucioso sem os erros de posição inerentes aos ace- lerômetros. Controlador Kinect O Microsoft Kinect leva as capacidades de visão dos controladores de jogos a um nível inteiramente novo. Esse dispositivo usa apenas a visão do computador para determinar as interações do usuário com o console de jogos. Ele funciona sentindo a posição do usuário na sala, mais a orientação e o movimento de seu corpo. Os jogos são controlados por movimentos predeterminados de suas mãos, braços e qualquer outra coisa que os projetistas do jogo acreditarem que você deva mexer a fim de controlar seu jogo.
  • 115. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 96 A capacidade de sentir do Kinect é baseada em uma câmera de profundidade combinada com uma câmera de vídeo. A câmera de profundidade calcula a distância do objeto no campo de visão do Kinect. Ela faz isso emitindo uma matriz bidimensional de pontos a laser infravermelho, depois capturando seus reflexos com uma câmera infravermelha. Usando uma técnica de visão do computador chamada “iluminação estruturada”, o Kinect pode determinar a distância dos objetos em seu campo de visão com base em como o conjunto de pontos infraverme- lhos é agitado pelas superfícies iluminadas. A informação de profundidade é combinada com a informação de textura retornada da câmera de vídeo para produzir um mapa de profundidade texturizado. Esse mapa pode então ser processado pelos algoritmos de visão do computador para localizar a pessoa na sala (até mesmo reconhecendo seus rostos) e a orientação e movimento de seu corpo. Depois de processar, a informação sobre as pessoas na sala é enviada ao console do jogo, que usa esses dados para controlar o videogame. 2.4.5 Impressoras Após o usuário preparar um documento ou buscar uma página na Web, muitas vezes quer imprimir seu trabalho, de modo que todos os computadores podem ser equipados com uma impressora. Nesta seção, descre- veremos alguns dos tipos mais comuns de impressoras. Impressoras a laser Talvez o desenvolvimento mais interessante da impressão desde que Johann Gutenberg inventou o tipo móvel no século  é a impressora a laser. Esse dispositivo combina uma imagem de alta qualidade, excelente flexibilidade, grande velocidade e custo moderado em um único periférico compacto. mpressoras a laser usam quase a mesma tecnologia das máquinas fotocopiadoras. Na verdade, muitas empresas fabricam equipamentos que combinam cópia e impressão (e, às vezes, também fax). A tecnologia básica é ilustrada na Figura 2.36. O coração da impressora é um tambor rotativo de precisão (ou uma correia, em alguns sistemas de primeira linha). No início de cada ciclo de página, ele recebe uma carga de até cerca de 1.000 volts e é revestido com um material fotossensível. Então, a luz de um laser passa pelo comprimento do tambor, refletindo-a de um espelho octogonal rotativo. O feixe de luz é modulado para produzir um padrão de pontos escuros e claros. Os pontos atingidos pelo feixe perdem sua carga elétrica. Figura 2.36 Operac a o de uma impressora a laser. Laser Espelho octogonal rotativo Tambor pulverizado e carregado Feixe de luz atinge o tambor Tambor Toner Raspador Dispensador Papel em branco Roletes aquecidos Saída empilhada
  • 116. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 97 Após pintar uma linha de pontos, o tambor gira uma fração de um grau para permitir que a próxima linha seja pintada. Com o decorrer da rotação, a primeira linha de pontos chega ao toner, um reservatório que contém um pó negro eletrostaticamente sensível. O toner é atraído por aqueles pontos que ainda estão carregados, for- mando uma imagem visual daquela linha. Um pouco mais adiante na trajetória de transporte, o tambor revestido de toner é pressionado contra o papel, transferindo o pó preto para ele. Em seguida, o papel passa por rolamentos aquecidos que fundem permanentemente o toner à superfície do papel, fixando a imagem. Em um ponto mais adiante de sua rotação, o tambor é descarregado e raspado para limpar qualquer resíduo de toner, preparando-o para receber nova carga elétrica e revestimento para imprimir a próxima página. Nem é preciso dizer que esse processo é uma combinação extremamente complexa de física, química, engenharia mecânica e engenharia ótica. Ainda assim, há vários fabricantes no mercado que oferecem conjuntos complexos denominados mecanismos de impressão. Fabricantes de impressoras a laser combinam os mecanis- mos de impressão com sua própria eletrônica e software próprio para montar uma impressora completa. A parte eletrônica consiste em uma CPU rápida embutida junto com megabytes de memória para conter um mapa de bits de uma página inteira e numerosas fontes, algumas delas embutidas, outras carregadas por download. Grande parte das impressoras aceita comandos que descrevem as páginas a serem impressas (ao contrário de apenas aceitar mapas de bits preparados pela CPU principal). Esses comandos são dados em linguagens como a PCL da HP e PostScript da Adobe ou PDF , que são linguagens de programação completas, embora especializadas. mpressoras a laser de 600 dpi ou mais podem executar um trabalho razoável na impressão de fotografias em preto e branco, mas a tecnologia é mais complicada do que pode parecer à primeira vista. Considere uma fotogra- fia digitalizada em 600 dpi que deve ser impressa por uma impressora de 600 dpi. A imagem contém 600 × 600 pixels/polegada, cada um consistindo em um valor de cinza que varia de 0 (branco) a 255 (preto). A impressora também pode imprimir 600 dpi, mas cada pixel impresso é ou preto (toner presente) ou branco (nenhum toner presente). alores cinza não podem ser impressos. A solução habitual para imprimir imagens com valores de cinza é usar a técnica do meio-tom (retícula), a mesma empregada para imprimir cartazes comerciais. A imagem é desmembrada em células de meios-tons, em geral com 6 × 6 pixels. Cada célula pode conter entre 0 e 36 pixels pretos. O olho percebe uma célula com muitos pixels como mais escura do que uma com menos pixels. alores de cinza na faixa de 0 a 255 são representados dividindo essa faixa em 37 zonas. alores de 0 a 6 estão na zona 0, valores de 7 a 13 estão na zona 1 e assim por diante (a zona 36 é um pouco menor do que as outras porque 256 não é divisível exatamente por 37). Sempre que é encontrado um valor de cinza na zona 0, sua célula de meio-tom sobre o papel é deixada em branco, como ilustrado na Figura 2.37(a). Um valor de zona 1 é impresso como 1 pixel negro. Um valor de zona 2 é impresso como 2 pixels negros, conforme mostra a Figura 2.37(b). Outros valores de zonas são mostrados nas figuras 2.37(c)–(f). Claro que pegar uma fotografia digitalizada a 600 dpi e usar essa técnica de meio-tom reduz a resolução efetiva a 100 células/polegada, denominada frequência de tela de meio-tom, medida por convenção em lpi (lines per inch  linhas por polegada). Figura 2.37 Pontos de meio-tom para va rias faixas de escala de cinza. (a) 0–6. (b) 14–20. (c) 28–34. (d) 56–62. (e) 105–111. (f) 161–167. (a) (b) (c) (d) (e) (f) Impressa o colorida Embora a maioria das impressoras a laser seja monocromática, impressoras a laser coloridas estão se tor- nando mais comuns, de modo que talvez seja útil dar aqui alguma explicação sobre a impressão colorida (que também se aplica a impressoras a jato de tinta e outras). Como você poderia imaginar, isso não é trivial. magens
  • 117. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 98 coloridas podem ser vistas de duas maneiras: por luz transmitida e por luz refletida. magens por luz transmiti- da, como as produzidas em monitores, são compostas por superposição linear das três cores primárias aditivas: vermelho, verde e azul. Ao contrário, imagens por luz refletida, como fotografias em cores e fotos em revistas de papel lustroso, absorvem certos comprimentos de onda de luz e refletem o resto. Elas são compostas por uma superposição linear das três cores subtrativas primárias, ciano (toda cor vermelha absorvida), magenta (toda cor verde absorvida) e amarela (toda cor azul absorvida). Em teoria, toda cor pode ser produzida misturando as tintas ciano, amarela e magenta. Na prática, é difícil conseguir essas tintas com pureza suficiente para absorver toda a luz e produzir um negro verdadeiro. Por essa razão, praticamente todos os sistemas de impressão em cores usam quatro tintas: ciano, magenta, amarela e negra. Esses sistemas são denominados impressoras CMYK. O K é geralmente associado à cor negra (blacK), porém, ele é a placa chave com a qual as placas de cores são alinhadas em impressoras con- vencionais de quatro cores. Monitores, ao contrário, usam luz transmitida e o sistema RGB para produzir cores. O conjunto completo de cores que um monitor ou uma impressora podem produzir é denominado sua gama. Nenhum dispositivo tem uma gama que se iguale à do mundo real, já que cada cor vem em 256 intensidades no máximo, o que dá apenas 16.777.216 cores discretas. mperfeições na tecnologia reduzem ainda mais esse total e as restantes nem sempre estão uniformemente espaçadas no espectro de cores. Além do mais, a percepção da cor tem muito a ver com o modo de funcionamento dos bastões e cones na retina, e não apenas com a física da luz. Como consequência dessas observações, converter uma imagem colorida que parece boa na tela em uma imagem impressa idêntica está longe de ser trivial. Entre os problemas estão: 1. Monitores em cores usam luz transmitida; impressoras em cores usam luz refletida. 2. Monitores produzem 256 intensidades por cor; impressoras têm de usar meios-tons. 3. Monitores têm um fundo negro; o papel tem um fundo claro. 4. As gamas RGB de um monitor e as gamas CMYK de uma impressora são diferentes. Obter imagens impressas em cores que reproduzem os tons do mundo real (ou até mesmo os das imagens na tela) requer calibração de dispositivos, software sofisticado e considerável conhecimento técnico e experiência da parte do usuário. Impressoras a jato de tinta Para impressão doméstica de baixo custo, as impressoras a jato de tinta são as favoritas. A cabeça de impres- são móvel, que mantém os cartuchos de tinta, é varrida horizontalmente pelo papel por uma correia, enquanto a tinta é espirrada por minúsculos esguichos. As gotículas de tinta têm um volume de mais ou menos 1 picolitro, de modo que 100 milhões delas formam uma única gota d’água. mpressoras a jato de tinta podem ter duas variedades: piezelétricas (usadas pela Epson) e térmicas (usadas pela Canon, HP e Lexmark). As impressoras a jato de tinta piezelétricas possuem um tipo especial de cristal próximo de sua câmara de tinta. Quando uma tensão elétrica é aplicada ao cristal, ela se deforma ligeiramente, forçando uma gotícula de tinta a sair pelo esguicho. Quanto maior a tensão, maior a gotícula, permitindo que o software controle seu tamanho. mpressoras a jato de tinta térmicas (também chamadas impressoras a jato de bolhas) contêm um minúsculo resistor dentro de cada esguicho. Quando uma tensão elétrica é aplicada ao resistor, ele se aquece extremamente rápido, elevando de imediato a temperatura da tinta que encosta nele até o ponto de ebulição, até que a tinta se vaporize para formar uma bolha de gás. A bolha de gás ocupa mais volume do que a tinta que a criou, produzindo pressão no esguicho. O único lugar para onde a tinta pode sair é pela frente do esguicho, para o papel. O esguicho é então resfriado e o vácuo resultante suga outra gota de tinta do cartucho. A velocidade da impressora é limitada pela velocidade com que o ciclo aquecer/resfriar pode ser repetido. As gotículas são todas do mesmo tamanho, mas menores do que as usadas pelas impressoras piezelétricas.
  • 118. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 99 As impressoras a jato de tinta normalmente possuem resoluções de pelo menos 1.200 dpi (dots per inch – pontos por polegada) e, no máximo, 4.800 dpi. Elas são baratas, silenciosas e possuem boa qualidade, apesar de também serem lentas, e utilizam cartuchos de tinta caros. Quando a melhor das impressoras a jato de tinta de alta qualidade é usada para imprimir fotografia em alta resolução profissional com papel fotográfico espe- cialmente lustroso, os resultados são parecidos com a fotografia convencional, até mesmo com impressões de 20 × 25 cm. Para obter melhores resultados, é preciso usar tinta e papel especiais. intas à base de corantes consistem em corantes coloridos dissolvidos em uma base fluida. Elas dão cores brilhantes e fluem com facilidade. Sua principal desvantagem é que desbotam quando expostas à luz ultravioleta, tal como a contida na luz solar. intas à base de pigmentos contêm partículas sólidas de pigmentos suspensas em uma base fluida, que evapora do papel dei- xando ali o pigmento. Não desbotam com o tempo, mas não são tão brilhantes como as tintas à base de corantes e as partículas de pigmento tendem a entupir os bicos injetores, que requerem limpeza periódica. Para imprimir fotografias, é preciso papel lustroso ou revestido. Esses tipos de papel foram projetados especialmente para conter as gotículas de tinta e não permitir que elas se espalhem. Impressoras especiais Embora impressoras a laser e a jato de tinta dominem os mercados de impressão doméstico e de escritório, outros tipos de impressoras são usados em outras situações, com outros requisitos em termos de qualidade de cor, preço e outras características. Uma variante da impressora a jato de tinta é a impressora de tinta sólida. Esse tipo de impressora aceita quatro blocos sólidos de uma tinta especial à base de cera, que são derretidos e passam para reservatórios de tinta quente. Os tempos de partida dessas impressoras podem chegar a 10 minutos, enquanto os blocos de tinta estão derretendo. A tinta quente é borrifada sobre o papel, onde se solidifica e se funde com o papel quando este é forçado a passar entre dois roletes rígidos. De certa forma, ela combina a ideia de borrifar tinta das impressoras a jato de tinta com a ideia de fundir a tinta no papel com roletes de borracha rígidos das impressoras a laser. Outro tipo de impressora em cores é a impressora a cera. Ela tem uma larga fita encerada em quatro cores, segmentada em faixas do tamanho de páginas. Milhares de elementos de aquecimento derretem a cera à medi- da que o papel passa por baixo dela. A cera se funde com o papel na forma de pixels usando o sistema CMYK. mpressoras a cera costumavam ser a principal tecnologia de impressão em cores, mas estão sendo substituídas pelos outros tipos cujos materiais de consumo são mais baratos. Ainda outro tipo de impressora em cores é a impressora por sublimação de corante, ou de tinta. Embora dê a entender algo de freudiano, sublimação é o nome científico da passagem do estado sólido para o gasoso sem passar pelo estado líquido. Gelo seco (dióxido de carbono congelado) é um material bem conhecido que sublima. Em uma impressora por sublimação de tinta, uma base contendo os corantes CMYK passa sobre um cabeçote de impressão térmico que contém milhares de elementos de aquecimento programáveis. As tintas são vaporizadas instantaneamente e absorvidas por um papel especial que está próximo. Cada elemento de aquecimento pode produzir 256 temperaturas diferentes. Quanto mais alta a temperatura, mais corante é depositado e mais intensa é a cor. Diferente de todas as outras impressoras em cores, nessa são possíveis cores praticamente contínuas para cada pixel, de modo que o meio-tom não é necessário. Pequenas impressoras de instantâneos muitas vezes usam o processo de sublimação de tinta para produzir imagens fotográficas de alto grau de realismo sobre papel especial (e caro). Por fim, chegamos à impressora térmica, que contém uma pequena cabeça de impressão com alguma quan- tidade de minúsculas agulhas que podem ser aquecidas. Quando uma corrente elétrica passa por uma agulha, ela se torna muito quente depressa. Quando um papel termicamente sensível especial é empurrado pela cabeça de impressão, os pontos são feitos no papel quando as agulhas estão quentes. Com efeito, uma impressora térmica é como as antigas impressoras matriciais, cujos pinos eram pressionados contra uma fita tipo máquina de escrever para formar os pontos de tinta no papel atrás da fita. As impressoras térmicas são muito usadas para imprimir recibos em lojas, caixas eletrônicos de banco, postos de gasolina automatizados etc.
  • 119. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 100 2.4.6 Equipamento de telecomunicac o es Hoje, grande parte dos computadores está ligada a uma rede de computadores, em geral a nternet. Para conseguir acesso, é preciso usar equipamento especial. Nesta seção, veremos como esse equipamento funciona. Modems Com o crescimento da utilização de computadores nos últimos anos, é comum que um computador pre- cise se comunicar com outro. Por exemplo, muitas pessoas têm em casa computadores pessoais que usam para se comunicar com o que está em seu local de trabalho, com uma provedora de serviço de nternet (SP – nternet Service Provider) ou com um sistema de home banking. Em muitos casos, a linha telefônica provê comunicação física. Contudo, uma linha telefônica comum (ou cabo) não é adequada para transmissão de sinais de computador que costumam representar um 0 como 0 volt e um 1 como 3 a 5 volts, conforme mostra a Figura 2.38(a). Sinais de dois níveis sofrem considerável distorção quando transmitidos por uma linha telefônica projetada para voz, ocasionando erros de transmissão. Todavia, um sinal de onda senoidal pura em uma frequência de 1.000 a 2.000 Hz, denominada portadora, pode ser transmitido com relativamente pouca distorção, e esse fato é explorado como a base da maioria dos sistemas de telecomunicação. Como as pulsações de uma onda senoidal são totalmente previsíveis, uma onda senoidal pura não transmite nenhuma informação. Contudo, variando a amplitude, frequência ou fase, uma sequência de 1s e 0s pode ser transmitida, como mostra a Figura 2.38. Esse processo é denominado modulação, e o dispositivo que faz isso é denominado modem, que significa MOdulador EModulador. Na modulação de amplitude (veja a Figura 2.38(b)), são usados dois níveis de tensão elétrica (voltagem) para 0 e 1, respectivamente. Uma pessoa que esteja ouvindo dados transmitidos a uma taxa de dados muito baixa ouviria um ruído alto para 1 e nenhum ruído para 0. Em modulação de frequência (veja a Figura 2.38(c)), o nível de tensão elétrica (voltagem) é constante, mas a frequência da portadora é diferente para 1 e para 0. Uma pessoa que estivesse ouvindo dados digitais com frequência modulada ouviria dois tons, correspondentes a 0 e 1. A modulação de frequência costuma ser denominada modulação por chaveamento de frequência. Figura 2.38 Transmissa o bit a bit do nu mero bina rio 01001011000100 por uma linha telefo nica. (a) Sinal de dois n veis. (b) Modulac a o de amplitude. (c) Modulac a o de freque ncia. (d) Modulac a o de fase. (a) (b) (c) (d) V1 V2 0 1 0 0 1 0 1 1 0 0 0 1 0 0 Tempo Tensão Alta amplitude Baixa amplitude Frequência alta Frequência baixa Mudança de fase
  • 120. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 101 Em modulação de fase simples (veja Figura 2.38(d)), a amplitude e a frequência não mudam, mas a fase da portadora é invertida 180 graus quando os dados passam de 0 para 1 ou de 1 para 0. Em sistemas de fase modulada mais sofisticados, no início de cada intervalo de tempo indivisível, a fase da portadora é bruscamente mudada para 45, 135, 225 ou 315 graus, para permitir 2 bits por intervalo de tempo, denominado codificação de fase dibit. Por exemplo, uma mudança de fase de 45 graus poderia representar 00, uma mudança de fase de 135 graus poderia representar 01 e assim por diante. Também existem outros esquemas para transmitir 3 ou mais bits por intervalo de tempo. O número de intervalos de tempo, isto é, o número de mudanças de sinal por segundo, é uma taxa de bauds. Com 2 ou mais bits por intervalo, a taxa de bits ultrapassará a taxa de bauds. Muitos confundem os dois termos. Novamente: a taxa de bauds é o número de vezes que o sinal muda por segundo, enquanto a taxa de bits é o número de bits transmitidos por segundo. A taxa de bits geralmente é um múltiplo da taxa de bauds, mas teoricamente ela pode ser menor. Se os dados a serem transmitidos consistirem em uma série de caracteres de 8 bits, seria desejável ter uma conexão capaz de transmitir 8 bits simultaneamente – isto é, oito pares de fios. Como as linhas telefônicas ofe- recem apenas um canal, os bits têm de ser enviados de modo serial, um após o outro (ou em grupos de dois se estiver sendo usada a codificação dibit). O dispositivo que aceita caracteres de um computador na forma de sinais de dois níveis, um bit por vez, e transmite os bits em grupos de um ou dois, em forma de amplitude, frequência ou fase modulada, é o modem. Para marcar o início e o final de cada caractere, é enviado um caractere de 8 bits precedido por um bit de início e seguido por um bit de fim, totalizando 10 bits. O modem que está transmitindo envia os bits individuais dentro de um caractere a intervalos de tempo regularmente espaçados. Por exemplo, 9.600 bauds implica uma mudança de sinal a cada 104 μs. Um segundo modem na extremidade receptora é usado para converter uma portadora modulada em um número binário. Como os bits chegam ao receptor a intervalos regulares, uma vez que o modem receptor tenha determinado o início do caractere, seu clock o informa quando amostrar a linha para ler os bits que estão entrando. Modems modernos funcionam a taxas de dados na faixa de 56 kbps, normalmente a taxas muito mais baixas. Eles usam uma combinação de técnicas para enviar múltiplos bits por baud, modulando a amplitude, a frequência e a fase. Quase todos eles são full-duplex, o que quer dizer que podem transmitir em ambas as direções ao mesmo tempo (usando frequências diferentes). Modems ou linhas de transmissão que só podem transmitir em uma dire- ção por vez (como uma ferrovia com uma única linha que pode transportar trens em direção ao norte ou trens em direção ao sul, mas não fazê-lo ao mesmo tempo) são denominados half-duplex. Linhas que só podem transmitir em uma direção são linhas simplex. Linhas digitais de assinante (DSL  Digital Subscriber Lines) Quando a indústria da telefonia chegou por fim aos 56 kbps, ela se congratulou por um trabalho bem-feito. Enquanto isso, a indústria da T a cabo estava oferecendo velocidades de até 10 Mbps em cabos compartilhados e as operadoras de satélites estavam planejando oferecer mais de 50 Mbps. À medida que o acesso à nternet tornou- -se uma parte cada vez mais importante de seus negócios, as telcos (telephone companies  empresas de telefonia) começaram a perceber que precisavam de um produto mais competitivo do que linhas discadas. A resposta dessas empresas foi começar a oferecer um novo serviço digital de acesso à nternet. Serviços com mais largura de banda do que o serviço telefônico padrão às vezes são denominados serviços de banda larga, embora, na realidade, o termo seja mais um conceito de marketing do que qualquer outra coisa. Por um ponto de vista estritamente técnico, banda larga significa que existem vários canais de sinalização, enquanto banda base significa que há somente um. Assim, teoricamente, a Ethernet a 10 gigabits, que é muito mais distante do que qualquer serviço de “banda larga” oferecido pela companhia telefônica, não é banda larga de forma alguma, pois tem apenas um canal de sinalização. De início, havia muitas ofertas que se sobrepunham, todas sob o mesmo nome geral de xSL (igital Subscriber Line), para vários x. Mais adiante, discutiremos o serviço que provavelmente vai se tornar o mais popular desses, o SL (symmetric SL  SL assimétrico). isto que o ADSL ainda está sendo desenvolvido e nem todos os padrões estão totalmente em vigor, alguns dos detalhes dados mais adiante podem mudar com o tempo, mas o quadro básico deve continuar válido. Para obter mais informações sobre ADSL, veja Summers, 1999; e etter et al., 2000.
  • 121. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 102 A razão por que modems são tão lentos é que os telefones foram inventados para transmitir a voz humana e todo o sistema foi cuidadosamente otimizado para essa finalidade. Dados sempre foram filhos adotivos. A linha, denominada loop local, de cada assinante da companhia telefônica é tradicionalmente limitada a cerca de 3.000 Hz por um filtro na central da empresa de telecomunicações. É esse filtro que limita a taxa de dados. A largura de banda real do loop local depende de seu comprimento, mas, para distâncias típicas de alguns qui- lômetros, 1,1 MHz é viável. O método mais comum da oferta de ADSL é ilustrado na Figura 2.39. Na verdade, o que ele faz é remover o filtro e dividir o espectro disponível de 1,1 MHz no loop local em 256 canais independentes de 4.312,5 Hz cada. O canal 0 é usado para POS (Plain Old elephone Service  serviço telefônico normal). Os canais de 1 a 5 não são usados para evitar que o sinal de voz e os sinais de dados interfiram uns com os outros. Dos 250 canais restantes, um é usado para controle na direção da empresa de telefonia e outro para controle na direção do usuário. O resto está disponível para dados do usuário. O ADSL equivale a ter 250 modems. Figura 2.39 Operac a o de ADSL. Direção do usuário Potência 256 canais de 4 kHz Voz Direção da empresa Em princípio, cada um dos canais remanescentes pode ser usado para um fluxo de dados full-duplex, mas, na prática, harmônicos, linhas cruzadas e outros efeitos mantêm os sistemas bem abaixo do limite teórico. Cabe ao provedor determinar quantos canais são usados na direção da empresa e quantos na direção do usuário. Uma proporção de 50–50 é tecnicamente possível, mas a maioria das provedoras aloca cerca de 80%–90% da largura de banda na direção do usuário, uma vez que eles descarregam mais dados do que carregam. Essa opção deu origem ao “A” em ADSL (de Assimétrico). Uma divisão comum são 32 canais na direção da empresa e o resto na direção do usuário. A qualidade da linha é monitorada constantemente dentro de cada canal e a taxa de dados é ajustada confor- me necessário, portanto, canais diferentes podem ter taxas de dados diferentes. Os dados propriamente ditos são enviados usando uma combinação de modulação de amplitude e de fase com até 15 bits por baud. Por exemplo, com 224 canais na direção do usuário e 15 bits/baud a 4.000 bauds, a largura de banda na direção do usuário é 13,44 Mbps. Na prática, a relação sinal/ruído nunca é boa o suficiente para alcançar essa taxa, mas 4–8 Mbps é possível em distâncias curtas por loops de alta qualidade. Uma configuração ADSL típica é mostrada na Figura 2.40. Nesse esquema, o usuário ou um técnico da com- panhia telefônica deve instalar um NI (Network Interface evice  dispositivo de interface de rede) na casa ou escritório do cliente. Essa caixinha de plástico marca o final da propriedade da companhia telefônica e o início da propriedade do cliente. Próximo ao ND (ou às vezes combinado com ele) há um divisor, um filtro analógico que separa a faixa de 0–4.000 Hz usada pelo POTS dos dados. O sinal do POTS é direcionado ao telefone ou apa- relho de fax e o sinal de dados é direcionado a um modem ADSL. Na verdade, o modem ADSL é um processador de sinais digitais que foi montado para agir como 250 modems funcionando em paralelo a frequências diferentes. Uma vez que a maioria dos modems ADSL é externa, o computador deve estar conectado a ele em alta velocidade. sso costuma ser feito com a instalação de uma placa Ethernet no computador e operação de uma Ethernet muito curta de dois nós que contém apenas o computador e o modem ADSL. (Ethernet é um padrão de rede local popular e barato.) Por vezes, usa-se a porta USB em vez da Ethernet. Sem dúvida, haverá placas internas de modem ADSL disponíveis no futuro. 0 25 1.100 kHz
  • 122. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 103 Figura 2.40 Configurac a o t pica de equipamento ADSL. Comutador de voz Codec Divisor DSLAM Para o ISP Escritório da companhia telefônica Linha telefônica Telefone Divisor Computador Modem ADSL Ethernet Casa ou escritório do cliente NID Na outra extremidade da linha, no lado da empresa telefônica está instalado um divisor correspondente, no qual a parte da voz é filtrada e enviada ao comutador de voz normal. O sinal acima de 26 kHz é direcionado para um novo tipo de dispositivo denominado SLM (igital Subscriber Line ccess Multiplexer  multiplexador de acesso de linha digital de assinante), que contém o mesmo tipo de processador de sinal digital que o modem ADSL. Uma vez recuperado o sinal digital em um fluxo de bits, são formados pacotes e enviados à SP . Internet por cabo Muitas empresas de T agora estão oferecendo acesso à nternet por meio de seus cabos. Como a tecnologia é muito diferente da ADSL, vale a pena fazer uma breve descrição. Em cada cidade, a operadora por cabo tem uma central e uma grande quantidade de caixas cheias de dispositivos eletrônicos denominados terminais de distribuição (headends) distribuídos por todo o seu território. Os terminais de distribuição estão conectados à central por cabos de alta largura de banda ou de fibra ótica. Cada terminal tem um ou mais cabos que passam por centenas de casas e escritórios. Cada cliente da prove- dora por cabo está ligado ao cabo que passa por sua casa ou escritório. Assim, centenas de usuários compartilham o mesmo cabo até o terminal. Em geral, o cabo tem uma largura de banda de mais ou menos 750 MHz. Esse sistema é radicalmente diferente do ADSL porque cada usuário de telefone tem uma linha privada (isto é, não compartilhada) com a central telefônica. Contudo, na prática, ter seu próprio canal de 1,1 MHz com uma empresa de telefonia não é muito diferente do que compartilhar uma porção de 200 MHz do espectro do cabo que chega ao terminal com 400 usuários, metade dos quais não o estará usando em qualquer dado momento. Porém, isso significa que um usuário de nternet por cabo conseguirá um serviço muito melhor às 4h00 do que às 16h00, enquanto o serviço ADSL é constante durante o dia inteiro. Quem quiser obter um serviço ideal de nternet por cabo deveria se mudar para uma vizinhança rica (casas mais afastadas uma da outra, portanto, menos usuários por cabo) ou para um bairro pobre (onde ninguém pode pagar pelo serviço de nternet). Uma vez que o cabo é um meio compartilhado, determinar quem pode enviar quando e em qual frequência é uma questão importante. Para ver como isso funciona, temos de fazer um breve resumo do modo de funciona- mento de uma T a cabo. Nos Estados Unidos, os canais de televisão a cabo ocupam a região de 54 a 550 MHz (exceto para rádio FM, de 88 a 108 MHz). Esses canais têm 6 MHz de largura, incluindo faixas de proteção para impe- dir vazamento de sinal entre canais. Na Europa, a extremidade baixa é normalmente 65 MHz e os canais têm de 6 a 8 MHz de largura para a resolução mais alta exigida por PAL e SECAM; porém, quanto ao mais, o esquema de alocação é similar. A porção inferior da banda não é usada para transmissão de televisão.
  • 123. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 104 Quando as empresas por cabo lançaram a nternet por cabo, tinham dois problemas a resolver: 1. Como acrescentar acesso à nternet sem interferir com programas de T. 2. Como ter tráfego bidirecional quando os amplificadores são inerentemente unidirecionais. As soluções são as seguintes. Cabos modernos têm uma largura de banda de pelo menos 550 MHz, muitas vezes até 750 MHz ou mais. Os canais ascendentes (isto é, do usuário ao terminal de distribuição) entram na faixa de 5–42 MHz (um pouco mais alta na Europa), e o tráfego descendente (isto é, do terminal de distribuição ao usuário) usa as frequências da extremidade alta, como ilustrado na Figura 2.41. Figura 2.41 Alocac a o de freque ncia em um sistema t pico de TV a cabo usado para acesso a  Internet. 0 108 550 750 MHz 5 42 54 88 Dados ascendentes Dados descendentes Frequências ascendentes Frequências descendentes TV FM TV Note que, como os sinais de T são todos descendentes, é possível usar amplificadores ascendentes que funcionam apenas na região de 5 a 42 MHz, e amplificadores descendentes que só funcionam a 54 MHz e acima, conforme mostra a figura. Assim, obtemos uma assimetria nas larguras de banda ascendente e descendente, por- que há mais espectro disponível acima da banda da televisão do que abaixo dela. Por outro lado, a maior parte do tráfego será provavelmente na direção descendente, portanto, as operadoras por cabo não estão infelizes com essas coisas da vida. Como vimos antes, empresas de telefonia costumam oferecer um serviço DSL assimétrico, ainda que não tenham nenhuma razão técnica para fazê-lo. O acesso à nternet requer um modem por cabo, um dispositivo que tem duas interfaces: uma com o compu- tador e outra com a rede a cabo. A interface computador-modem a cabo é direta. Em geral, é Ethernet, exatamente como na ADSL. No futuro, o modem inteiro poderá se resumir a uma pequena placa inserida no computador, exatamente como nos antigos modems por telefone. A outra extremidade é mais complicada. Grande parte do padrão por cabo lida com engenharia de rádio, uma questão que está muito além do escopo deste livro. A única parte que vale a pena mencionar é que modems por cabo, assim como os ADSL, estão sempre ligados. Eles estabelecem uma conexão quando são ligados e a mantêm enquanto houver energia, porque operadoras por cabo não cobram por tempo de conexão. Para entender melhor como elas funcionam, vamos ver o que acontece quando um modem por cabo é ins- talado e ligado. O modem faz uma varredura dos canais descendentes em busca de um pacote especial lançado periodicamente pelo terminal de distribuição para fornecer parâmetros do sistema aos modems que acabaram de entrar em linha. Quando achar esse pacote, o novo modem anuncia sua presença em um dos canais ascendentes. O terminal de distribuição responde designando o modem a seus canais ascendente e descendente. Essas designações podem ser mudadas mais tarde se o terminal de distribuição achar necessário equilibrar a carga. O modem determina sua distância em relação ao terminal de distribuição enviando um pacote especial e observando quanto tempo demora para obter uma resposta. Esse processo é denominado ranging. É importante que o modem conheça sua distância para ajustar o modo como os canais ascendentes operam e para acertar sua temporização. Eles são divididos em mini-intervalos de tempo. Cada pacote ascendente deve se ajustar a um ou
  • 124. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 105 mais mini-intervalos de tempo consecutivos. O terminal de distribuição anuncia periodicamente o início de uma nova rodada de mini-intervalos, mas o tiro de largada não é ouvido por todos os modems simultaneamente por causa do tempo de propagação pelo cabo. Sabendo a que distância está do terminal de distribuição, cada modem pode calcular há quanto tempo o primeiro mini-intervalo de fato começou. O comprimento do mini-intervalo depende da rede. Uma carga útil típica é 8 bytes. Durante a inicialização, o terminal de distribuição também designa cada modem a um mini-intervalo que será usado para requisitar largura de banda ascendente. Como regra, múltiplos modems serão designados ao mesmo mini-intervalo, o que leva à disputa. Quando um computador quer enviar um pacote, ele o transfere ao modem, que então requisita o número necessário de mini-intervalos para ele. Se a requisição for aceita, o terminal de distribuição manda um reconhecimento pelo canal descendente, informando ao modem quais mini-intervalos foram reservados para seu pacote. Então, o pacote é enviado, começando no mini-intervalo a ele alocado. Pacotes adicionais podem ser requisitados usando um campo no cabeçalho. Por outro lado, se houver disputa para o mini-intervalo requisitado, nenhum reconhecimento será enviado e o modem espera um tempo aleatório, e tenta mais uma vez. Após cada uma dessas tentativas sucessivas malsuce- didas, o tempo aleatório é duplicado para distribuir a carga quando o tráfego estiver pesado. Os canais descendentes são gerenciados de modo diferente dos canais ascendentes. Uma razão é que há só um remetente (o terminal de distribuição), portanto, não há nenhuma disputa e nenhuma necessidade de mini- -intervalos que, na verdade, é apenas um modo de multiplexação por divisão estatística. Outra razão é que o tráfego descendente costuma ser muito maior do que o ascendente, portanto, é um pacote de tamanho fixo de 204 bytes. Parte dele é um código de correção de erros Reed-Solomon e algumas outras informações de controle, sobrando 184 bytes de carga útil para o usuário. Esses números foram escolhidos por compatibilidade com a televisão digital, que usa MPEG-2, de modo que os canais de T e os canais descendentes sejam formatados do mesmo modo. O aspecto lógico das conexões é mostrado na Figura 2.42. Figura 2.42 Detalhes t picos dos canais ascendente e descendente na Ame rica do Norte. QAM-64 (Quadrature Amplitude Modulation – modulac a o de amplitude em quadratura) permite 6 bits/Hz, mas funciona somente em altas freque ncias. QPSK (Quadrature Phase Shift Keying – modulac a o por chaveamento de fase em quadratura) funciona em baixas freque ncias, mas permite apenas 2 bits/Hz. Canal ascendente com contenção: 9 Mbps usando QPSK e mini-intervalos de 8 bytes Cabo coaxial Canal descendente sem contenção: 27 Mbps usando QAM-64 e cargas úteis de 184 bytes Fibra Terminal Pacote Modem ISP oltando à inicialização do modem, uma vez concluída a ranging e obtida a designação de seu canal ascendente, canal descendente e mini-intervalo, ele está liberado para começar a enviar pacotes. Esses pacotes vão até o terminal de distribuição, que os retransmite por um canal dedicado até a central da operadora por cabo e então até o SP (que pode ser a própria empresa por cabo). O primeiro pacote é dirigido à SP e requisita um endereço de rede (tecni- camente, um endereço P) que é designado dinamicamente. O pacote também requisita e obtém um horário exato. A próxima etapa envolve segurança. Uma vez que o cabo é um meio compartilhado, quem quiser se dar ao trabalho pode ler todo o tráfego que passar por ele. Para evitar que qualquer um bisbilhote seus vizinhos (lite-
  • 125. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 106 ralmente), todo o tráfego é criptografado em ambas as direções. Parte do procedimento de inicialização envolve estabelecer chaves criptográficas. A princípio, poderíamos pensar que conseguir que dois estranhos, o terminal de distribuição e o modem, combinem uma chave secreta em plena luz do dia com milhares de pessoas vigiando seria algo difícil. Acontece que não é, mas a técnica usada (o algoritmo Diffie-Hellman) está fora do escopo deste livro. Uma discussão sobre esse algoritmo é dada em Kaufman et al. (2002). Por fim, o modem tem de registrar (fazer login) e fornecer seu identificador exclusivo pelo canal seguro. Nesse ponto, está concluída a inicialização. Agora, o usuário pode se conectar com o SP e começar a trabalhar. Há muito mais a ser dito sobre modems a cabo. Algumas referências relevantes são: Adams e Dulchinos, 2001; Donaldson e Jones, 2001; Dutta-Roy, 2001. 2.4.7 Ca meras digitais Uma utilização cada vez mais popular de computadores é a fotografia digital, o que transforma câmeras digitais em uma espécie de periférico de computador. amos descrever rapidamente como isso funciona. Todas as câmeras têm uma lente que forma uma imagem do sujeito no fundo da câmera. Em um equipamen- to convencional, o fundo da câmera está coberto por uma película fotográfica sobre a qual é formada uma imagem latente quando a luz a atinge. Essa imagem latente pode ficar visível pela ação de certos produtos químicos presentes no líquido de revelação, ou revelador. Uma câmera digital funciona da mesma maneira, exceto que o filme é substituído por um arranjo retangular de CCs (Charge-Coupled evices  disposi- tivos de carga acoplada) sensíveis à luz. (Algumas câmeras digitais usam CMOS [Complementary Metal- -Oxyde Semiconductor – semicondutor de óxido metálico complementar], mas aqui vamos nos concentrar nos CCDs, que são mais comuns.) Quando a luz atinge um CCD, ele adquire uma carga elétrica. Quanto mais luz, mais carga. A carga pode ser lida em um conversor analógico para digital como um inteiro de 0 a 255 (em câmeras mais baratas) ou de 0 a 4.095 (em câmeras reflex digitais de uma lente). A configuração básica é mostrada na Figura 2.43. Figura 2.43 Ca mera digital. R R B R R B B B G G G G G G G G Um pixel é composto de quatro CCDs, um vermelho (R), um azul (B) e dois verdes (G). Lente Diafragma Arranjo de CCDs CPU RAM Memória flash Câmera digital
  • 126. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 107 Cada CCD produz um único valor, independente da cor da luz que o atinge. Para formar imagens colo- ridas, os CCDs são organizados em grupos de quatro elementos. Um filtro Bayer é colocado no topo do CCD de modo a permitir que somente a luz vermelha atinja um dos quatro em cada grupo, apenas a luz azul atinja um outro e só a luz verde atinja os outros dois. São usados dois CCDs para a luz verde porque utilizar quatro CCDs para representar um pixel é muito mais conveniente do que usar três, e o olho é mais sensível à luz verde do que à vermelha ou à azul. Quando um fabricante afirma que uma câmera tem, por exemplo, 6 milhões de pixels, ele está mentindo. A câmera tem 6 milhões de CCDs que, juntos, formam 1,5 milhão de pixels. A imagem será lida como um arranjo de 2.828 × 2.121 pixels (em câmeras de baixo preço) ou de 3.000 × 2.000 pixels (em SLRs digitais), mas os pixels extras são produzidos por interpolação pelo software dentro da câmera. Quando o botão do obturador da câmera é pressionado, o software no equipamento realiza três tare- fas: ajusta o foco, determina a exposição e efetua o equilíbrio do branco. O autofoco funciona analisando a informação de alta frequência na imagem e então movimentando a lente até que ela seja maximizada, para dar o máximo de detalhe. A exposição é determinada medindo a luz que cai sobre os CCDs e então ajustando o diafragma da lente e o tempo de exposição para fazer a intensidade da luz cair no meio da faixa de alcance dos CCDs. Ajustar o equilíbrio do branco tem a ver com medir o espectro da luz incidente para efetuar as necessárias correções de cor mais tarde. Então, a imagem é lida com base nos CCDs e armazenada como um arranjo de pixels na RAM interna da câmera. SLRs de primeira linha usados por fotojornalistas podem fotografar oito quadros de alta resolução por segundo por 5 segundos, e precisam de cerca de 1 GB de RAM interna para armazenar as imagens antes de processá-las e armazená-las permanentemente. Câmeras mais baratas têm menos RAM, mas ainda assim têm boa quantidade. Na fase de pós-captura, o software da câmera aplica correção da cor por equilíbrio do branco para compensar a luz avermelhada ou azulada (por exemplo, de um objeto na sombra ou da utilização de um flash). Em seguida, ele aplica um algoritmo para reduzir ruído e outro para compensar CCDs defeituosos. Logo após, o software tenta dar melhor definição à imagem (a menos que essa característica esteja desativada), procurando contornos e aumentando o gradiente de intensidade ao redor deles. Por fim, a imagem pode ser comprimida para reduzir a quantidade de armazenagem requerida. Um formato comum é o JPEG (Joint Photographic Experts Group  grupo associado de especialistas em fotografia), no qual uma transformada de Fourier espacial bidimensional é aplicada e alguns dos componentes de alta frequência são omitidos. O resultado dessa transformação é que a imagem requer um número menor de bits de armazenagem, mas perdem-se os detalhes mais sutis. Quando todo processamento interno à câmera estiver concluído, a imagem é gravada no meio de armaze- nagem, em geral uma memória rápida ou um minúsculo disco rígido removível denominado microdrive. O pós- -processamento e a gravação podem levar vários segundos por imagem. Quando o usuário chega em casa, a câmera pode ser conectada a um computador, em geral usando, por exemplo, uma entrada USB ou um cabo específico. Então, as imagens são transferidas da câmera para o disco rígido do computador. Usando software especial, tal como o Adobe Photoshop, o usuário pode recortar a imagem, ajustar brilho, contraste e equilíbrio de cor, destacar, escurecer ou remover porções da imagem e aplicar diversos filtros. Quando ele estiver contente com o resultado, os arquivos podem ser impressos em uma impressora em cores, enviados pela nternet a uma loja especializada para fazer o acabamento ou gravados em um CD-ROM ou DD para armazenagem em arquivo e subsequente impressão. A quantidade de capacidade computacional, RAM, espaço em disco rígido e software em uma câmera digital SLR é estarrecedora. Além de o computador ter de fazer todas as coisas mencionadas, ainda precisa se comunicar com a CPU na lente e com a CPU na memória rápida, renovar a imagem na tela LCD e gerenciar todos os botões, engrenagens, luzes, mostradores e dispositivos da câmera em tempo real. Esse sistema embutido é extremamente poderoso e muitas vezes rivaliza com um computador de mesa de apenas alguns anos atrás.
  • 127. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 108 2.4.8 Co digos de caracteres Cada computador tem um conjunto de caracteres que ele usa. O conjunto mínimo contém as 26 letras maiúsculas, as 26 letras minúsculas, os algarismos de 0 a 9 e um conjunto de símbolos especiais, como espaço, sinal de menos, vírgula e retorno ao início da linha. Para transferir esses caracteres para o computador, um número é designado a cada um, por exemplo, a = 1, b = 2, ..., z = 26, + = 27, – = 28. O mapeamento de caracteres para números inteiros é denominado código de caracteres. É essencial que computadores que se comunicam usem o mesmo código ou não conseguirão se entender. Por essa razão, foram desenvolvidos padrões. A seguir, examinaremos dois dos mais importantes. ASCII Um código de ampla utilização é denominado SCII (merican Standard Code for Information Interchange  código padrão americano para troca de informações). Cada caractere ASC tem 7 bits, o que permite 128 caracteres no total. Porém, como os computadores são orientados a byte, cada caractere ASC é armazenado em um byte separado. A Figura 2.44 mostra o código ASC. Os códigos de 0 a 1F (hexadecimal) são caracteres de controle e não são impressos. Os códigos de 128 a 255 não fazem parte do ASC, mas o BM PC os definiu para serem caracteres especiais, como os smileys, e a maioria dos computadores tem suporte para eles. Figura 2.44 O conjunto de caracteres ASCII. Hexa Nome Significado Hexa Nome Significado 0 NUL Null 10 DLE Data Link Escape 1 SOH Start Of Heading 11 DC1 Device Control 1 2 STX Start Of TeXt 12 DC2 Device Control 2 3 ETX End Of TeXt 13 DC3 Device Control 3 4 EOT End Of Transmission 14 DC4 Device Control 4 5 ENQ Enquiry 15 NAK Negative AcKnowledgement 6 ACK ACKnowledgement 16 SYN SYNchronous idle 7 BEL BELl 17 ETB End of Transmission Block 8 BS BackSpace 18 CAN CANcel 9 HT Horizontal Tab 19 EM End of Medium A LF Line Feed 1A SUB SUBstitute B VT Vertical Tab 1B ESC ESCape C FF Form Feed 1C FS File Separator D CR Carriage Return 1D GS Group Separator E SO Shift Out 1E RS Record Separator F SI Shift In 1F US Unit Separator Hexa Car Hexa Car Hexa Car Hexa Car Hexa Car Hexa Car 20 Espaço 30 0 40 @ 50 P 60 ' 70 p 21 ! 31 1 41 A 51 Q 61 a 71 q 22 " 32 2 42 B 52 R 62 b 72 r 23 # 33 3 43 C 53 S 63 c 73 s 24 $ 34 4 44 D 54 T 64 d 74 t 25 % 35 5 45 E 55 U 65 e 75 u 26 & 36 6 46 F 56 V 66 f 76 v 27 ' 37 7 47 G 57 W 67 g 77 w 28 ( 38 8 48 H 58 X 68 h 78 x 29 ) 39 9 49 I 59 Y 69 i 79 y
  • 128. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 109 Hexa Car Hexa Car Hexa Car Hexa Car Hexa Car Hexa Car 2A * 3A : 4A J 5A Z 6A j 7A z 2B + 3B ; 4B K 5B [ 6B k 7B { 2C , 3C < 4C L 5C 6C l 7C | 2D - 3D = 4D M 5D ] 6D m 7D } 2E . 3E > 4E N 5E ^ 6E n 7E ~ 2F / 3F ? 4F O 5F _ 6F o 7F DEL Muitos dos caracteres de controle ASC são destinados à transmissão de dados. Por exemplo, uma men- sagem pode ser composta de um caractere SOH (start of header – início de cabeçalho), um caractere ST (start of text – início de texto), o texto em si, um caractere ET (end of text – fim do texto) e então um caractere EOT (end of transmission – fim da transmissão). Contudo, na prática, as mensagens enviadas por linhas telefônicas e redes são formatadas de modo muito diferente, de modo que os caracteres ASC de controle de transmissão já não são muito usados. Os caracteres de impressão ASC são diretos. ncluem as letras maiúsculas e minúsculas, dígitos, sinais de pontuação e alguns símbolos matemáticos. Unicode A indústria do computador se desenvolveu em grande parte nos Estados Unidos, o que levou ao conjunto de caracteres ASC. Esse código é bom para a língua inglesa, mas não tão bom para outros idiomas. O francês precisa de acentos (por exemplo, système); o alemão precisa de sinais diacríticos (por exemplo, für) e assim por diante. Algumas línguas europeias têm certas letras que não se encontram no ASC, tais como a alemã ß e a dinamarquesa ø. Alguns idiomas têm alfabetos inteiramente diferentes (por exemplo, russo e árabe), e algumas poucas línguas não têm alfabeto algum (por exemplo, a chinesa). Como os computadores se espalharam pelos quatro cantos do mundo e como os fabricantes de software querem vender produtos em países onde a maioria dos usuários não fala inglês, é preciso um novo conjunto de caracteres. A primeira tentativa de ampliar o ASC foi o S 646, que acrescentou mais 128 caracteres ao ASC, trans- formando-o em um código de 8 bits denominado Latin-1. A maioria dos caracteres adicionais eram letras latinas com acentos e sinais diacríticos. A próxima tentativa foi o S 8859, que introduziu o conceito de uma página de código, um conjunto de 256 caracteres para um idioma particular ou grupo de idiomas. O S 8859-1 é Latin-1. O S 8859-2 trata dos idiomas eslavos baseados no latim (por exemplo, tcheco, polonês e húngaro). O S 8859-3 contém os caracteres necessários para os idiomas turco, maltês, esperanto, galego e assim por diante. O problema da abordagem da página de código é que o software tem de manter controle da página em que está; é impossível misturar idiomas nas páginas e o esquema não cobre a língua japonesa nem a chinesa. Um grupo de empresas de computadores resolveu esse problema formando um consórcio para criar um novo sistema, denominado Unicode, e transformando-o em um Padrão nternacional (S 10646). Agora, o Unicode é suportado por algumas linguagens de programação (por exemplo, Java), alguns sistemas operacionais (por exem- plo, Windows) e muitas aplicações. A ideia que fundamenta o Unicode é designar a cada caractere e símbolo um valor único de 16 bits, deno- minado ponto de código. Não são usados caracteres multibytes nem sequências de escape. Símbolos de 16 bits simplificam a escrita do software. Com símbolos de 16 bits, o Unicode tem 65.536 pontos de código. isto que todos os idiomas do mundo usam cerca de 200 mil símbolos, os pontos de código são um recurso escasso que deve ser alocado com grande cuidado. Para acelerar a aceitação do Unicode, o consórcio teve a brilhante ideia de usar Latin-1 como pontos de código 0 a 255, o que facilita a conversão entre ASC e Unicode. Para evitar desperdiçar pontos de código, cada sinal diacrítico tem seu próprio ponto de código. Cabe ao software combinar sinais diacríticos com seus vizinhos para formar novos caracteres. Embora isso aumente o trabalho do software, economiza preciosos pontos de código.
  • 129. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 110 O espaço do ponto de código é dividido em blocos, cada qual um múltiplo de 16 pontos de código. Todo alfa- beto importante em Unicode tem uma sequência de zonas consecutivas. Alguns exemplos (e o número de pontos de código alocados) são latim (336), grego (144), cirílico (256), armênio (96), hebraico (112), devanágari (128), gurmuqui (128), oriá (128), telugo (128) e canará (128). Note que cada um desses idiomas recebeu um número maior de pontos de código do que número de letras que possui. Essa opção foi escolhida em parte porque muitas línguas têm várias formas para cada letra. Por exemplo, cada letra em português tem duas formas – minúscula e MAÚSCULA. Alguns idiomas têm três ou mais formas, possivelmente dependendo de a letra estar no início, no meio ou no final de uma palavra. Além desses alfabetos, foram designados pontos de código para sinais diacríticos (112), sinais de pontuação (112), subscritos e sobrescritos (48), símbolos monetários (48), símbolos matemáticos (256), formas geomé- tricas (96) e sinais variados (dingbats) (192). Depois desses, vêm os símbolos necessários para as línguas chinesa, japonesa e coreana. Primeiro, há 1.024 símbolos fonéticos (por exemplo, katakana e bopomofo) e, em seguida, os ideogramas han unificados (20.992) usados em chinês e japonês, e as sílabas hangul do idioma coreano (11.156). Para permitir que os usuários inventem caracteres especiais para finalidades especiais, 6.400 pontos de códi- go foram designados para uso local. Embora o Unicode solucione muitas dificuldades associadas com a internacionalização, ele não resolve (nem tenta resolver) todos os problemas do mundo. Por exemplo, enquanto o alfabeto latino está em ordem alfabética, os ideogramas han não estão na ordem do dicionário. Por conseguinte, um programa em inglês pode procurar cat e dog em ordem alfabética simplesmente comparando o valor Unicode de seu primeiro caractere. Um programa em japonês precisa de tabelas externas para interpretar qual dos dois símbolos vem antes do outro no dicionário. Outra questão é que surgem novas palavras o tempo todo. Há 50 anos ninguém falava de applets, ciberespaço, gigabytes, lasers, modems, smileys ou videoteipes. Acrescentar novas palavras em inglês não requer novos pontos de código, mas adicioná-las em japonês, sim. Além de novas palavras técnicas, há uma demanda para adicionar no mínimo 20 mil novos nomes de pessoas e lugares (a maioria chineses). Os cegos acham que o braille deveria estar presente e grupos de interesse especial de todos os tipos querem o que entendem como pontos de código a que têm direito. O consórcio Unicode estuda e decide todas as novas propostas. O Unicode usa o mesmo ponto de código para caracteres que parecem quase idênticos mas têm significados diferentes ou são escritos de maneira ligeiramente diferente em japonês e chinês (como se processadores de texto em inglês sempre escrevessem blue como blew, porque têm o mesmo som). Há quem considere isso uma otimização para economizar pontos de código escassos; outros o veem como imperialismo cultural anglo-saxão (e você acha que designar 16 bits para caracteres não foi uma decisão muito política?). Para piorar as coisas, um dicionário japonês completo tem 50 mil kanji (excluindo nomes), portanto, com apenas 20.992 pontos de código disponíveis para os ideogramas han, escolhas tiveram de ser feitas. Nem todos os japoneses acham que um consórcio de fabricantes de computadores – mesmo que alguns deles sejam japoneses – é o fórum ideal para fazer essas escolhas. Adivinha só: 65.536 pontos de código não foram suficientes para satisfazer a todos, de modo que, em 1996, 16 planos adicionais de 16 bits cada foram acrescentados, expandindo o número total de caracteres para 1.114.112. UTF-8 Embora melhor que o ASC, o Unicode por fim esgotou os pontos de código e também requer 16 bits por caractere para representar o texto ASC puro, o que é um desperdício. Por conseguinte, outro esquema de codifi- cação foi desenvolvido para resolver essas questões. Ele é denominado Formato de ransformação UF-8 UCS, em que UCS significa Universal Character Set (conjunto de caracteres universal), que é Unicode na essência. Códigos UTF-8 têm tamanho variável, de 1 a 4 bytes, e podem codificar cerca de dois bilhões de caracteres. Ele é o conjunto de caracteres dominante em uso na Web. Uma das propriedades interessantes do UTF-8 é que os códigos de 0 a 127 são os caracteres ASC, permitin- do que sejam expressos em 1 byte (contra os 2 bytes do Unicode). Para caracteres que não são ASC, o bit de alta ordem do primeiro byte é definido como 1, indicando que virão 1 ou mais bytes adicionais. No fim, seis formatos diferentes são usados, conforme ilustra a Figura 2.45. Os bits marcados com “d” são bits de dados.
  • 130. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 111 Figura 2.45 O esquema de codificac a o UTF-8. Bits Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6 7 0ddddddd 11 110ddddd 10dddddd 16 1110dddd 10dddddd 10dddddd 21 11110ddd 10dddddd 10dddddd 10dddddd 26 111110dd 10dddddd 10dddddd 10dddddd 10dddddd 31 1111110d 10dddddd 10dddddd 10dddddd 10dddddd 10dddddd O UTF-8 tem uma série de vantagens em relação ao Unicode e outros esquemas. Primeiro, se um programa ou documento utiliza apenas caracteres que estão no conjunto ASC, cada um pode ser representado em 8 bits. Segundo, o primeiro byte de cada caractere UTF-8 determina exclusivamente o número de bytes deste. Terceiro, os bytes de continuação em um caractere UTF-8 sempre começam com 10, enquanto o byte inicial nunca começa assim, tornando o código autossincronizável. Em particular, no caso de um erro de comunicação ou memória, sempre é possível prosseguir e achar o início do próximo caractere (supondo que ele não tenha sido danificado). Em geral, o UTF-8 é usado para codificar apenas os 17 planos Unicode, embora o esquema tenha muito mais de 1.114.112 pontos de código. Porém, se os antropólogos descobrirem novas tribos em Nova Guiné (ou em outro lugar) cujos idiomas ainda não sejam conhecidos (ou se, no futuro, fizermos contato com extraterrestres), o UTF-8 conseguirá acrescentar seus alfabetos ou ideogramas. 2.5 Resumo Sistemas de computadores são compostos por três tipos de componentes: processadores, memórias e dispo- sitivos de E/S. A tarefa de um processador é buscar instruções, uma por vez, em uma memória, decodificá-las e executá-las. O ciclo busca-decodificação-execução pode ser descrito como um algoritmo e, na verdade, às vezes ele é executado por um interpretador de software que roda em um nível mais baixo. Para ganhar velocidade, muitos computadores agora têm um ou mais pipelines (paralelismo) ou têm um projeto superescalar com múltiplas uni- dades funcionais que funcionam em paralelo. Um pipeline permite que uma instrução seja dividida em etapas e as etapas para diferentes instruções sejam executadas ao mesmo tempo. Múltiplas unidades funcionais é outra forma de obter paralelismo sem afetar o conjunto de instruções ou a arquitetura visível ao programador ou compilador. Sistemas com vários processadores são cada vez mais comuns. Computadores paralelos incluem processa- dores matriciais, nos quais a mesma operação é efetuada sobre múltiplos conjuntos de dados ao mesmo tempo; multiprocessadores, nos quais várias CPUs compartilham uma memória; e multicomputadores, nos quais cada um dos vários computadores tem sua própria memória, mas se comunicam passando mensagens. Memórias podem ser categorizadas como primárias ou secundárias. A memória primária é usada para conter o programa que está sendo executado no momento. Seu tempo de acesso é curto – algumas poucas dezenas de nanos- segundos, no máximo – e independe do endereço que está sendo acessado. Caches reduzem ainda mais esse tempo de acesso. Eles são necessários porque as velocidades do processador são muito maiores do que as velocidades da memória, o que significa que ter de esperar pelos acessos à memória o tempo todo atrasa bastante a execução do processador. Algumas memórias são equipadas com códigos de correção de erros para aumentar a confiabilidade. Memórias secundárias, ao contrário, têm tempos de acesso muito mais longos (milissegundos ou mais) e dependem da localização dos dados que estão sendo lidos ou escritos. Fitas, discos magnéticos e discos ópticos são as memórias secundárias mais comuns. Há muitas variedades de discos magnéticos, incluindo discos DE, discos SCS e RADs. Entre os discos ópticos figuram CD-ROMs, CD-Rs, DDs e Blu-rays.
  • 131. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 112 Dispositivos de E/S são usados para transferir informações para dentro e para fora do computador. Então, são conectados ao processador e à memória por um ou mais barramentos. Alguns exemplos são terminais, mouses, impressoras e modems. A maioria dos dispositivos de E/S usa o código de caracteres ASC, embora o Unicode também seja usado e o UTF-8 esteja ganhando rápida aceitação à medida que a indústria de computadores se volta mais para a Web. Problemas 1. Considere a operação de uma máquina que tenha o caminho de dados da Figura 2.2. Suponha que carregar os registradores de entrada da ULA leve 5 ns, executar a ULA demore 10 ns e armazenar o resultado de volta no registrador de rascunho tome 5 ns. Qual é o número máximo de MPS de que essa máquina é capaz na ausência de paralelismo (pipelining)? 2. Qual é a finalidade da etapa 2 na lista da Seção 2.1.2? O que aconteceria se essa etapa fosse omitida? 3. No computador 1, o tempo de execução de todas as instruções é 10 ns. No computador 2, o tempo de execução é de 5 ns. ocê pode afirmar com certeza que o computador 2 é mais rápido? Discuta sua resposta. 4. magine que você está projetando um computador de um só chip para um sistema embutido. O chip conte- rá toda sua memória e executará à mesma velocidade da CPU sem penalidade de acesso. Examine cada um dos princípios discutidos na Seção 2.1.4 e diga por que são tão importantes (admitindo que ainda se deseje alto desempenho). 5. Para competir com a prensa impressora recentemen- te inventada, um mosteiro medieval decidiu produzir em massa livros escritos em papel, reunindo um vasto número de escribas em uma grande sala. O superior do mosteiro então ditaria a primeira palavra do livro a ser produzido e todos os escribas a escre- veriam. Em seguida, ele ditaria a segunda palavra e todos os escribas a escreveriam. Esse processo seria repetido até que o livro inteiro fosse lido e copiado. Com qual dos sistemas de processador paralelo dis- cutidos na Seção 2.1.6 esse sistema é mais parecido? 6. À medida que descemos na hierarquia de memória de cinco níveis discutida no texto, o tempo de aces- so aumenta. Faça uma estimativa razoável da razão entre o tempo de acesso por disco óptico e o tempo de acesso ao registrador da memória. Suponha que o disco já esteja on-line. 7. Sociólogos podem obter três respostas possíveis para uma típica pergunta de levantamento como “ocê acredita em Papai Noel?” – ou seja: sim, não, nenhu- ma opinião. Tendo isso em mente, a Sociomagnetic Computer Company decidiu construir um com- putador para processar os dados do levantamento. Esse computador tem uma memória ternária, isto é, cada byte (tryte?) consiste em 8 trits, sendo que um trit contém um 0, um 1 ou um 2. Quantos trits são necessários para conter um número de 6 bits? Escreva uma expressão para o número de trits neces- sário para conter n bits. 8. Calcule a taxa de dados do olho humano usando as seguintes informações. O campo visual consiste em cerca de 106 elementos (pixels). Cada pixel pode ser reduzido a uma sobreposição das três cores pri- márias, cada uma com 64 intensidades. A resolução temporal é de 100 ms. 9. Calcule a taxa de dados do ouvido humano usando as seguintes informações. As pessoas podem ouvir frequências de até 22 kHz. Para capturar toda a informação em um sinal sonoro a 22 kHz, é preciso amostrar o som a duas vezes aquela frequência, isto é, a 44 kHz. Uma amostra de 16 bits provavelmente basta para capturar a maioria das informações auditi- vas (isto é, o ouvido não pode distinguir mais do que 65.535 níveis de intensidade). 10. As informações genéticas de todos os seres viventes estão codificadas como moléculas de DNA. Uma molécula de DNA é uma sequência linear dos quatro nucleotídeos básicos: A, C, G e T. O genoma humano contém cerca de 3 × 109 nucleotídeos na forma de mais ou menos 30 mil genes. Qual é a capacidade total de informações (em bits) do genoma humano? Qual é a capacidade máxima de informações (em bits) do gene médio? 11. Certocomputadorpodeserequipadocom1.073.741.824 bytes de memória. Por que um fabricante escolheria tal número peculiar, em vez de um número fácil de lem- brar, como 1 milhão? 12. nvente um código de Hamming de paridade par de 7 bits para os dígitos 0 a 9. 13. nvente um código para os dígitos 0 a 9 cuja distância de Hamming seja 2. 14. Em um código de Hamming, alguns bits são “des- perdiçados” no sentido de que são usados para verificação, e não para informação. Qual é a porcen- tagem de bits desperdiçados para mensagens cujo
  • 132. C a p  t u l o 2 O r g a n i z a c  a  o d e s i s t e m a s d e c o m p u t a d o r e s 113 comprimento total (dados + bits de verificação) é 2n – 1? Avalie essa expressão numericamente para valores de n de 3 a 10. 15. Um caractere ASC estendido é representado por uma quantidade de 8 bits. A codificação de Hamming asso- ciada a cada caractere pode então ser representada por uma sequência de três dígitos hexa. Codifique o seguin- te texto ASC estendido de cinco caracteres usando um código de Hamming com paridade par: Earth. Mostre sua resposta como uma sequência de dígitos hexa. 16. A sequência de dígitos hexa a seguir codifica carac- teres ASC estendidos em um código de Hamming com paridade par: 0D3 DD3 0F2 5C1 1C5 CE3. Decodifique essa sequência e escreva os caracteres que são codificados. 17. O disco ilustrado na Figura 2.19 tem 1.024 setores/ trilha e uma taxa de rotação de 7.200 RPM. Qual é a taxa de transferência sustentada do disco sobre uma trilha? 18. Um computador tem um barramento com tempo de ciclo de 5 ns, durante o qual ele pode ler ou escrever uma palavra de 32 bits da memória. O computador tem um disco Ultra4-SCS que usa o barramento e executa a 160 Mbytes/s. A CPU normalmente busca e executa uma instrução de 32 bits a cada 1 ns. De quanto é a desaceleração da CPU causada pelo disco? 19. magine que você esteja escrevendo a parte do geren- ciamento de disco de um sistema operacional. ocê representa o disco logicamente como uma sequência de blocos desde 0 no interior até algum máximo no exterior. À medida que são criados arquivos, você tem de alocar setores livres. ocê poderia fazer isso de fora para dentro ou de dentro para fora. A estratégia que escolhe tem importância em um disco moderno? Explique sua resposta. 20. Quanto tempo leva para ler um disco com 10 mil cilindros, cada um com quatro trilhas de 2.048 setores? Primeiro, todos os setores da trilha 0 devem ser lidos iniciando no setor contendo 0, em seguida, todos os setores da trilha 1 iniciando no setor 0 e assim por diante. O tempo de rotação é 10 ms, e uma busca leva 1 ms entre cilindros adja- centes e 20 ms para o pior caso. As passagens de uma trilha para outra de um cilindro podem ser feitas instantaneamente. 21. O RAD nível 3 é capaz de corrigir erros de um só bit usando apenas um drive de paridade. Então, para que serve o RAD nível 2? Afinal, ele só pode corrigir um erro e precisa de mais drives para fazê-lo. 22. Qual é a exata capacidade de dados (em bytes) de um CD-ROM modo 2 que contenha os 80 minutos de mídia que agora são o padrão? Qual é a capacidade para dados de usuário em modo 1? 23. Para gravar um CD-R, o laser deve pulsar entre ligado e desligado a alta velocidade. Ao executar em velocidade 10x em modo 1, qual é a duração do pulso em nanossegundos? 24. Para poder colocar 133 minutos de vídeo em um DD de um lado só e em uma única camada, é preci- so uma razoável compressão. Calcule o fator de com- pressão exigido. Suponha que haja 3,5 GB de espaço disponível para a faixa de vídeo, que a resolução de imagem é de 720 × 480 pixels com cor de 24 bits (RGB a 8 bits cada) e as imagens são apresentadas a 30 quadros/s. 25. O Blu-ray transfere dados a 4,5 MB/s e tem uma capacidade de 25 GB. Quanto tempo leva para ler um disco inteiro? 26. Um fabricante anuncia que seu terminal de mapas de bits de cor pode exibir 224 cores diferentes. Porém, o hardware só tem 1 byte para cada pixel. Como é possível fazer isso? 27. ocê faz parte de uma equipe científica internacio- nal ultrassecreta, que acabou de receber a tarefa de estudar um ser chamado Herb, um extraterrestre do Planeta 10 que chegou recentemente aqui na Terra. Herb lhe deu a seguinte informação sobre como funcionam seus olhos: seu campo visual consiste em cerca de 108 pixels. Cada pixel é basicamente uma sobreposição de cinco “cores” (ou seja, infraver- melho, vermelho, verde, azul e ultravioleta), cada um com 32 intensidades. A resolução de tempo do campo visual de Herb é de 10 ms. Calcule a taxa de dados, em GB/s, dos olhos de Herb. 28. Um terminal de mapa de bits tem um monitor de 1.920 × 1.080. Ele é redesenhado 75 vezes por segundo. Qual é a duração do pulso correspondente a um pixel? 29. Usando certa fonte, uma impressora monocromáti- ca a laser pode imprimir 50 linhas de 80 caracteres por página. O caractere médio ocupa um quadrado de 2 mm × 2 mm, dos quais cerca de 25% é toner. O resto é branco. A camada de toner tem 25 micra de espessura. O cartucho de toner da impressora mede 25 × 8 × 2 cm. Quantas páginas podem ser impres- sas com um cartucho de toner? 30. A Hi-Fi Modem Company acabou de projetar um novo modem de modulação em frequência que usa 64 frequências em vez de apenas 2. Cada segundo é dividido em n intervalos de tempo iguais, cada um deles contendo um dos 64 tons possíveis. Quantos bits por segundo esse modem pode transmitir usando transmissão síncrona?
  • 133. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 114 31. Um usuário de nternet contratou um serviço ADSL de 2 Mbps. O vizinho dele preferiu um serviço por cabo que tem uma largura de banda compartilhada de 12 MHz. O esquema de modulação em uso é QAM-64. Há n residências ligadas ao cabo, cada uma com um computador. Uma fração f desses compu- tadores está on-line a qualquer dado instante. Sob quais condições o usuário do cabo obterá melhor serviço do que o usuário ADSL? 32. Uma câmera digital tem uma resolução de 3.000 × 2.000 pixels, com 3 bytes/pixel para cor RGB. O fabri- cante da câmera quer gravar uma imagem JPEG a um fator de compressão de 5x na memória rápida em 2s. Qual é a taxa de dados necessária? 33. Uma câmera digital de primeira linha tem um sen- sor com 24 milhões de pixels, cada qual com 6 bytes/pixel. Quantas fotos podem ser armazenadas em um cartão de memória rápida de 8 GB se o fator de compressão for 5x? Suponha que 1 GB signifique 230 bytes. 34. Estime quantos caracteres, incluindo espaços, con- tém um livro típico sobre ciência da computação. Quantos bits são necessários para codificar um livro em ASC com paridade? Quantos CD-ROMs são necessários para armazenar uma biblioteca de ciência da computação com 10 mil livros? Quantos DDs de dupla face, dupla camada, são necessários para a mesma biblioteca? 35. Escreva um procedimento hamming (ascii, encoded) para converter os 7 bits de baixa ordem de ascii em uma palavra de código de 11 bits armazenada em encoded. 36. Escreva uma função distance (code, n, k) que recebe uma matriz code de n caracteres de k bits cada como entrada e retorna a distância do conjunto de carac- teres como saída.
  • 134. N a parte inferior da hierarquia da Figura 1.2 encontramos o nível lógico digital, o real hardware do computador. Neste capítulo, examinaremos muitos aspectos da lógica digital, como um fundamento para o estudo de níveis mais altos em capítulos subsequentes. Esse assunto está no limiar entre a ciência da computação e a engenharia elétrica, mas o material é independente, portanto, não há necessidade de experiência prévia de hardware nem de engenharia para entendê-lo. Os elementos básicos que fazem parte de todos os computadores digitais são surpreendentemente simples. niciaremos nosso estudo examinando esses elementos básicos e também a álgebra especial de dois valores (álge- bra booleana) usada para analisá-los. Em seguida, examinaremos alguns circuitos fundamentais que podem ser construídos usando simples combinações de portas, entre eles os circuitos que efetuam a aritmética. O tópico que vem depois desse é o modo como essas portas podem ser combinadas para armazenar informações, isto é, como as memórias são organizadas. Logo após, chegamos à questão das CPUs e, em especial, de como é a interface entre CPUs de um só chip, a memória e os dispositivos periféricos. Mais adiante neste capítulo serão estudados diversos exemplos da indústria de computadores. 3.1 Portas e a lgebra booleana Circuitos digitais podem ser construídos com um pequeno número de elementos primitivos combinando-os de inúmeras maneiras. Nas seções seguintes, descreveremos tais elementos, mostraremos como eles podem ser com- binados e introduziremos uma poderosa técnica matemática que pode ser usada para analisar seu comportamento. O n vel lo gico digital 3 Cap tulo
  • 135. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 116 3.1.1 Portas Um circuito digital é aquele em que estão presentes somente dois valores lógicos. O normal é que um sinal entre 0 e 0,5 volt represente um valor (por exemplo, 0 binário) e um sinal entre 1 e 1,5 volt represente o outro valor (por exemplo, 1 binário). Não são permitidas tensões fora dessas duas faixas. Minúsculos dispositivos ele- trônicos, denominados portas (gates), podem calcular várias funções desses sinais de dois valores. Essas portas formam a base do hardware sobre a qual todos os computadores digitais são construídos. Os detalhes do funcionamento interno das portas estão fora do escopo deste livro, pois pertencem ao nível de dispositivo, que está abaixo do nível 0. Não obstante, agora vamos divagar um pouco e examinar rapidamente a ideia básica, que não é difícil. No fundo, toda a lógica digital moderna se apoia no fato de que um transistor pode funcionar como um comutador binário muito rápido. Na Figura 3.1(a), mostramos um transistor bipolar (repre- sentado pelo círculo) inserido em um circuito simples. Esse transistor tem três conexões com o mundo exterior: o coletor, a base e o emissor. Quando a voltagem de entrada, Vin, está abaixo de certo valor crítico, o transistor desliga e age como uma resistência infinita. sso faz com que a saída do circuito, Vout, assuma um valor próximo a Vcc, uma voltagem regulada externamente, em geral +1,5 volt para esse tipo de transistor. Quando Vin excede o valor crítico, o transistor liga e age como um fio, fazendo Vout ficar conectado com a terra (por convenção, 0 volt). O importante é notar que, quando Vin é baixa, Vout é alta, e vice-versa. Assim, esse circuito é um inversor, que converte um 0 lógico em um 1 lógico e um 1 lógico em um 0 lógico. O resistor (linha serrilhada) é necessário para limitar a quantidade de corrente drenada pelo transistor, de modo que ele não queime. O tempo típico exigido para passar de um estado para outro é tipicamente de um nanossegundo ou menos. Na Figura 3.1(b), dois transistores estão ligados em série. Se ambas, V1 e V2, forem altas, ambos os transisto- res conduzirão e Vout cairá. Se qualquer das entradas for baixa, o transistor correspondente se desligará e a saída será alta. Em outras palavras, Vout será baixa se, e somente se, ambas, V1 e V2, forem altas. Na Figura 3.1(c), os dois transistores estão ligados em paralelo em vez de em série. Nessa configuração, se qualquer das entradas for alta, o transistor correspondente ligará e conectará a saída com a terra. Se ambas as entradas forem baixas, a saída permanecerá alta. Esses três circuitos, ou seus equivalentes, formam as três portas mais simples e são denominadas portas not, nand e nor, respectivamente. Portas not costumam ser denominadas inversoras; usaremos os dois termos indiferentemente. Se agora adotarmos a convenção de que “alta” (Vcc volts) é um 1 lógico e “baixa” (terra) é um 0 lógico, podemos expressar o valor de saída como uma função dos valores de entrada. Os símbolos usados para representar essas portas são mostrados nas figuras 3.2(a)-(c) junto com o comportamento funcional de cada circuito. Nessas figuras, A e B são entradas e X é a saída. Cada linha especifica a saída para uma combinação diferente das entradas. Figura 3.1 (a) Inversor de transistor. (b) Porta nand. (c) Porta nor. Coletor +Vcc Vout Vin (a) Vout +Vcc +Vcc Vout V2 (b) V1 V1 (c) V2 Base Emissor
  • 136. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 117 Se o sinal de saída da Figura 3.1(b) for alimentado em um circuito inversor, obtemos outro circuito com o inverso exato da porta nand, a saber, um cuja saída é 1 se, e somente se, ambas as entradas forem 1. Esse circuito é denominado uma porta and; seu símbolo e descrição funcional são dados na Figura 3.2(d). De modo semelhante, a porta nor pode ser conectada a um inversor para produzir um circuito cuja saída é 1 se quaisquer das saídas, ou ambas, for um 1, mas 0 se ambas as entradas forem 0. O símbolo e a descrição funcional desse circuito, denominado uma porta or, são dados na Figura 3.2(e). Os pequenos círculos usados como parte dos símbolos para o inversor, porta nand e porta nor, são denominados bolhas de inversão. Também são usadas em outros contextos para indicar um sinal invertido. As cinco portas da Figura 3.2 são os principais elementos de construção do nível lógico digital. A discussão precedente deve ter deixado claro que as portas nand e nor requerem dois transistores cada, ao passo que as portas and e or requerem três cada. Por essa razão, muitos computadores são baseados em portas nand e nor em vez das portas mais conhecidas, and e or. (Na prática, todas as portas são executadas de modo um pouco diferente, mas as nand e nor ainda são mais simples do que as and e or.) A propósito, vale a pena observar que as portas podem perfeitamente ter mais de duas entradas. Em princípio, uma porta nand, por exemplo, pode ter, arbitrariamente, muitas entradas, mas na prática não é comum encontrar mais de oito. Embora a questão do modo como são construídas as portas pertença ao nível do dispositivo, gostaríamos de mencionar as principais famílias de tecnologia de fabricação porque elas são citadas com muita frequência. As duas tecnologias principais são bipolar e MOS (Metal Oxide Semiconductor – semicondutor de óxido metálico). Os dois principais tipos bipolares são a L (ransistor-ransistor Logic – lógica transistor-transistor), que há mui- tos anos é o burro de carga da eletrônica digital, e a ECL (Emitter-Coupled Logic – lógica de emissor acoplado), que era usada quando se requeria uma operação de velocidade muito alta. Para circuitos de computador, o que predomina agora é a tecnologia MOS. Portas MOS são mais lentas do que as TTL e ECL, mas exigem bem menos energia elétrica e ocupam um espaço muito menor, portanto, um grande número delas pode ser compactado e empacotado. Há muitas varieda- des de MOS, entre as quais PMOS, NMOS e CMOS. Embora os modos de construção dos transistores MOS e dos transistores bipolares sejam diferentes, sua capacidade de funcionar como comutadores eletrônicos é a mesma. A maioria das CPUs e memórias modernas usa tecnologia CMOS, que funciona a +1,5 volt. E isso é tudo o que diremos sobre o nível de dispositivo. O leitor interessado em continuar o estudo desse nível deve consultar as leituras sugeridas na Sala irtual. 3.1.2 A lgebra booleana Para descrever os circuitos que podem ser construídos combinando portas, é necessário um novo tipo de álgebra, no qual variáveis e funções podem assumir somente os valores 0 e 1. Essa álgebra é denominada álge- bra booleana, nome que se deve a seu descobridor, o matemático inglês George Boole (1815–1864). Em termos Figura 3.2 S mbolos e comportamento funcional das cinco portas ba sicas. (b) NAND A B X A B X 0 0 1 0 1 1 1 0 1 1 1 0 (c) NOR A B X A B X 0 0 1 0 1 0 1 0 0 1 1 0 AND A B X (d) A B X 0 0 0 0 1 0 1 0 0 1 1 1 OR A B X (e) A B X 0 0 0 0 1 1 1 0 1 1 1 1 (a) NOT A A X X 0 1 1 0
  • 137. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 118 estritos, estamos nos referindo a um tipo específico de álgebra booleana, uma álgebra de comutação, mas o termo “álgebra booleana” é tão utilizado no lugar de “álgebra de comutação” que não faremos a distinção. Assim como há funções na álgebra “ordinária” (isto é, a álgebra do colegial), também há funções na álge- bra booleana. Uma função booleana tem uma ou mais variáveis de entrada e produz um resultado que depende somente dos valores dessas variáveis. Uma função simples, f, pode ser definida ao se dizer que f(A) é 1 se A for 0 e f(A) é 0 se A for 1. Essa função é a função not da Figura 3.2(a). Como uma função booleana de n variáveis só tem 2n combinações possíveis de valores de entrada, ela pode ser completamente descrita por uma tabela com 2n linhas, na qual cada linha informa o valor da fun- ção para uma combinação diferente de valores de entrada. Ela é denominada tabela verdade. As tabelas da Figura 3.2 são todas exemplos de tabelas verdade. Se concordarmos em sempre listar as linhas de uma tabela verdade em ordem numérica (base 2), isto é, para duas variáveis na ordem 00, 01, 10 e 11, a função pode ser completamente descrita pelo número binário de 2n bits obtido pela leitura vertical da coluna de resultado da tabela verdade. Assim, nand é 1110, nor é 1000, and é 0001 e or é 0111. É óbvio que só existem 16 funções booleanas de duas variáveis, correspondentes às 16 possíveis sequências de 4 bits resultantes. Por outro lado, a álgebra ordinária tem um número infinito de funções de duas variáveis, nenhuma das quais pode ser des- crita por meio de uma tabela de saídas para todas as entradas possíveis, porque cada variável pode assumir qualquer valor de um número infinito de valores possíveis. A Figura 3.3(a) mostra a tabela verdade para uma função booleana de três variáveis: M = f(A, B, C). Essa fun- ção é a de lógica majoritária, isto é, ela é 0 se a maioria de suas entradas for 0, e 1 se a maioria de suas entradas for 1. Embora qualquer função booleana possa ser completamente especificada dada sua tabela verdade, à medida que aumenta o número de variáveis, essa notação fica cada vez mais trabalhosa. Portanto, costuma-se usar outra notação no lugar dela. Figura 3.3 (a) Tabela verdade para a func a o majorita ria de tre s varia veis. (b) Circuito para (a). A B C 0 0 0 0 0 1 0 1 0 0 1 1 M 0 0 0 1 1 0 0 1 0 1 1 1 0 1 1 1 0 1 1 1 (a) (b) ABC A A B C B C A A B C ABC ABC ABC M 1 4 8 5 6 7 B 2 C 3
  • 138. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 119 Para ver como ocorre essa outra notação, observe que qualquer função booleana pode ser especificada ao se dizer quais combinações de variáveis de entrada dão um valor de saída igual a 1. Para a função da Figura 3.3(a), há quatro combinações de variáveis de entrada que fazem com que M seja 1. Por convenção, marcaremos a variável de entrada com uma barra para indicar que seu valor é invertido. A ausência de uma barra significa que o valor não é invertido. Além disso, usaremos a multiplicação implícita ou um ponto para representar a função booleana AND e + para representar a função booleana OR. Assim, por exemplo, ABC assume o valor 1 somente quando A = 1 e B = 0 e C = 1. Além disso, AB + BC é 1 somente quando (A = 1 e B = 0) ou (B = 1 e C = 0). As quatro linhas da Figura 3.3(a) que produzem bits 1 na saída são: ABC, ABC, ABC e ABC. A função, M, é verdadeira (isto é, 1) se qualquer uma dessas quatro condições for verdadeira; daí, podemos escrever M = ABC + ABC + ABC + ABC como um modo compacto de dar a tabela verdade. Assim, uma função de n variáveis pode ser descrita como se desse uma “soma” de no máximo 2n termos de “produtos” de n variáveis. Essa formulação é de especial impor- tância, como veremos em breve, pois leva diretamente a uma execução da função que usa portas padronizadas. É importante ter em mente a distinção entre uma função booleana abstrata e sua execução por um circuito eletrônico. Uma função booleana consiste em variáveis, como A, B e C, e operadores booleanos, como AND, OR e NOT. Ela é descrita por uma tabela verdade ou por uma função booleana como F = ABC + ABC Uma função booleana pode ser executada por um circuito eletrônico (muitas vezes de vários modos diferentes) usando sinais que representam as variáveis de entrada e saída e portas como and, or e not. Em geral, empregaremos a notação AND, OR e NOT quando nos referirmos aos operadores booleanos, e and, or e not quando nos referirmos a portas, embora essa notação quase sempre seja ambígua em se tratando de indicar funções ou portas. 3.1.3 Execuc a o de func o es booleanas Como já mencionamos, a formulação de uma função booleana como uma soma de até 2n termos produtos leva a uma possível implementação. Usando a Figura 3.3 como exemplo, podemos ver como essa implementação é efetuada. Na Figura 3.3(b), as entradas, A, B e C, aparecem na extremidade esquerda, e a função de saída, M, na extremidade direita. Como são necessários complementos (inversos) das variáveis de entrada, eles são gerados tomando as entradas e passando-as pelos inversores rotulados 1, 2 e 3. Para evitar atravancar a figura, desenhamos seis linhas verticais, três das quais conectadas às variáveis de entrada e três aos complementos dessas variáveis. Tais linhas oferecem uma fonte conveniente para as entradas das portas subsequentes. Por exemplo, as portas 5, 6 e 7 usam A como uma entrada. Em um circuito real, essas portas provavelmente estariam ligadas direto a A sem usar nenhum fio “vertical” intermediário. O circuito contém quatro portas and, uma para cada termo da equação para M (isto é, uma para cada linha da tabela verdade que tenha um bit 1 na coluna de resultado). Cada porta and calcula uma linha da tabela verda- de, como indicado. Por fim, todos os termos produtos alimentam a porta lógica or para obter o resultado final. O circuito da Figura 3.3(b) usa uma convenção que utilizaremos repetidas vezes neste livro: quando duas linhas se cruzam, não há nenhuma ligação implícita a menos que haja um ponto negro bem visível na intersecção. Por exemplo, a saída da porta 3 cruza todas as seis linhas verticais, mas está ligada apenas a C. É bom lembrar que alguns autores usam outras convenções. Pelo exemplo da Figura 3.3 deve ficar claro como colocar em prática um circuito para qualquer função booleana: 1. Escreva a tabela verdade para a função. 2. Providencie inversores para gerar o complemento de cada entrada. 3. Desenhe uma porta and para cada termo que tenha um 1 na coluna de resultado. 4. Ligue as portas and às entradas adequadas. 5. Alimente a saída de todas as portas and a uma porta or.
  • 139. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 120 Embora tenhamos mostrado como qualquer função booleana pode ser executada usando portas not, and e or, muitas vezes é conveniente realizar circuitos usando só um tipo de porta. Felizmente, converter circuitos gera- dos pelo algoritmo precedente à forma nand pura ou nor pura é uma operação direta. Para fazer essa conversão, basta que tenhamos um modo de implementar not, and e or usando um único tipo de porta. A linha superior da Figura 3.4 mostra como todas essas três podem ser implementadas usando apenas portas nand; a fileira de baixo mostra como isso pode ser feito usando apenas portas nor. (Essas operações são diretas, mas também há outras maneiras.) Um modo de implementar uma função booleana usando somente portas nand ou somente portas nor é primeiro seguir o procedimento dado anteriormente para construí-la com not, and e or. Em seguida, substi- tuir as portas de múltiplas entradas por circuitos equivalentes usando portas de duas entradas. Por exemplo, A + B + C + D pode ser computada como (A + B) + (C + D), empregando três portas or de duas entradas. Por fim, as portas not, and e or são substituídas pelos circuitos da Figura 3.4. Figura 3.4 Construc a o de portas (a) not, (b) and e (c) or usando somente portas nand ou somente portas nor. A + B A + B A A B B AB AB A A A A (a) (b) (c) A B A B Embora esse procedimento não resulte em circuitos ótimos, no sentido do número mínimo de portas, ele mostra que sempre há uma solução viável. Ambas as portas, nand e nor, são denominadas completas porque qual- quer função booleana pode ser calculada usando quaisquer das duas. Nenhuma outra porta tem essa propriedade, o que é outra razão para elas serem preferidas como blocos de construção de circuitos. 3.1.4 Equivale ncia de circuito Projetistas de circuitos muitas vezes tentam reduzir o número de portas em seus produtos para reduzir a área da placa de circuito interno necessária para executá-las, diminuir o consumo de potência e aumentar a velocidade. Para reduzir a complexidade de um circuito, o projetista tem de encontrar outro circuito que calcule a mesma função que o original, mas efetue essa operação com um número menor de portas (ou talvez com portas mais
  • 140. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 121 simples, por exemplo, com duas em vez de com quatro entradas). A álgebra booleana pode ser uma ferramenta valiosa na busca de circuitos equivalentes. Como exemplo de como a álgebra booleana pode ser usada, considere o circuito e a tabela verdade para AB + AC mostrados na Figura 3.5(a). Embora ainda não as tenhamos discutido, muitas das regras da álgebra comum também são válidas para a booleana. Em particular, a expressão AB + AC pode ser fatorada para A(B + C) usando a lei distributiva. A Figura 3.5(b) mostra o circuito e a tabela verdade para A(B + C). Como duas funções são equivalentes se, e somente se, elas tiverem a mesma saída para todas as entradas possíveis, é fácil ver pelas tabe- las verdade da Figura 3.5 que A(B + C) é equivalente a AB + AC. Apesar dessa equivalência, o circuito da Figura 3.5(b) é claramente melhor do que o da Figura 3.5(a), pois contém menos portas. Figura 3.5 Duas func o es equivalentes. (a) AB + AC. (b) A(B + C). C B A A(B + C) B + C A B C AB + AC AB AC (a) (b) A B C AB AC AB + AC 0 0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 1 0 1 0 1 1 1 1 0 1 0 1 1 1 1 1 1 1 A B C A B + C A(B + C) 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 1 0 0 1 1 0 1 0 1 0 0 1 0 0 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 Em geral, um projetista de circuitos começa com uma função booleana e depois aplica a ela as leis da álgebra booleana na tentativa de achar uma função mais simples, porém equivalente. Um circuito pode ser construído com base na função final. Para usar essa abordagem, precisamos de algumas identidades da álgebra booleana. A Figura 3.6 mostra algumas das mais importantes. É interessante notar que cada lei tem duas formas que são duais uma da outra. Permutando AND e OR e também 0 e 1, quaisquer das formas pode ser produzida com base na outra. Todas as leis podem ser provadas com facilidade construindo suas tabelas verdade. Com exceção da lei de De Morgan, a lei da absorção, e da forma AND da lei distributiva, os resultados são razoavelmente intuitivos. A lei de De Morgan pode ser estendida para mais de duas variáveis, por exemplo, ABC = A + B + C.
  • 141. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 122 Figura 3.6 Algumas identidades da a lgebra booleana. Nome Forma AND Forma OR Lei da identidade 1A = A 0 + A = A Lei do elemento nulo 0A = 0 1 + A = 1 Lei idempotente AA = A A + A = A Lei do inverso AA = 0 A + A = 1 Lei comutativa AB = BA A + B = B + A Lei associativa (AB)C = A(BC) (A + B) + C = A + (B + C) Lei distributiva A + BC = (A + B)(A + C) A(B + C) = AB + AC Lei da absorção A(A + B) = A A + AB = A Lei de De Morgan AB = A + B A + B = AB A lei de De Morgan sugere uma notação alternativa. Na Figura 3.7(a), a forma AND é mostrada com negação indicada por bolhas de inversão tanto para entrada quanto para saída. Assim, uma porta or com entradas inver- tidas é equivalente a uma porta nand. Pela Figura 3.7(b), a forma dual da lei de De Morgan, deve ficar claro que uma porta nor pode ser desenhada como uma porta and com entradas invertidas. Negando ambas as formas da lei de De Morgan, chegamos às figuras 3.7(c) e (d), que mostram representações equivalentes das portas and e or. Existem símbolos análogos para as formas de múltiplas variáveis da lei de De Morgan (por exemplo, uma porta nand com n entradas se torna uma porta or com entradas invertidas). Figura 3.7 S mbolos alternativos para algumas portas: (a) nand. (b) nor. (c) and. (d) or. (a) AB = A + B (c) A + B AB = (b) A + B = AB AB = (d) A + B Usando as identidades da Figura 3.7 e as análogas para portas de múltiplas entradas é fácil converter a repre- sentação de soma de produtos de uma tabela verdade para a forma nand pura ou nor pura. Como exemplo, con- sidere a função ECLUSE OR da Figura 3.8(a). O circuito padrão da soma de produtos é mostrado na Figura 3.8(b). Para converter para a forma nand, as linhas que conectam a saída das portas and à entrada da porta or devem ser redesenhadas com duas bolhas de inversão, conforme mostra a Figura 3.8(c). Por fim, usando a Figura 3.7(a), chegamos à Figura 3.8(d). As variáveis A e B podem ser geradas de A e B usando portas nand ou nor com suas entradas interligadas. Note que as bolhas de inversão podem ser deslocadas à vontade ao longo da linha, por exemplo, desde as saídas das portas de entrada na Figura 3.8(d) até as entradas da porta de saída.
  • 142. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 123 Figura 3.8 (a) Tabela verdade para a func a o XOR. (b)–(d) Tre s circuitos para calcular essa tabela. (a) (b) A B XOR 0 0 0 0 1 1 1 0 1 1 1 0 A B B A (d) (c) A B B A A B B A Como observação final em relação à equivalência de circuitos, demonstraremos agora o surpreendente resul- tado, isto é, a mesma porta física pode calcular funções diferentes dependendo das convenções usadas. Na Figura 3.9(a), mostramos a saída de certa porta, F, para diferentes combinações de entrada. Tanto entradas quanto saídas são representadas por volts. Se adotarmos a convenção de que 0 volt é 0 lógico e 1,5 volt é 1 lógico, denomina- da lógica positiva, obtemos a tabela verdade da Figura 3.9(b), a função AND. Contudo, se adotarmos a lógica negativa, na qual 0 volt é 1 lógico e 1,5 volt é 0 lógico, obtemos a tabela verdade da Figura 3.9(c), a função or. Figura 3.9 (a) Caracter sticas ele tricas de um dispositivo. (b) Lo gica positiva. (c) Lo gica negativa. (a) A B 0V 0V 0V 5V 5V 0V 5V 5V F 0V 0V 0V 5V (b) A B 0 0 0 1 1 0 1 1 F 0 0 0 1 (c) A B 1 1 1 0 0 1 0 0 F 1 1 1 0 Assim, a convenção escolhida para mapear voltagens para valores lógicos é crítica. A menos que especifique- mos outra coisa, daqui em diante usaremos lógica positiva, portanto, os termos 1 lógico, verdade e tensão alta são sinônimos, assim como 0 lógico, falso e tensão baixa. 3.2 Circuitos lo gicos digitais ba sicos Nas seções anteriores vimos como executar tabelas verdade e outros circuitos simples usando portas indivi- duais. Na prática, poucos circuitos são construídos porta por porta, embora tenha havido uma época em que isso era comum. Hoje, os blocos de construção mais comuns são módulos que contêm várias portas. Nas próximas seções, examinaremos esses blocos de construção mais de perto e veremos como eles podem ser construídos com base em portas individuais.
  • 143. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 124 3.2.1 Circuitos integrados Portas não são fabricadas nem vendidas individualmente, mas em unidades denominadas circuitos inte- grados, muitas vezes denominados ICs ou chips. Um C é um pedaço quadrado de silício de tamanho variado, dependendo de quantas portas são necessárias para executar os componentes do chip. Substratos pequenos medi- rão cerca de 2 × 2 mm, enquanto os maiores podem ter até 18 × 18 mm. Cs costumam ser montados em pacotes retangulares de plástico ou cerâmica, que podem ser muito maiores que os substratos que eles abrigam, se forem necessários muitos pinos para conectar o chip ao mundo exterior. Cada pino se conecta com a entrada ou saída de alguma porta no chip ou à fonte de energia, ou ao terra. A Figura 3.10 mostra uma série de pacotes de C comuns, usados para os chips de hoje. Chips menores, como os usados para microcontroladores domésticos ou chips de RAM, usarão pacotes duplos em linha (IPs  ual Inline Packages). Um DP é um pacote com duas fileiras de pinos que se encaixam em um soquete correspondente na placa-mãe. Os pacotes mais comuns têm 14, 16, 18, 20, 22, 24, 28, 40, 64 ou 68 pinos. Para chips grandes costumam ser usados pacotes quadrados com pinos nos quatro lados ou na parte de baixo. Dois pacotes comuns para chips maiores são Pin Grid rrays, ou PGs, e Land Grid rrays, ou LGs. PGAs possuem pinos na parte inferior do pacote, que se encaixam em um soquete correspondente na placa-mãe. Soquetes PGA normalmente utilizam um mecanismo com força de inserção nula, onde uma alavanca aplica pressão lateral sobre todos os pinos do PGA, mantendo-o firmemente no soquete PGA. LGAs, por outro lado, possuem pequenas plataformas planas na parte inferior do chip, e um soquete LGA terá uma capa que se encaixa sobre o LGA e aplica uma força para baixo no chip, garantindo que todas as plataformas do LGA façam contato com as plataformas do soquete LGA. Figura 3.10 Tipos comuns de pacotes de circuito integrado, incluindo um pacote dual-in-line, ou DIP (a), PGA (b) e LGA (c). (c) (b) (a) Como muitos pacotes de C têm forma simétrica, descobrir a orientação correta é um problema constante com a instalação de C. DPs normalmente têm um entalhe em uma ponta, que combina com uma marca corres- ponde no soquete DP. PGAs, em geral, possuem um pino faltando, de modo que, se você tentar inserir o PGA no soquete incorretamente, o PGA não se encaixará. Como os LGAs não possuem pinos, a instalação correta é imposta colocando-se um entalhe em um ou dois lados do LGA, que corresponde a um entalhe no soquete LGA. O LGA não entrará no soquete a menos que os dois entalhes combinem. Para todos os efeitos, todas as portas são ideais no sentido de que a saída aparece logo que a entrada é apli- cada. Na realidade, os chips têm um atraso de porta finito que inclui o tempo de propagação de sinal pelo chip e o tempo de comutação. Atrasos típicos são de centésimos de picossegundos a alguns nanossegundos. A tecnologia moderna vigente permite colocar mais de 1 bilhão de transistores em um chip. Como qualquer circuito pode ser construído com base em portas nand, você bem poderia imaginar que um fabricante poderia produzir um chip muito geral que contivesse 500 milhões de portas nand. nfelizmente, um chip como esse neces- sitaria de 1.500.000.002 pinos. Como o espaço-padrão entre pinos é 1 milímetro, um chip LGA teria 38 metros de comprimento para acomodar todos esses pinos, o que talvez tivesse um efeito negativo sobre as vendas. É claro que a única maneira de tirar proveito da tecnologia é projetar circuitos com uma alta relação porta/pino.
  • 144. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 125 Nas seções seguintes vamos examinar circuitos simples que combinam uma quantidade de portas internamente para fornecer uma função útil que requer apenas um número limitado de conexões externas (pinos). 3.2.2 Circuitos combinato rios Muitas aplicações de lógica digital requerem um circuito com múltiplas entradas e múltiplas saídas, no qual as saídas são determinadas exclusivamente pelas entradas em questão. Esses circuitos são denominados circuitos combinatórios. Nem todos os circuitos têm essa propriedade. Por exemplo, um circuito que contenha elementos de memória pode perfeitamente gerar saídas que dependem de valores armazenados, bem como de variáveis de entrada. Um circuito que esteja executando uma tabela verdade como a da Figura 3.3(a) é um exemplo típico de um circuito combinatório. Nesta seção, examinaremos alguns circuitos combinatórios de uso frequente. Multiplexadores No nível lógico, um multiplexador é um circuito com 2n entradas de dados, uma saída de dados e n entradas de controle que selecionam uma das entradas de dados. Essa entrada selecionada é dirigida (isto é, roteada) até a saída. A Figura 3.11 é um diagrama esquemático de um multiplexador de oito entradas. As três linhas de controle, A, B e C, codificam um número de 3 bits que especifica qual das oito linhas de entrada é direcionada até a porta or e dali até a saída. Não importa qual valor esteja nas linhas de controle, sete das portas and sempre produzirão saída 0; a outra pode produzir ou um 0 ou um 1, dependendo do valor da linha de entrada selecionada. Cada porta and é habilitada por uma combinação diferente das entradas de controle. O circuito do multiplexador é mostrado na Figura 3.11. Figura 3.11 Circuito multiplexador de oito entradas. F D0 D1 D2 D3 D4 D5 D6 D7 A B C A A B C B C
  • 145. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 126 Usando o multiplexador, podemos executar a função majoritária da Figura 3.3(a), como mostrado na Figura 3.12(b). Para cada combinação de A, B e C, uma das linhas de dados é selecionada. Cada entrada é ligada ou a Vcc (1 lógico) ou ao terra (0 lógico). O algoritmo para ligar as entradas é simples: a entrada Di é a que tem o mesmo valor da linha i da tabela verdade. Na Figura 3.3(a), as linhas 0, 1, 2 e 4 são 0, portanto, as entradas correspon- dentes estão aterradas; as linhas restantes são 1, portanto, estão ligadas a 1 lógico. Dessa maneira, qualquer tabela verdade de três variáveis pode ser executada usando o chip da Figura 3.12(a). Figura 3.12 (a) Multiplexador com oito entradas. (b) O mesmo multiplexador ligado para calcular a func a o majorita ria. (a) A B C F D0 D1 D2 D3 D4 D5 D6 D7 (b) VCC A B C F D0 D1 D2 D3 D4 D5 D6 D7 Acabamos de ver como um chip multiplexador pode ser usado para selecionar uma das diversas entradas e como ele pode implementar uma tabela verdade. Outra de suas muitas aplicações é como um conversor de dados paralelo para serial. Colocando 8 bits de dados nas linhas de entrada e então escalonando as linhas em sequência de 000 a 111 (binário), os 8 bits são colocados em série na linha de saída. Uma utilização típica da conversão paralela para serial é um teclado, onde cada acionamento de uma tecla define implicitamente um número de 7 ou 8 bits que deve ser enviado por um enlace serial, como USB. O inverso de um multiplexador é um demultiplexador, que dirige sua única entrada até uma das 2n saídas, dependendo dos valores das n linhas de controle. Se o valor binário das linhas de controle for k, é selecionada a saída k. Decodificadores Como um segundo exemplo, agora vamos examinar um circuito que toma um número de n bits como entra- da e o usa para selecionar (isto é, definir em 1) exatamente uma das 2n linhas de saída. Tal circuito, ilustrado para n = 3 na Figura 3.13, é denominado decodificador. Para ver como um decodificador pode ser útil, imagine uma pequena memória que consiste em oito chips, cada um contendo 256 MB. O chip 0 tem endereços de 0 a 256 MB, o chip 1 tem endereços de 256 MB a 512 MB e assim por diante. Quando um endereço é apresentado à memória, os 3 bits de ordem alta são usados para selecionar um dos oito chips. Usando o circuito da Figura 3.13, esses 3 bits são as três entradas, A, B e C. Dependendo das entradas, exatamente uma das oito linhas de saída, D0, ..., D7, é 1; o resto é 0. Cada linha de saída habilita um dos oito chips de memória. Como só uma linha de saída é colocada em 1, apenas um chip é habilitado.
  • 146. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 127 A operação do circuito da Figura 3.13 é direta. Cada porta and tem três entradas, das quais a primeira é A ou A, a segunda é B ou B e a terceira é C ou C. Cada porta é habilitada por uma combinação diferente de entradas: D0 por A B C, D1 por A B C, e assim por diante. Figura 3.13 Circuito decodificador 3 para 8. D0 D1 D2 D3 D4 D5 D6 D7 A C B A B C B C A Comparadores Outro circuito útil é o comparador, que compara duas palavras de entrada. O comparador simples da Figura 3.14 toma duas entradas, A e B, cada uma de 4 bits de comprimento, e produz um 1 se elas forem iguais e um 0 se elas não o forem. O circuito é baseado na porta OR (ECLUSE OR), que produz um 0 se suas entradas forem iguais e um 1 se elas forem diferentes. Se as duas palavras de entrada forem iguais, todas as quatro portas xor devem produzir 0. Então, pode-se efetuar uma operação OR nesses quatro sinais; se o resultado for 0, as palavras de entrada são iguais; caso contrário, não. Em nosso exemplo, usamos uma porta nor como o estágio final para reverter o sentido do teste: 1 significa igual, 0 significa diferente. 3.2.3 Circuitos aritme ticos Chegou a hora de passar dos circuitos de uso geral discutidos anteriormente para circuitos combinatórios usados para operações aritméticas. Começaremos com um simples deslocador de 8 bits e em seguida veremos como são construídos os somadores e, por fim, estudaremos as unidades de lógica e aritmética, que desempenham um papel fundamental em qualquer computador.
  • 147. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 128 Figura 3.14 Comparador simples de 4 bits. A = B A0 B0 A1 B1 A2 B2 A3 B3 porta EXCLUSIVE OR Deslocadores Nosso primeiro circuito aritmético é um deslocador de oito entradas e oito saídas (veja a Figura 3.15). Oito bits de entrada são apresentados nas linhas D0, ..., D7. A saída, que é apenas a entrada deslocada de 1 bit, está nas linhas S0, ..., S7. A linha de controle, C, determina a direção do deslocamento, 0 para a esquerda e 1 para a direita. Quando o deslocamento for para a esquerda, um 0 é inserido no bit 7. De modo semelhante, quando o deslocamento for para a direita, um 1 é inserido no bit 0. Figura 3.15 Deslocador esquerda/direita de 1 bit. C D0 D1 D2 D3 D4 D5 D6 D7 S0 S1 S2 S3 S4 S5 S6 S7
  • 148. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 129 Para ver como o circuito funciona, observe os pares de portas and para todos os bits, exceto as portas na extremidade. Quando C = 1, o membro da direita de cada par é ligado, passando o bit de entrada correspondente para a saída. Como a porta and da direita está ligada à entrada da porta or à sua direita, é executado um deslo- camento para a direita. Quando C = 0, o membro da esquerda do par da porta and é ligado, o que provoca um deslocamento para a esquerda. Somadores Um computador que não possa somar números inteiros é quase inimaginável. Por consequência, um circuito de hardware para efetuar adição é uma parte essencial de toda CPU. A tabela verdade para adição de inteiros de 1 bit é mostrada na Figura 3.16(a). Há duas saídas presentes: a soma das entradas, A e B, e o transporte (vai-um) para a posição seguinte (à esquerda). Um circuito para calcular o bit de soma e o de transporte é ilustrado na Figura 3.16(b). Esse circuito simples é conhecido como um meio-somador. Figura 3.16 (a) Tabela verdade para adic a o de 1 bit. (b) Circuito para um meio-somador. A B Soma Transporte A B 0 0 0 0 0 1 1 0 1 0 1 0 1 1 0 1 Porta EXCLUSIVE OR Soma Transporte Embora um meio-somador seja adequado para somar os bits de ordem baixa de duas palavras de entrada de múltiplos bits, ele não servirá para uma posição de bit no meio da palavra porque não trata o transporte de bit da posição à direita (vem-um). Em seu lugar, precisamos do somador completo da Figura 3.17. Pela inspeção do circuito, deve ficar claro que um somador completo é composto de dois meios-somadores. A linha de saída Soma é 1 se um número ímpar A, B e o vem-um (carry in) forem 1. O vai-um (carry out) é 1 se A e B forem ambos 1 (entrada esquerda para a porta or) ou se exatamente um deles for 1 e o bit de vem-um (carry in) também é 1. Juntos, os dois meios-somadores geram a soma e também os bits de transporte. Para construir um somador para palavras de 16 bits, por exemplo, basta repetir o circuito da Figura 3.17(b) 16 vezes. O vai-um de um bit é usado como vem-um para seu vizinho da esquerda. O vem-um do bit da extrema direita está ligado a 0. Esse tipo de somador é denominado somador de transporte encadeado porque, na pior das hipóteses, somando 1 a 111...111 (binário), a adição não pode ser concluída até que o vai-um tenha percorrido todo o caminho do bit da extrema direita até o da extrema esquerda. Também existem somadores que não têm esse atraso e, portanto, são mais rápidos – em geral, são os preferidos. Como exemplo simples de um somador mais rápido, considere subdividir um somador de 32 bits em uma metade inferior e uma metade superior de 16 bits cada. Quando a adição começa, o somador superior ainda não pode trabalhar porque não sabe qual é o vem-um por 16 tempos de adição.
  • 149. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 130 Figura 3.17 (a) Tabela verdade para somador completo. (b) Circuito para um somador completo. A B 0 0 0 0 0 1 1 0 1 0 1 0 1 0 0 0 0 1 0 1 0 0 1 0 0 1 0 1 1 0 0 1 1 1 1 1 1 1 1 1 (a) (b) Vai-um A B Vem- Soma Vai- -um -um Vem-um Soma Contudo, considere essa modificação no circuito. Em vez de uma única metade superior, vamos dar ao somador duas metades superiores em paralelo duplicando o hardware da metade superior. Desse modo, agora o circuito consiste em três somadores de 16 bits: uma metade inferior e duas metades superiores, U0 e U1 que funcionam em paralelo. Um 0 é alimentado em U0 como vai-um; um 1 é alimentado em U1 como vai-um. Agora, ambos podem iniciar ao mesmo tempo do que a metade inferior, mas somente um estará correto. Após 16 tempos de adição de bits, já se saberá qual é o vem-um que deve ir para a metade superior, portanto, agora já se pode selecionar a metade superior correta com base em duas respostas disponíveis. Esse estratagema reduz o tempo de adição por um fator de dois. Um somador como esse é denominado somador de seleção de transporte. Então, o estratagema pode ser repetido para construir cada somador de 16 bits com base em somadores de 8 bits repetidos e assim por diante. Unidades lo gica e aritme tica Grande parte dos computadores contém um único circuito para efetuar and, or e soma de duas palavras de máquina. No caso típico, tal circuito para palavras de n bits é composto de n circuitos idênticos para as posições individuais de bits. A Figura 3.18 é um exemplo simples de um circuito desses, denominado uni- dade lógica e aritmética (UL) (rithmetic Logic Unit  LU). Ela pode calcular qualquer uma das quatro funções – a saber, A and B, A or B, B ou A + B, dependendo de as linhas de entrada de seleção de função F0 e F1 conterem 00, 01, 10 ou 11 (binário). Note que, aqui, A + B significa a soma aritmética de A e B, e não a operação booleana or. O canto inferior esquerdo de nossa ULA contém um decodificador de 2 bits para gerar sinais de enable (habilitação) para as quatro operações, com base nos sinais de controle F0 e F1. Dependendo dos valores de F0 e F1, exatamente uma das quatro linhas de habilitação é selecionada. Ativar essa linha permite que a saída para a função selecionada passe por ela até a porta OR final, para saída. O canto superior esquerdo contém a lógica para calcular A and B, A or, B e B, mas no máximo um desses resultados é passado para a porta or final, dependendo das linhas de habilitação que saem do decodificador. Como exatamente uma das saídas do decodificador será 1, exatamente uma das quatro portas and que comandam a porta or será habilitada; as outras três resultarão em 0, independente de A e B.
  • 150. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 131 Figura 3.18 ULA de 1 bit. Vai-um A INVA ENA B AB B F0 F1 A + B ENB Unidade lógica Vem-um Saída Soma Linhas de enable Somador completo Decodificador Além de poder usar A e B como entradas para operações lógicas ou aritméticas, também é possível for- çar quaisquer delas para 0 negando ena ou enb, respectivamente. Também é possível obter A ativando inva. eremos utilizações para inva, ena e enb no Capítulo 4. Em condições normais, ena e enb são ambas 1 para habilitar ambas as entradas e inva é 0. Nesse caso, A e B são apenas alimentados na unidade lógica, sem modificação. O canto direito inferior da ULA contém um somador completo para calcular a soma de A e B, incluindo manipulação de transportes (vai-um e vem-um), porque é provável que, em seu devido tempo, vários desses circuitos serão ligados juntos para efetuar operações de palavra inteira. Na verdade, existem circuitos como o da Figura 3.18 que são conhecidos como segmentos de bits (bit slices). Eles permitem que o projetista do computa- dor monte uma ULA da largura que quiser. A Figura 3.19 mostra uma ULA de 8 bits montada com 8 segmentos (slices) de ULA de 1 bit. O sinal inc só é útil para operações de adição. Quando presente, aumenta o resultado (isto é, soma 1 a ele), possibilitando o cálculo de somas como A + 1 e A + B + 1. Anos atrás, um segmento de bit era na verdade um chip que você podia comprar. Hoje, é mais como uma biblioteca que um projetista de chip pode replicar quantas vezes quiser em um programa projeto-auxiliado-por- -computador produzindo um arquivo de saída que direciona as máquinas de produção de chips. Mas a ideia, na essência, é a mesma.
  • 151. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 132 Figura 3.19 Oito segmentos (slices) de ULA de 1 bit conectados para formar uma ULA de 8 bits. Os sinais de habilitac a o e inversa o na o sa o mostrados por simplicidade. F0 F1 A7 B7 O7 A6 B6 O6 A5 B5 O5 A4 B4 O4 A3 B3 O3 A2 B2 O2 A1 B1 O1 INC A0 B0 O0 ULA de 1 bit ULA de 1 bit ULA de 1 bit ULA de 1 bit ULA de 1 bit ULA de 1 bit ULA de 1 bit ULA de 1 bit Vem-um Vai-um 3.2.4 Clocks Em muitos circuitos digitais, a ordem em que os eventos ocorrem é crítica. Às vezes um evento deve preceder outro, às vezes dois eventos devem ocorrer simultaneamente. Para permitir que os projetistas consigam as rela- ções de temporização requeridas, muitos circuitos digitais usam clocks para prover sincronização. Nesse contexto, um clock é um circuito que emite uma série de pulsos com uma largura de pulso precisa e intervalos precisos entre pulsos consecutivos. O intervalo de tempo entre as arestas correspondentes de dois pulsos consecutivos é denominado tempo de ciclo de clock. Em geral, as frequências de pulso estão entre 100 MHz e 4 GHz, corres- pondendo a ciclos de clock de 10 nanossegundos a 250 picossegundos. Para conseguir alta precisão, a frequência de clock normalmente é controlada por um oscilador de cristal. Muitos eventos podem ocorrer dentro de um computador durante um único ciclo de clock. Se eles devem ocorrer em uma ordem específica, o ciclo de clock deve ser dividido em subciclos. Uma maneira comum de prover resolução superior à do clock básico é aproveitar a linha de clock primária e inserir um circuito com um atraso conhecido, gerando assim um sinal de clock secundário deslocado em certa fase em relação ao primeiro, confor- me mostra a Figura 3.20(a). O diagrama de temporização da Figura 3.20(b) dá quatro referências de tempo para eventos discretos: 1. Fase ascendente de C1. 2. Fase descendente de C1. 3. Fase ascendente de C2. 4. Fase descendente de C2. inculando diferentes eventos às várias fases, pode-se conseguir a sequência requerida. Se forem necessárias mais do que quatro referências de tempo dentro de um ciclo de clock, podem-se puxar mais linhas da linha pri- mária, com diferentes atrasos, se for preciso. Em alguns circuitos, estamos interessados em intervalos de tempo em vez de instantes discretos de tempo. Por exemplo, pode-se permitir que algum evento aconteça toda vez que C1 estiver alto, em vez de exatamente na fase ascendente. Outro evento só poderá acontecer quando C2 estiver alto. Se forem necessários mais de dois intervalos diferentes, podem ser instaladas mais linhas de clock ou pode-se fazer com que os estados altos dos dois clocks se sobreponham parcialmente no tempo. No último caso, podem-se distinguir quatro intervalos distintos: C1 and C2, C1 and C2, C1 and C2 e C1 and C2. A propósito, clocks são simétricos, com o tempo gasto no estado alto igual ao tempo gasto no estado baixo, como mostra a Figura 3.20(b). Para gerar um trem de pulsos assimétrico, o clock básico é deslocado usando um circuito de atraso e efetuando uma operação AND com o sinal original, como mostra a Figura 3.20(c) como C.
  • 152. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 133 Figura 3.20 (a) Um clock. (b) Diagrama de temporizac a o para o clock. (c) Gerac a o de um clock assime trico. C1 C2 (a) (b) A B C (c) Atraso 3.3 Memo ria Um componente essencial de todo computador é sua memória. Sem ela não poderiam existir os computa- dores que conhecemos. A memória é usada para armazenar instruções a serem executadas e dados. Nas seções seguintes examinaremos os componentes básicos de um sistema de memória começando no nível da porta para ver como eles funcionam e como são combinados para produzir memórias de grande porte. 3.3.1 Memo rias de 1 bit Para criar uma memória de 1 bit (“latch”), precisamos de um circuito que “se lembre”, de algum modo, de valores de entrada anteriores. Tal circuito pode ser construído com base em duas portas nor, como ilustrado na Figura 3.21(a). Circuitos análogos podem ser construídos com portas nand, porém, não vamos mais mencioná-los porque são conceitualmente idênticos às versões nor. O circuito da Figura 3.21(a) é denominado latch SR. Ele tem duas entradas, S, para ativar (setting) o latch, e R, para restaurá-lo (resetting), isto é, liberá-lo. O circuito também tem duas saídas, Q e Q, que são complemen- tares, como veremos em breve. Ao contrário de um circuito combinacional, as saídas do latch não são exclusiva- mente determinadas pelas entradas atuais. Figura 3.21 (a) Latch nor no estado 0. (b) Latch nor no estado 1. (c) Tabela verdade para nor. A B NOR 0 0 1 0 1 0 1 0 0 1 1 0 R Q S 0 0 1 0 0 1 Q R Q S 0 1 0 0 1 0 Q (a) (b) (c)
  • 153. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 134 Para ver como isso ocorre, vamos supor que ambos, S e R, sejam 0, o que é verdade na maior parte do tempo. Apenas para polemizar, vamos supor que Q = 0. Como Q é realimentado para a porta nor superior, ambas as suas entradas são 0, portanto, sua saída, Q, é 1. O 1 é realimentado para a porta inferior que, então, tem entradas 1 e 0, resultando em Q = 0. Esse estado é no mínimo coerente e está retratado na Figura 3.21(a). Agora, vamos imaginar que Q não seja 0, mas 1, com R e S ainda 0. A porta superior tem entradas de 0 e 1, e uma saída, Q, de 0, que é realimentada para a porta inferior. Esse estado, mostrado na Figura 3.21(b), também é coerente. Um estado com as duas saídas iguais a 0 é incoerente, porque força ambas as portas a ter dois 0 como entrada, o que, se fosse verdade, produziria 1, não 0, como saída. De modo semelhante, é impossível ter ambas as saídas iguais a 1, porque isso forçaria as entradas a 0 e 1, o que resultaria 0, não 1. Nossa conclusão é simples: para R = S = 0, o latch tem dois estados estáveis, que denominaremos 0 e 1, dependendo de Q. Agora, vamos examinar o efeito das entradas sobre o estado do latch. Suponha que S se torna 1 enquanto Q = 0. Então, as entradas para a porta superior são 1 e 0, forçando a saída Q a 0. Essa mudança faz ambas as entradas para a porta inferior serem 0, forçando a saída para 1. Portanto, ativar S (isto é, fazer com que seja 1) muda o estado de 0 para 1. Definir R em 1 quando o latch está no estado 0 não tem efeito algum porque a saída da porta NOR inferior é 0 para entradas de 10 e entradas de 11. Usando raciocínio semelhante, é fácil ver que definir S em 1 quando em estado Q = 1 não tem efeito algum, mas definir R leva o latch ao estado Q = 0. Resumindo, quando S é definido em 1 momentaneamente, o latch acaba no estado Q = 1, pouco importando seu estado anterior. Da mesma maneira, definir R em 1 momentaneamente força o latch ao estado Q = 0. O circuito “se lembra” se foi S ou R definido por último. Usando essa propriedade podemos construir memórias de computadores. Latches SR com clock Muitas vezes é conveniente impedir que o latch mude de estado, a não ser em certos momentos especificados. Para atingir esse objetivo, fazemos uma ligeira modificação no circuito básico, conforme mostra a Figura 3.22, para obter um latch SR com clock. Figura 3.22 Latch SR com clock. Clock S Q Q R Esse circuito tem uma entrada adicional, o clock, que em geral é 0. Com o clock em 0, ambas as portas and geram saída 0, independentemente de ser S e R, e o latch não muda de estado. Quando o clock é 1, o efeito das portas and desaparece e o latch se torna sensível a S e R. Apesar de seu nome, o sinal do clock não precisa ser gerado por um clock. Os termos enable e strobe também são muito usados para indicar que a entrada do clock é 1; isto é, o circuito é sensível ao estado de S e R. Até aqui evitamos falar no que acontece quando ambos, S e R, são 1, por uma boa razão: o circuito se torna não determinístico quando ambos, R e S, finalmente retornam a 0. O único estado coerente para S = R = 1 é Q = Q = 0; porém, assim que ambas as entradas voltam para 0, o latch deve saltar para um de seus dois estados está- veis. Se quaisquer das entradas cair para 0 antes da outra, a que permanecer em 1 por mais tempo vence, porque, quando apenas uma entrada for 1, ela força o estado. Se ambas as entradas voltarem a 0 ao mesmo tempo (o que é muito improvável), o latch salta aleatoriamente para um de seus estados estáveis.
  • 154. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 135 Latches D com clock Uma boa maneira de resolver a instabilidade do latch SR (causada quando S = R = 1) é evitar que ela ocorra. A Figura 3.23 apresenta um circuito de latch com somente uma entrada, D. Como a entrada para a porta and inferior é sempre o complemento da entrada para a superior, nunca ocorre o problema de ambas as entradas serem 1. Quando D = 1 e o clock for 1, o latch é levado ao estado Q = 1. Quando D = 0 e o clock for 1, ele é levado ao estado Q = 0. Em outras palavras, quando o clock for 1, o valor corrente de D é lido e armazenado no latch. Esse circuito, denominado latch  com clock, é uma verdadeira memória de 1 bit. O valor armazenado sempre estará disponível em Q. Para carregar o valor atual de D na memória, um pulso positivo é colocado na linha do clock. Figura 3.23 Latch D com clock. D Q Q Esse circuito requer 11 transistores. Circuitos mais sofisticados (porém, menos óbvios) podem armazenar 1 bit com até seis transistores. Esses projetos costumam ser usados na prática. Esse circuito pode permanecer estável indefinidamente, desde que seja aplicada energia (não mostrado). Mais adiante, veremos os circuitos de memória que se esquecem rápido do estado em que estão, a menos que, de alguma forma, sejam “relembrados” constantemente. 3.3.2 Flip-flops Em muitos circuitos é necessário ler o valor em determinada linha em dado instante, e armazená-lo. Nessa variante, denominada flip-flop, a transição de estado não ocorre quando o clock é 1, mas durante a transição de 0 para 1 (borda ascendente), ou de 1 para 0 (borda descendente). Assim, o comprimento do pulso do clock não é importante, contanto que as transições ocorram rapidamente. Para dar ênfase, vamos repetir qual é a diferença entre um flip-flop e um latch. Um flip-flop é disparado pela borda, enquanto um latch é disparado pelo nível. Contudo, fique atento, porque esses termos são muito confun- didos na literatura. Muitos autores usam “flip-flop” quando estão se referindo a um latch, e vice-versa. Há várias formas de projetar um flip-flop. Por exemplo, se houvesse alguma maneira de gerar um pulso muito curto na borda ascendente do sinal de clock, esse pulso poderia ser alimentado para um latch D. Na verdade, essa maneira existe, e o circuito para ela é mostrado na Figura 3.24(a). À primeira vista, poderia parecer que a saída da porta and seria sempre zero, uma vez que a operação and de qualquer sinal com seu inverso é zero, mas a situação é um pouco diferente disso. O inversor tem um atraso de propa- gação pequeno, mas não zero, e é esse atraso que faz o circuito funcionar. Suponha que meçamos a tensão nos quatro pontos de medição a, b, c e d. O sinal de entrada, medido em a, é um pulso de clock longo, como mostrado na parte inferior da Figura 3.24(b). O sinal em b é mostrado acima dele. Observe que ele está invertido e também ligeiramente atrasado, quase sempre de alguns nanossegundos, dependendo do tipo de inversor utilizado. O sinal em c também está atrasado, mas apenas pelo tempo correspondente à propagação (à velocidade da luz) do sinal. Se a distância física entre a e c for, por exemplo, 20 micra, então o atraso de propagação é 0,0001 ns, que decerto é desprezível em comparação com o tempo que o sinal leva para se propagar pelo inversor. Assim, para todos os efeitos e propósitos, o sinal em c é praticamente idêntico ao sinal em a.
  • 155. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 136 Quando se efetua uma operação and com as entradas para a porta and, b e c, o resultado é um pulso curto, como mostra a Figura 3.24(b), onde a largura do pulso, Δ, é igual ao atraso da porta do inversor, em geral 5 ns ou menos. A saída da porta and é exatamente esse pulso deslocado pelo atraso da porta and, como mostrado na parte superior da Figura 3.24(b). Esse deslocamento de tempo significa apenas que o latch D será ativado com um atraso fixo após a fase ascendente do clock, mas não tem efeito sobre a largura do pulso. Em uma memória com tempo de ciclo de 10 ns, um pulso de 1 ns para informar quando ler a linha D pode ser curto o bastante, caso em que o circuito completo pode ser o da Figura 3.25. ale a pena observar que esse projeto de flip-flop é atraente porque é fácil de entender, embora, na prática, sejam usados flip-flops mais sofisticados. Figura 3.24 (a) Gerador de pulso. (b) Temporizac a o em quatro pontos do circuito. Tempo a b c d d b AND c c b a (a) (b) ∆ Figura 3.25 Flip-flop D. Q D Q Os símbolos padronizados para latches e flip-flops são mostrados na Figura 3.26. A Figura 3.26(a) é um latch cujo estado é carregado quando o clock, CK, é 1, ao contrário da Figura 3.26(b), que é um latch cujo clock costuma ser 1, mas cai para 0 momentaneamente para carregar o estado a partir de D. As figuras 3.26(c) e (d) são flip-flops em vez de latches, o que é indicado pelo símbolo em ângulo nas entradas do clock. A Figura 3.26(c) muda de estado na borda ascendente do pulso do clock (transição de 0 para 1), enquanto a Figura 3.26(d) muda de estado na borda
  • 156. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 137 descendente (transição de 1 para 0). Muitos latches e flip-flops (mas não todos) também têm Q como uma saída, e alguns têm duas entradas adicionais Set ou Preset (que forçam o estado para Q = 1) e Reset ou Clear (que forçam o estado para Q = 0). Figura 3.26 Latches e flip-flops D. D Q CK (a) D Q CK (b) D Q CK (c) D Q (d) CK 3.3.3 Registradores Flip-flops podem ser combinados em grupos para criar registradores, que mantêm tipos de dados com comprimentos maiores do que 1 bit. O registrador na Figura 3.27 mostra como oito flip-flops podem ser ligados para formar um registrador armazenador de 8 bits. O registrador aceita um valor de entrada de 8 bits (I0 a I7) quando o clock CK fizer uma transição. Para implementar um registrador, todas as linhas de clock são conectadas ao mesmo sinal de entrada CK, de modo que, quando o clock fizer uma transição, cada registrador aceitará o novo valor de dados de 8 bits no barramento de entrada. Os próprios flip-flops são do tipo da Figura 3.26(d), mas as bolhas de inversão nos flip-flops são canceladas pelo inversor ligado ao sinal de clock CK, de modo que os flip-flops são carregados na transição ascendente do clock. Todos os oito sinais clear também são ligados, de modo que, quando o sinal clear CLR passar para 0, todos os flip-flops serão forçados a passar para o seu estado 0. Caso você queira saber por que o sinal de clock CK é invertido na entrada e depois invertido novamente em cada flip-flop, um sinal de entrada pode não ter corrente suficiente para alimentar todos os oito flip-flops; o inversor da entrada, na realidade, está sendo usado como um amplificador. Figura 3.27 Um registrador de 8 bits constru do a partir de flip-flops de u nico bit. Q CK CLR D Q CK CLR D Q CK CLR D Q CK CK CLR CLR D Q D CK CLR Q D CK CLR Q D CK CLR CLR O4 O5 O6 O7 I4 O0 O1 I0 O2 I1 O3 I2 O3 CK I5 I6 I7 Q D Quando tivermos projetado um registrador de 8 bits, poderemos usá-lo como um bloco de montagem para criar registradores maiores. Por exemplo, um registrador de 32 bits poderia ser criado pela combinação de dois registradores de 16 bits, unindo seus sinais de clock CK e sinais de clear CLR. eremos os registradores e seus usos com mais detalhes no Capítulo 4.
  • 157. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 138 3.3.4 Organizac a o da memo ria Embora agora tenhamos progredido de uma simples memória de 1 bit da Figura 3.23 para a de 8 bits da Figura 3.27, para construir memórias grandes é preciso uma organização diferente, na qual palavras individuais podem ser endereçadas. Uma organização de memória muito utilizada e que obedece a esse critério é mostrada na Figura 3.28. Esse exemplo ilustra uma memória com quatro palavras de 3 bits. Cada operação lê ou escreve uma palavra completa de 3 bits. Embora uma capacidade total de memória de 12 bits seja pouco mais do que nosso flip-flop octal, ela requer um número menor de pinos e, mais importante, o projeto pode ser estendido com facilidade para memórias grandes. Observe que o número de palavras é sempre uma potência de 2. Figura 3.28 Diagrama lo gico para uma memo ria 4 x 3. Cada linha e  uma das quatro palavras de 3 bits. Uma operac a o de leitura ou escrita sempre le  ou escreve uma palavra completa. HABILITAR SAÍDA = CS · RD · OE I0 I1 I2 Q D CK O2 O1 O0 CS RD OE CS • RD A0 A1 Q D CK Q D CK Q D CK Q D CK Q D CK Q D CK Q D CK Q D CK Q D CK Q D CK Q D CK Entrada de dados Porta de escrita Linha de seleção de palavra 0 Linha de seleção de palavra 1 Linha de seleção de palavra 2 Palavra 0 Palavra 1 Palavra 2 Palavra 3
  • 158. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 139 Embora à primeira vista talvez pareça complicada, a memória da Figura 3.28 na verdade é bastante simples devido à sua estrutura regular. Ela tem oito linhas de entrada e três de saída. Três entradas são de dados: I0, I1 e I2; duas são para o endereço: A0 e A1; e três são para controle: cs para chip select (selecionar chip), rd para distinguir entre ler e escrever e oe para output enable (habilitar saída). As três saídas são para dados: O0, O1 e O2. É interessante notar que essa memória de 12 bits requer menos sinais que o registra- dor de 8 bits anterior. Este requer 20 sinais, incluindo alimentação e terra, enquanto a memória de 12 bits requer apenas 13 sinais. O bloco de memória requer menos sinais porque, diferente do registrador, os bits de memória compartilham um sinal de saída. Nessa memória, cada um dos 4 bits de memória compar- tilha um sinal de saída. O valor das linhas de endereço determina quais dos 4 bits de memória pode receber ou enviar um valor. Para selecionar esse bloco de memória, a lógica externa deve estabelecer cs alto e também rd alto (1 lógico) para leitura e baixo (0 lógico) para escrita. As duas linhas de endereço devem ser ajustadas para indicar qual das quatro palavras de 3 bits deve ser lida ou escrita. Para uma operação de leitura, as linhas de entrada de dados não são usadas, mas a palavra selecionada é colocada nas linhas de saída de dados. Para uma operação de escrita, os bits presentes nas linhas de entrada de dados são carregados na palavra de memória selecionada; as linhas de saída de dados não são usadas. Agora, vamos examinar atentamente a Figura 3.28 para ver como isso funciona. As quatro portas and de seleção de palavras à esquerda da memória formam um decodificador. Os inversores de entrada foram instalados de modo que cada porta é habilitada (saída é alta) por um endereço diferente. Cada porta comanda uma linha de seleção de palavra, de cima para baixo, para as palavras 0, 1, 2 e 3. Quando o chip é selecionado para uma escrita, a linha vertical rotulada cs · rd estará alta, habilitando uma das quatro portas de escrita, dependendo de qual linha de seleção de palavra esteja alta. A saída da porta de escrita comanda todos os sinais ck para a palavra selecionada, carregando os dados de entrada nos flip-flops para aquela palavra. Uma escrita é efetuada apenas se cs estiver alto e rd estiver baixo, e, ainda assim, somente a palavra selecionada por A0 e A1 é escrita; as outras palavras não são alteradas. Ler é semelhante a escrever. A decodificação de endereço é idêntica à da escrita. Mas agora a linha cs · rd está baixa, portanto, todas as portas de escrita estão desabilitadas e nenhum dos flip-flops é modificado. Em vez disso, a linha de seleção de palavra que for escolhida habilita as portas and vinculadas aos Q bits da palavra selecionada. Portanto, a palavra selecionada entrega seus dados às portas or de quatro entradas na parte inferior da figura, enquanto as outras três palavras produzem 0s. Em consequência, a saída das portas or é idêntica ao valor armazenado na palavra selecionada. As três palavras não selecionadas não dão nenhuma contribuição à saída. Embora pudéssemos ter projetado um circuito no qual as três portas or fossem diretamente ligadas às três linhas de saída de dados, essa operação às vezes causa problemas. Em particular, mostramos que as linhas de entrada de dados e as linhas de saída de dados são diferentes, porém, nas memórias em si, as mesmas linhas são usadas. Se tivéssemos vinculado as portas or às linhas de saída de dados, o chip tentaria produzir dados, isto é, forçar cada linha a um valor específico, mesmo nas escritas, interferindo desse modo com os dados de entrada. Por essa razão, é desejável ter um meio de conectar as portas or às linhas de saída de dados em leituras, mas desconectá-las completamente nas escritas. O que precisamos é de um comutador eletrônico que possa estabele- cer ou interromper uma conexão em poucos nanossegundos. Felizmente, esses comutadores existem. A Figura 3.29(a) mostra o símbolo para o que denominamos buffer não inversor, que tem uma entrada e uma saída de dados e uma entrada de controle. Quando a entrada de con- trole estiver alta, o buffer age como um fio, como mostra a Figura 3.29(b). Quando a entrada de controle esti- ver baixa, ele age como um circuito aberto, como mostra a Figura 3.29(c); é como se alguém desconectasse a saída de dados do resto do circuito com um alicate de corte. Contudo, ao contrário do que aconteceria no caso do alicate de corte, a conexão pode ser restaurada logo em seguida, dentro de alguns nanossegundos, apenas fazendo o sinal de controle ficar alto novamente. A Figura 3.29(d) mostra um buffer inversor, que funciona como um inversor normal quando o controle estiver alto, e desconecta a saída do circuito quando o controle estiver baixo. Ambos os tipos de buffers são
  • 159. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 140 dispositivos de três estados, porque podem produzir 0, 1, ou nenhum dos dois (circuito aberto). Buffers também amplificam sinais, portanto, podem comandar muitas entradas simultaneamente. Às vezes, eles são usados em circuitos por essa razão, mesmo quando suas propriedades de comutação não são necessárias. oltando ao circuito de memória, agora já deve estar claro para que servem os três buffers não inversores nas linhas de saída de dados. Quando cs, rd e oe estiverem todos altos, o sinal output enable também está alto, habilitando os buffers e colocando uma palavra nas linhas de saída. Quando qualquer um dos cs, rd ou oe estiver baixo, as saídas de dados são desconectadas do resto do circuito. 3.3.5 Chips de memo ria O bom da memória da Figura 3.28 é que ela pode ser ampliada com facilidade para tamanhos maiores. Em nosso desenho, a memória é 4 × 3, isto é, quatro palavras de 3 bits cada. Para ampliá-la para 4 × 8, basta adicionar cinco colunas de quatro flip-flops cada, bem como cinco linhas de entrada e cinco linhas de saída. Para passar de 4 × 3 para 8 × 3, devemos acrescentar quatro linhas de três flip-flops cada, bem como uma linha de endereço A2. Com esse tipo de estrutura, o número de palavras na memória deve ser uma potência de 2 para que haja o máximo de eficiência, mas o número de bits em uma palavra pode ser qualquer um. Como a tecnologia de circuitos integrados se ajusta bem à fabricação de chips cuja estrutura interna é um padrão bidimensional repetitivo, chips de memória são uma aplicação ideal para ela. À medida que a tecnologia melhora, o número de bits que podem ser colocados em um chip continua crescendo, normalmente por um fator de dois a cada 18 meses (lei de Moore). Os chips maiores nem sempre tornam os menores obsoletos devido aos diferentes compromissos entre capacidade, velocidade, energia, preço e conveniência da interface. Em geral, os chips maiores disponíveis no momento são vendidos por preços mais elevados, portanto, são mais caros por bit do que os antigos, menores. Há vários modos de organizar o chip para qualquer tamanho de memória dado. A Figura 3.30 mostra duas organizações possíveis para um chip de memória mais antigo de 4 Mbits de tamanho: 512 K × 8 e 4.096 K × 1. (A propósito, os tamanhos de chips de memória costumam ser citados em bits em vez de bytes, e por isso adotaremos essa convenção.) Na Figura 3.30(a), são necessárias 19 linhas de endereço para endereçar um dos 219 bytes e oito linhas de dados para carregar e armazenar o byte selecionado. Cabe aqui uma observação sobre tecnologia. Em alguns pinos, a alta tensão provoca uma ação. Em outros, é a baixa tensão que causa uma ação. Para evitar confusão, preferimos manter a coerência e dizer sempre que o sinal é afirmado (em vez de dizer que fica alto ou baixo), o que significa que foi disparado para provocar alguma ação. Assim, para alguns pinos, afirmá-lo significa estabelecê-lo alto. Para outros, significa estabelecer o pino baixo. Os nomes de sinais de pinos afirmados baixos são distinguidos por uma barra superior. Assim, um sinal com rótulo cs é ativado alto, mas um sinal com rótulo cs é ativado baixo. O oposto de afirmado é negado. Quando nada de especial estiver acontecendo, os pinos são negados. Figura 3.29 (a) Buffer na o inversor. (b) Efeito de (a) quando o controle esta  alto. (c) Efeito de (a) quando o controle esta  baixo. (d) Buffer inversor. Controle (b) (a) (d) (c) Entrada de dados Saída de dados
  • 160. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 141 Agora, vamos voltar ao nosso chip de memória. Uma vez que um computador costuma ter muitos chips de memória, é preciso um sinal para selecionar o chip necessário no momento em questão, de modo que ele responda e todos os outros não. O sinal cs (chip select – seleção de chip) existe para essa finalidade e é ativado para habilitar o chip. Além disso, é preciso uma maneira de distinguir entre leituras e escritas. O sinal we (write enable – habilitar escrita) é usado para indicar que os dados estão sendo escritos, e não lidos. Por fim, o sinal oe (output enable – habilitar saída) é afirmado para comandar os sinais de saída. Quando ele não é afirmado, a saída do chip é desconectada do circuito. Na Figura 3.30(b), é usado um esquema de endereçamento diferente. Esse chip é organizado internamente como uma matriz 2.048 × 2.048 de células de 1 bit, o que dá 4 Mbits. Para endereçar o chip, em primeiro lugar uma linha é selecionada ao se colocar seu número de 11 bits nos pinos de endereço. Então o ras (row address strobe – strobe de endereço de linha) é afirmado. Em seguida, um número de coluna é colocado nos pinos de endereço e o cas (column address strobe – strobe de endereço de coluna) é afirmado. O chip responde aceitando ou entregando um bit de dados. Chips de memória de grande porte costumam ser construídos como matrizes n × n endereçadas por linha e coluna. Essa organização reduz o número de pinos requerido, mas também torna mais lento o endereçamento do chip, já que são necessários dois ciclos, um para a linha e outro para a coluna. Para recuperar um pouco da velocidade perdida por esse projeto, alguns chips de memória podem receber um endereço de linha acompanhado por uma sequência de endereços de coluna para acessar bits consecutivos em uma linha. Anos atrás, os maiores chips de memória costumavam ser organizados como os da Figura 3.30(b). À medida que as palavras de memória cresciam de 8 bits até 32 bits e mais, os chips de 1 bit começaram a ser inconvenien- tes. Construir uma memória com uma palavra de 32 bits usando chips de 4.096 K × 1 requer 32 chips em paralelo. Esses 32 chips têm capacidade total de no mínimo 16 MB, ao passo que usar chips de 512 K × 8 requer somente quatro chips em paralelo e permite memórias pequenas, de até 2 MB. Para evitar ter 32 chips para memória, grande parte dos fabricantes lançou famílias com 4, 8 e 16 bits de largura. A situação com as palavras de 64 bits é pior ainda, é claro. Dois exemplos de chips modernos de 512 Mbits são dados na Figura 3.31. Esses chips têm quatro bancos de memória internos de 128 Mbits cada, o que requer duas linhas de seleção de banco para escolher um banco. O projeto da Figura 3.31(a) é de um chip de 32 M × 16 com 13 linhas para o sinal ras, 10 linhas para o sinal cas e 2 linhas para a seleção de banco. Juntos, esses 25 sinais permitem o endereçamento de cada uma das 225 células Figura 3.30 Dois modos de organizar um chip de memo ria de 4 Mbits. Chip de memória de 4.096 K x 1 (4 Mbits) D0 A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15 A16 A17 A18 D1 D2 D3 D4 D5 D6 D7 WE (a) CS OE A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 RAS CAS D WE (b) CS OE Chip de memória de 512 K x 8 (4 Mbits)
  • 161. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 142 internas de 16 bits. Em comparação, a Figura 3.31(b) apresenta um projeto de 128 M × 4 com 13 linhas para o sinal ras, 12 linhas para o sinal cas e 2 linhas para a seleção de banco. Nesse caso, 27 sinais podem selecionar quaisquer das 227 células internas de 4 bits a serem endereçadas. A decisão sobre o número de linhas e de colunas que um chip tem é tomada por razões de engenharia. A matriz não precisa ser quadrada. Figura 3.31 Dois modos de organizar um chip de memo ria de 512 Mbits. A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 D0 D1 D2 D3 D4 D5 D6 D7 WE (a) CS OE A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 RAS CAS WE (b) CS OE RAS CAS D8 D9 D10 D11 D12 D13 D14 D15 A11 A12 D0 D1 D2 D3 Chip de memória de 32 M × 16 (512 Mbits) Banco 0 Banco 1 Chip de memória de 128 M × 4 (512 Mbits) Banco 0 Banco 1 Esses exemplos demonstram duas questões separadas e independentes para o projeto do chip de memória. A primeira é a largura da saída (em bits): o chip entrega 1, 4, 8, 16 ou algum outro número de bits de uma vez só? A segunda é se todos os bits de endereço são apresentados em pinos separados de uma vez só ou se as linhas e colunas são apresentadas em sequência, como nos exemplos da Figura 3.31. Um projetista de chips de memória tem de responder a ambas as perguntas antes de iniciar o projeto do chip. 3.3.6 RAMs e ROMs Todas as memórias que estudamos até aqui podem ser escritas e lidas. Elas são denominadas memórias RM (Random Access Memory – memória de acesso aleatório), um nome suspeito porque todos os chips de memória têm acesso aleatório. No entanto, o termo já é muito utilizado para que o mudemos agora. RAMs podem ser de duas variedades, estáticas e dinâmicas. Nas estáticas (Static RMs  SRMs), a construção interna usa circuitos similares ao nosso flip-flop D básico. Uma das propriedades dessas memórias é que seus conteúdos são conser- vados enquanto houver fornecimento de energia: segundos, minutos, horas e até mesmo dias. As RAMs estáticas são muito rápidas. Um tempo de acesso típico é da ordem de um nanossegundo ou menos. Por essa razão, elas são muito usadas como memória cache. RMS dinâmicas (ynamic RMs  RMs), ao contrário, não usam flip-flops. Em vez disso, uma RAM dinâmica é um arranjo de células, cada uma contendo um transistor e um pequenino capacitor. Os capacitores podem ser carregados ou descarregados, permitindo que 0s e 1s sejam armazenados. Como a carga elétrica tende a vazar, cada bit em uma RAM dinâmica deve ser renovado (recarregado) com alguns milissegundos de intervalo para evitar que os dados desapareçam. Como a lógica externa é que tem de cuidar da renovação, as RAMs dinâmi- cas precisam de uma interface mais complexa do que as estáticas, embora em muitas aplicações essa desvantagem seja compensada por suas maiores capacidades.
  • 162. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 143 isto que as RAMs dinâmicas precisam de apenas um transistor e um capacitor por bit, em comparação com os seis transistores por bit para a melhor RAM estática, elas têm densidade muito alta (muitos bits por chip). Por essa razão, as memórias principais quase sempre são construídas com RAMs dinâmicas. Contudo, essa grande capacidade tem um preço: são lentas (dezenas de nanossegundos). Dessa maneira, a combinação de uma cache de RAM estática e uma memória principal de RAM dinâmica tenta combinar as boas propriedades de cada uma. Existem diversos tipos de RAMs dinâmicas. A mais antiga ainda existente (em computadores antigos) é a DRAM FPM (Fast Page Mode  modo de página rápida). Ela é organizada internamente como uma matriz de bits e funciona da seguinte maneira: o hardware escolhe um endereço de linha e então seleciona endereços de coluna um a um, como descrevemos para o ras e o cas no contexto da Figura 3.30. Sinais explícitos informam à memória quando é hora de responder, de modo que ela funciona de forma assíncrona com o clock do sistema principal. A DRAM FPM foi substituída pela EO (Extended ata Output  saída de dados ampliada), que permite iniciar uma segunda referência à memória antes de ser concluída a referência à memória precedente. Esse parale- lismo simples não acelerava uma referência individual à memória, mas melhorava a largura de banda da memória, resultando em mais palavras por segundo. FPM e EDO funcionavam bastante bem quando os tempos de ciclo de chips de memória eram de 12 nanos- segundos ou mais lentos. Quando os processadores ficaram tão rápidos que era mesmo preciso ter memórias mais rápidas, a FPM e a EDO foram substituídas pela SRM (Synchronous RM  RM síncrona), que é uma híbrida de RAM estática e dinâmica, comandada pelo clock do sistema principal. A grande vantagem da SDRAM é que o clock elimina a necessidade de sinais de controle para informar ao chip de memória quando responder. Em vez disso, a CPU informa à memória por quantos ciclos ela deve funcionar e então a inicia. Em cada ciclo subse- quente, a memória entrega 4, 8 ou 16 bits, dependendo de quantas linhas de saída ela tem. Eliminar a necessidade de sinais de controle aumenta a taxa de dados entre CPU e memória. A melhoria seguinte em relação à SDRAM foi a SDRAM R (ouble ata Rate  dupla taxa de dados). Com esse tipo de memória, o chip de memória produz saída na borda ascendente do clock e também na borda descendente, dobrando a taxa de dados. Portanto, um chip DDR de 8 bits de largura funcionando a 200 MHz entrega dois valores de 8 bits 200 milhões de vezes por segundo (por um curto intervalo, é claro), o que dá uma taxa de saída (burst) teórica de 3,2 Gbps. As interfaces de memória DDR2 e DDR3 oferecem desempenho adi- cional em relação à DDR, aumentando as velocidades do barramento de memória para 533 MHz e 1.067 MHz, respectivamente. No momento em que este livro era impresso, os chips DDR3 mais velozes poderiam enviar dados a 17,067 GB/s. Chips de memo ria na o vola til RAMs não são o único tipo de chip de memória. Em muitas aplicações, como brinquedos, eletrodomésti- cos e carros, o programa e alguns dos dados devem permanecer armazenados mesmo quando o fornecimento de energia for interrompido. Além do mais, uma vez instalados, nem o programa nem os dados são alterados. Esses requisitos levaram ao desenvolvimento de ROMs (Read-Only Memories  memórias somente de leitura), que não podem ser alteradas nem apagadas, seja intencionalmente ou não. Os dados de uma ROM são inseridos durante sua fabricação por um processo que expõe um material fotossensível por meio de uma máscara que con- tém o padrão de bits desejado e então grava o padrão sobre a superfície exposta (ou não exposta). A única maneira de mudar o programa em uma ROM é substituir o chip inteiro. ROMs são muito mais baratas que RAMs quando fabricadas em volumes grandes o bastante para cobrir o custo da fabricação da máscara. Todavia, são inflexíveis porque não podem ser alteradas após a manufatura, e o tempo decorrido entre fazer o pedido e receber as ROMs pode chegar a semanas. Para facilitar o desenvol- vimento pelas empresas de novos produtos com ROM, foi inventada a PROM (Programmable ROM – ROM programável). Uma PROM é como uma ROM, exceto que ela pode ser programada (uma vez) em campo, elimi- nando o tempo de espera entre produção e entrega. Muitas PROMs contêm um arranjo de minúsculos fusíveis em seu interior. Um fusível específico pode ser queimado selecionando sua linha e coluna e então aplicando alta tensão a um pino especial no chip.
  • 163. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 144 O desenvolvimento seguinte nessa linha foi a EPROM (Erasable PROM – PROM apagável), que não só pode ser programada, mas também apagada em campo. Quando a janela de quartzo de uma EPROM é exposta a uma forte luz ultravioleta durante 15 minutos, todos os bits são definidos em 1. Se a expectativa é ter muitas alterações durante o ciclo de projeto, as EPROMs são muito mais econômicas do que as PROMs, porque podem ser reuti- lizadas. As EPROMS costumam ter a mesma organização que as RAMs estáticas. A EPROM 27C040 de 4 Mbits, por exemplo, usa a organização da Figura 3.31(a), que é típica de uma RAM estática. O interessante é que chips antigos como este não desaparecem. Eles apenas se tornam mais baratos e são usados em produtos inferiores, que são altamente sensíveis ao custo. Um 27C040 agora pode ser comprado no varejo por menos de US$ 3, e por muito menos em grandes volumes. Ainda melhor do que a EPROM é a EEPROM, que pode ser apagada aplicando-se pulsos em vez de ser exposta à luz ultravioleta dentro de uma câmara especial. Além disso, uma EEPROM pode ser reprogramada no local, enquanto uma EPROM tem de ser inserida em um dispositivo especial de programação de EPROM para ser programada. Uma desvantagem é que a capacidade das maiores EEPROMs é em geral somente 1/64 da capacidade das EPROMs comuns, e sua velocidade é a metade. EEPROMs não podem competir com DRAMs ou SRAMs por- que são 10 vezes mais lentas, sua capacidade é 100 vezes menor e são muito mais caras. Elas são usadas somente em situações em que sua não volatilidade for crucial. Um tipo mais recente de EEPROM é a memória flash. Diferente da EPROM, que é apagada pela exposição à luz ultravioleta, e da EEPROM, cujos bytes podem ser apagados, os blocos da memória flash podem ser apagados e reescritos. Como a EEPROM, a memória flash pode ser apagada sem ser removida do circuito. ários fabricantes produzem pequenas placas de circuito impresso com até 64 GB de memória flash que são utilizadas como um “filme” para armazenar fotos em câmeras digitais e muitas outras finalidades. Como já vimos no Capítulo 2, a memória flash agora está começando a substituir os discos mecânicos. Assim como um disco, a memória flash oferece tempos de acesso menores com menor consumo de energia, mas com um custo por bit muito mais alto. Um resumo dos diversos tipos de memória pode ser visto na Figura 3.32. Figura 3.32 Comparac a o entre va rios tipos de memo rias (Arranjo de portas programa vel em campo). Tipo Categoria Modo de apagar Byte alterável Volátil Utilização típica SRAM Leitura/escrita Elétrico Sim Sim Cache de nível 2 DRAM Leitura/escrita Elétrico Sim Sim Memória principal (antiga) SDRAM Leitura/escrita Elétrico Sim Sim Memória principal (nova) ROM Somente de leitura Não é possível Não Não Equipamentos de grande volume PROM Somente de leitura Não é possível Não Não Equipamentos de pequeno volume EPROM Principalmente leitura Luz UV Não Não Prototipagem de dispositivos EEPROM Principalmente leitura Elétrico Sim Não Prototipagem de dispositivos Flash Leitura/escrita Elétrico Não Não Filme para câmera digital Field-programmable gate arrays Como vimos no Capítulo 1, Field-Programmable Gate rrays (FPGs) são chips que contêm lógica pro- gramável, de modo que podem formar um circuito lógico qualquer simplesmente carregando o FPGA com dados de configuração apropriados. A principal vantagem dos FPGAs é que novos circuitos de hardware podem ser construídos em horas, em vez dos meses necessários para fabricar Cs. Porém, os circuitos integrados não serão extintos, pois ainda possuem uma vantagem de custo significativa em relação aos FPGAs para aplicações de alto volume, e também são mais rápidos e usam muito menos energia. Contudo, com suas vantagens de tempo de projeto, os FPGAs são usados constantemente para protótipo de projeto e aplicações com baixo volume.
  • 164. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 145 Agora, vejamos o interior de um FPGA para entender como ele pode ser usado para executar uma grande gama de circuitos lógicos. O chip FPGA contém dois componentes principais que são replicados muitas vezes: LUs (LookUp ables  tabelas de pesquisa) e interconexões programáveis. ejamos agora como estes são utilizados. Uma LUT, mostrada na Figura 3.33(a), é uma pequena memória programável que produz um sinal de saída opcionalmente para um registrador, que é então enviada para a interconexão programável. A memória progra- mável é usada para criar uma função lógica qualquer. A LUT na figura tem uma memória de 16 × 4, que pode simular qualquer circuito lógico com 4 bits de entrada e 4 bits de saída. A programação da LUT requer a carga da memória com as respostas apropriadas da lógica combinatória sendo simulada. Em outras palavras, se a lógica combinatória produz o valor Y quando recebe a entrada X, o valor Y é escrito na LUT no índice X. O projeto de exemplo na Figura 3.33(b) mostra como uma única LUT de 4 entradas poderia executar um contador de 3 bits com reset. O exemplo de contador conta de modo contínuo somando um (módulo 4) ao valor atual, a menos que um sinal de reset CLR seja afirmado, que nesse caso retorna o valor do contador a zero. Para pôr em prática o contador do exemplo, as quatro entradas superiores da LUT são todas zero. Essas entradas enviam o valor zero quando o contador é reiniciado. Assim, o bit mais significativo da entrada da LUT (I3) representa a entrada de reset (CLR) que é ativada com uma lógica 1. Para as entradas restantes da LUT, o valor no índice I0..3 da LUT contém o valor (I + 1) módulo 4. Para concluir o projeto, o sinal de saída O0..3 deve ser conectado, usando a interconexão programável para o sinal de entrada interno I0..3. Para entender melhor o contador baseado em FPGA com reset, vamos considerar sua operação. Se, por exem- plo, o estado atual do contador for 2 e o sinal de reset (CLR) não for afirmado, o endereço de entrada da LUT será 2, que produzirá uma saída de 3 nos flip-flops. Se o sinal de reset (CLR) fosse afirmado para o mesmo estado, a entrada na LUT seria 6, que produziria o próximo estado de 0. Apesar de tudo, esse pode parecer um modo arcaico de se construir um contador com reset e, de fato, um projeto totalmente personalizado, com um circuito incrementador e sinais de reset para os flip-flops, seria menor, mais rápido e usaria menos energia. A principal vantagem do projeto baseado em FPGA é que você pode ajustá-lo em uma hora em casa, enquanto o projeto totalmente personalizado, mais eficiente, deve ser fabricado com base no silício, o que poderia levar pelo menos um mês. Figura 3.33 (a) Uma tabela de pesquisa (LUT) de um FPGA. (b) A configurac a o da LUT para criar um contador de apagamento de 3 bits. CK 0 1 1 2 2 3 3 0 O2..0 O2..0 O0..3 I0..3 CK CK I CLR 4 0 5 0 6 0 7 0 D Q 3 FPGA Contador Endereço Dados Endereço Dados Da interconexão programável Endereço Dados Memória de 16 × 4 Flip-flop ×4 À interconexão programável Designação de sinal Para usar um FPGA, o projeto precisa ser descrito usando uma descrição de circuito ou uma linguagem de descrição de hardware (ou seja, uma linguagem de programação usada para descrever estruturas de hardware). O projeto é então processado por um sintetizador, que mapeia o circuito para uma arquitetura FPGA específica. (a) (b)
  • 165. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 146 Um desafio do uso de FPGAs é que o projeto que você quer mapear nunca parece ser o suficiente. Os FPGAs são fabricados com uma quantidade variável de LUTs, com quantidades maiores custando mais. Em geral, se o seu projeto não for suficiente, você terá que simplificar ou abrir mão de alguma funcionalidade, ou então comprar um FPGA maior (e mais caro). Projetos muito grandes podem não caber nos maiores FPGAs, exigindo que o projetista mapeie o projeto em vários FPGAs; essa tarefa é definitivamente mais difícil, porém, ainda muito mais fácil do que projetar um circuito integrado personalizado completo. 3.4 Chips de CPU e barramentos Agora que já temos todas essas informações sobre circuitos integrados, clocks e chips de memória, pode- mos começar a juntar todas as peças, examinando sistemas completos. Nesta seção, estudaremos primeiro alguns aspectos gerais das CPUs do ponto de vista do nível lógico digital, incluindo a pinagem (pinout) (isto é, o que significam os sinais dos vários pinos). Como as CPUs estão tão entrelaçadas com o projeto dos barramen- tos que utilizam, também faremos uma introdução ao projeto de barramentos nesta seção. Nas seções seguintes, daremos exemplos detalhados de CPUs e seus barramentos e de como é a interface entre eles. 3.4.1 Chips de CPU Todas as CPUs modernas são contidas em um único chip, o que faz sua interação com o resto do sistema ser bem definida. Cada chip de CPU tem um conjunto de pinos por meio dos quais deve ocorrer toda sua comu- nicação com o mundo exterior. Alguns pinos produzem sinais da CPU para o mundo exterior; outros aceitam sinais do mundo exterior; alguns podem fazer as duas coisas. Entendendo a função de todos esses pinos, podemos aprender como a CPU interage com a memória e os dispositivos de E/S no nível lógico digital. Os pinos de um chip de CPU podem ser divididos em três tipos: de endereço, de dados e de controle. Eles são conectados a pinos similares na memória e a chips de E/S por meio de um conjunto de fios paralelos, denominado barramento. Para buscar uma instrução, primeiro a CPU coloca o endereço de memória daquela instrução em seus pinos de endereço. Então, ela ativa uma ou mais linhas de controle para informar à memória que ela quer ler uma palavra, por exemplo. A memória responde colocando a palavra requisitada nos pinos de dados da CPU e ativando um sinal que informa o que acabou de fazer. Quando percebe esse sinal, a CPU aceita a palavra e executa a instrução. A instrução pode requisitar leitura ou escrita de palavras de dados, caso em que todo o processo é repetido para cada palavra adicional. Mais adiante, vamos entrar nos detalhes do modo de funcionamento da leitura e da escrita. Por enquanto, o importante é entender que a CPU se comunica com a memória e com dispositivos de E/S apresentando sinais em seus pinos e aceitando sinais em seus pinos. Nenhuma outra comunicação é possível. Dois dos parâmetros fundamentais que determinam o desempenho de uma CPU são o número de pinos de endereço e o número de pinos de dados. Um chip com m pinos de endereço pode endereçar até 2m localizações de memória. alores comuns de m são 16, 32 e 64. De modo semelhante, um chip com n pinos de dados pode ler ou escrever uma palavra de n bits em uma única operação. alores comuns de n são 8, 32 e 64. Uma CPU com 8 pinos de dados efetuará quatro operações para ler uma palavra de 32 bits, enquanto uma CPU com 32 pinos de dados pode executar a mesma tarefa em uma única operação. Assim, o chip com 32 pinos de dados é muito mais rápido; porém, invariavelmente, também é mais caro. Além dos pinos de endereço e de dados, cada CPU tem alguns pinos de controle. Os pinos de controle regulam o fluxo e a temporização de dados que vêm da CPU e vão para ela, além de ter outras utilizações diversas. Todas as CPUs têm pinos para energia elétrica (geralmente +1,2 volt a +1,5 volt), para terra e para um sinal de clock (uma onda quadrada com uma frequência bem definida), mas os outros pinos variam muito de um chip para outro. Não obstante, os pinos de controle podem ser agrupados aproximadamente nas seguintes categorias principais: 1. Controle de barramento. 2. nterrupções.
  • 166. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 147 3. Arbitragem de barramento. 4. Sinalização de coprocessador. 5. Estado. 6. Diversos. Logo faremos uma breve descrição de cada uma dessas categorias. Quando examinarmos os chips ntel Core i7, T OMAP4430 e Atmel ATmega168, mais adiante, daremos mais detalhes. Um chip de CPU genérico que usa esses grupos de sinais pode ser visto na Figura 3.34. Figura 3.34 Pinagem lo gica de uma CPU gene rica. As setas indicam sinais de entrada e sinais de sa da. Os segmentos de reta diagonais indicam que sa o utilizados va rios pinos. Ha  um nu mero que indica quantos sa o os pinos para uma CPU espec fica. Símbolo para aterramento elétrico Φ Endereçamento Dados Controle de barramento Interrupções Micropro- cessador típico Arbitragem de barramento Coprocessador Estado Diversos Símbolo para sinal de clock Alimentação A maioria dos pinos de controle do barramento são saídas da CPU para o barramento (e, portanto, entradas para a memória e chips de E/S) que informam se a CPU quer ler ou escrever na memória ou fazer outra coisa qualquer. A CPU usa esses pinos para controlar o resto do sistema e informar o que ela quer fazer. Os pinos de interrupção são entradas que vêm de dispositivos de E/S para a CPU. Em grande parte dos sis- temas, a CPU pode dizer a um dispositivo de E/S que inicie uma operação e então continuar e fazer outra coisa qualquer enquanto o dispositivo de E/S está realizando seu trabalho. Quando a E/S estiver concluída, o chip controlador de E/S ativa um sinal em um desses pinos para interromper a CPU e fazê-la prestar algum serviço ao dispositivo de E/S, por exemplo, verificar se ocorreram erros de E/S. Algumas CPUs têm um pino de saída para confirmar o sinal de interrupção. Os pinos de arbitragem de barramento são necessários para disciplinar o tráfego no barramento de modo a impedir que dois dispositivos tentem usá-lo ao mesmo tempo. Do ponto de vista da arbitragem, a CPU é um dispositivo e tem de requisitar o barramento como qualquer outro. Alguns chips de CPUs são projetados para funcionar com coprocessadores, como chips de ponto flutuante, mas às vezes também com chips gráficos ou outros chips. Para facilitar a comunicação entre CPU e coprocessador, há pinos especiais dedicados a fazer e aceitar requisições. Além desses sinais, há outros pinos diversos presentes em algumas CPUs. Alguns deles fornecem ou aceitam informações de estado, outros são úteis para depuração ou para reiniciar o computador, e outros mais estão pre- sentes para garantir a compatibilidade com chips de E/S mais antigos. 3.4.2 Barramentos de computador Um barramento é um caminho elétrico comum entre vários dispositivos. Os barramentos podem ser cate- gorizados por sua função. Podem ser usados no interior da CPU para transportar dados de e para a ULA ou ser
  • 167. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 148 externos à CPU, para conectá-la à memória ou a dispositivos de E/S. Cada tipo tem seus próprios requisitos e propriedades. Nesta seção e nas seguintes, focalizaremos barramentos que conectam a CPU à memória e a dispo- sitivos de E/S. No capítulo seguinte, examinaremos mais de perto os barramentos internos à CPU. Os primeiros computadores pessoais tinham somente um barramento externo, ou barramento do sistema, que consistia em 50 a 100 fios de cobre paralelos gravados na placa-mãe, com conectores a intervalos regulares para ligação com a memória e placas de E/S. Os computadores pessoais modernos em geral têm um barramento de uso especial entre a CPU e a memória e (pelo menos) outro barramento para os dispositivos de E/S. Um sistema mínimo, com um barramento de memória e um barramento de E/S, é ilustrado na Figura 3.35. Figura 3.35 Sistema de computador com va rios barramentos. Chip de CPU Registradores Barramentos ULA Barramento no chip Controlador de barramento Barramento de memória Memória Barramento de E/S Disco Rede Impres- sora Na literatura, às vezes os barramentos são representados por setas largas e sombreadas, como nesta figura. A distinção entre essas setas e uma linha reta cortada por um pequeno segmento de reta inclinado acompanhado de um número de bits é sutil. Quando todos os bits são do mesmo tipo, por exemplo, todos são bits de endereço ou todos são bits de dados, então costuma ser usada a representação pelo segmento de reta diagonal. Quando estão envolvidas linhas de endereço, de dados e de controle, a seta larga sombreada é a mais comum. Embora os projetistas de CPUs tenham liberdade para usar qualquer tipo de barramento que quiserem dentro do chip, para possibilitar a ligação de placas projetadas por terceiros ao barramento de sistema é preciso haver regras bem definidas sobre o modo de funcionamento do barramento, às quais todos os dispositivos a ele ligados têm de obedecer. Essas regras são denominadas protocolo de barramento. Além disso, são necessárias especifi- cações mecânicas e elétricas, de modo que placas de terceiros caibam no suporte da placa e tenham conectores compatíveis com os da placa-mãe, tanto em termos mecânicos quanto em termos de tensões, temporizações etc. Ainda assim, outros barramentos não possuem especificações mecânicas, pois são projetados para serem usados dentro de um circuito integrado, por exemplo, para unir componentes dentro de um sistema-em-um-chip (SoC – System-on-a-Chip). Há inúmeros barramentos em uso no mundo dos computadores. Alguns dos mais conhecidos, no passado e atualmente (com exemplos), são: Omnibus (PDP-8), Unibus (PDP-11), Multibus (8086), barramento ME (equipamento para laboratório de física), barramento do BM PC (PC/T), barramento SA (PC/AT), barramento ESA (80386), Microchannel (PS/2), Nubus (Macintosh), barramento PC (muitos PCs), barramento SCS (mui- tos PCs e estações de trabalho), Universal Serial Bus (PCs modernos) e FireWire (equipamentos eletrônicos de consumo). O mundo provavelmente seria um lugar melhor se todos os barramentos, menos um, desaparecessem repentinamente da face da Terra (tudo bem, menos dois, então). nfelizmente, a padronização nessa área parece muito improvável porque muito dinheiro já foi investido em todos esses sistemas incompatíveis.
  • 168. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 149 A propósito, existe outra interconexão, PC Express, que geralmente é chamada de barramento, mas na ver- dade não é barramento algum. amos estudá-la mais adiante neste capítulo. Agora, vamos iniciar nosso estudo do funcionamento dos barramentos. Alguns dispositivos ligados a um barramento são ativos e podem iniciar transferências no barramento, ao passo que outros são passivos e esperam requisições. Os ativos são denominados mestres; os passivos são denominados escravos. Quando a CPU ordena a um controlador que leia ou escreva um bloco, ela está agindo como mestre e o controlador de disco, como escra- vo. Todavia, mais tarde, o controlador de disco pode agir como um mestre quando manda a memória aceitar as palavras que são lidas do drive de disco. árias combinações típicas mestre e escravo estão relacionadas na Figura 3.36. Em nenhuma circunstância a memória pode ser mestre. Figura 3.36 Exemplos de mestres e escravos de barramentos. Mestre Escravo Exemplo CPU Memória Buscar instruções e dados CPU Dispositivo de E/S Iniciar transferência de dados CPU Coprocessador CPU que passa instruções para o coprocessador Dispositivo de E/S Memória DMA (acesso direto à memória) Coprocessador CPU Coprocessador que busca operandos na CPU Os sinais binários emitidos por dispositivos de computador muitas vezes são fracos demais para energizar um barramento, em especial se ele for relativamente longo ou tiver muitos dispositivos ligados a ele. Por esse motivo, a maioria dos mestres de barramento está conectada a ele por um chip denominado controlador de barramento, que é nada mais que um amplificador digital. De modo semelhante, grande parte dos escravos está conectada ao barramento por um receptor de barramento. Quando dispositivos podem agir como mestres e também como escravos, é usado um chip combinado denominado transceptor de barramento. Essas interfaces de barramento são com frequência disposi- tivos de três estados, o que permite que flutuem (se desconectem) quando não são necessários ou então se conectem de modo um tanto diferente, denominado coletor aberto, que consegue um efeito semelhante. Quando dois ou mais dispositivos em uma linha de coletor aberto ativam a linha ao mesmo tempo, o resultado é o OR booleano de todos os sinais. Esse arranjo costuma ser denominado OR cabeado (wired-OR). Na maioria dos barramentos, algumas das linhas são de três estados, e outras, que precisam da propriedade OR cabeado, são de coletor aberto. Assim como uma CPU, um barramento também tem linhas de endereço, de dados e de controle. Contudo, nem sempre há um mapeamento um-para-um entre os pinos da CPU e os sinais do barramento. Por exemplo, algumas CPUs têm três pinos que codificam se ela está fazendo uma leitura de memória, uma escrita na memória, uma leitura de E/S, uma escrita de E/S ou alguma outra operação. Um barramento típico poderia ter uma linha para leitura de memória, uma segunda para escrita na memória, uma terceira para leitura de E/S, uma quarta para escrita de E/S e assim por diante. Nesse caso, seria necessário um chip decodificador entre a CPU e o barramento para compatibilizar os dois lados, isto é, converter o sinal de 3 bits codificado em sinais separados que podem comandar as linhas do barramento. Projeto e operação de barramento são questões de tamanha complexidade que há inúmeros livros escritos apenas sobre isso (Anderson et al., 2004; Solari e Willse, 2004). Os principais tópicos do projeto de barramento são largura, clock, arbitragem e operações. Cada um desses tópicos tem impacto substancial sobre a velocidade e a largura de banda do barramento. Agora, examinaremos cada um nas quatro seções seguintes. 3.4.3 Largura do barramento A largura do barramento é o parâmetro de projeto mais óbvio. Quanto mais linhas de endereço tiver um bar- ramento, mais memória a CPU pode endereçar diretamente. Se um barramento tiver n linhas de endereço, então
  • 169. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 150 uma CPU pode usá-las para endereçar 2n localizações de memória diferentes. Para memórias de grande porte, os barramentos precisam de muitas linhas de endereço, o que parece algo bem simples. O problema é que barramentos largos precisam de mais fios do que os estreitos, e também ocupam mais espaço físico (por exemplo, na placa-mãe), além de precisar de conectores maiores. Todos esses fatores encare- cem o barramento e, por isso, há um compromisso entre tamanho máximo de memória e custo do sistema. Um sistema com barramento de endereços de 64 linhas e 232 bytes de memória custará mais que um com 32 linhas e os mesmos 232 bytes de memória. A possibilidade de expansão posterior não é gratuita. O resultado dessa observação é que muitos projetistas de sistemas tendem a ser imediatistas, o que provoca consequências desastrosas mais tarde. O BM PC original continha uma CPU 8088 e um barramento de endereços de 20 bits, conforme mostra a Figura 3.37(a). Os 20 bits permitiam ao PC endereçar 1 MB de memória. Figura 3.37 Crescimento de um barramento de enderec os ao longo do tempo. 8088 (a) 80286 (b) 80386 (c) Endereço de 20 bits Controle Endereço de 20 bits Controle Endereço de 4 bits Controle Endereço de 20 bits Controle Endereço de 4 bits Controle Endereço de 8 bits Controle Quando lançou seu próximo chip de CPU (o 80286), a ntel decidiu aumentar o espaço de endereços para 16 MB, por isso precisou adicionar quatro linhas de barramento (sem mexer nas 20 originais, por razões de compa- tibilidade), como ilustrado na Figura 3.37(b). nfelizmente, mais linhas de controle tiveram de ser acrescentadas para lidar com as novas linhas de endereço. Quando o 80386 foi lançado, oito linhas de endereço foram adiciona- das, junto com ainda mais linhas de controle, como mostra a Figura 3.37(c). O projeto resultante (o barramento ESA) é muito mais confuso do que seria se o barramento tivesse 32 linhas desde o início. Não é apenas o número de linhas de endereço que tende a crescer com o tempo, mas também o número de linhas de dados, porém, por uma razão diferente. Há dois modos de aumentar a largura de banda de dados de um barramento: reduzir o tempo deste (mais transferências por segundo) ou aumentar sua largura de dados (mais bits por transferência). Acelerar o barramento é possível, mas difícil, porque os sinais trafegam em linhas dife- rentes com velocidades ligeiramente diferentes, um problema conhecido como atraso diferencial do barramento. Quanto mais rápido o barramento, mais sério se torna o atraso diferencial. Outro problema com a aceleração é que isso não será compatível. Placas antigas, projetadas para os barra- mentos mais lentos, não funcionarão com o novo. nvalidar as placas antigas descontentará não somente seus proprietários, mas também os fabricantes. Por conseguinte, a técnica que costuma ser adotada para melhorar o desempenho é adicionar linhas de dados, de forma análoga à Figura 3.37. Todavia, como era de esperar, no fim das contas esse crescimento incremental não leva a um projeto limpo. O BM PC e seus sucessores, por exemplo, passaram de oito linhas de dados para 16 e em seguida para 32, conservando praticamente o mesmo barramento. Para contornar o problema de barramentos muito largos, às vezes os projetistas optam por um barramento multiplexado. Nesse projeto, em vez de as linhas de endereços e dados serem separadas, há, por exemplo, 32 linhas para endereços e dados juntos. No início de uma operação de barramento, as linhas são usadas para o endereço.
  • 170. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 151 Mais tarde, são usadas para dados. Para uma escrita na memória, por exemplo, isso significa que as linhas de endereço devem ser estabelecidas e propagadas para a memória antes que os dados possam ser colocados no barramento. Com linhas separadas, endereços e dados podem ser colocados juntos. Multiplexar as linhas reduz a largura (e o custo) do barramento, mas resulta em um sistema mais lento. Quando tomam suas decisões, os projetistas de barramento têm de pesar cuidadosamente todas essas opções. 3.4.4 Clock do barramento Barramentos podem ser divididos em duas categorias distintas, dependendo de seu clock. Um barramento síncrono tem uma linha comandada por um oscilador de cristal. O sinal nessa linha consiste em uma onda qua- drada com uma frequência em geral entre 5 e 133 MHz. Todas as atividades do barramento tomam um número inteiro desses ciclos denominados ciclos de barramento. O outro tipo de barramento, o barramento assíncrono, não tem um clock mestre. Ciclos de barramento podem ter qualquer largura requerida e não são os mesmos entre todos os pares de dispositivos. A seguir, estudaremos cada tipo de barramento. Barramentos s ncronos Como exemplo do funcionamento de um barramento síncrono, considere o diagrama temporal da Figura 3.38(a). Nesse exemplo, usaremos um clock de 100 MHz, que dá um ciclo de barramento de 10 nanossegundos. Embora isso possa parecer um tanto lento em comparação a velocidades de CPU de 3 GHz ou mais, poucos bar- ramentos de PCs são muito mais rápidos. Por exemplo, o popular barramento PC normalmente funciona a 33 ou 66 MHz e o barramento PC- atualizado (porém agora extinto) funcionava a uma velocidade de até 133 MHz. As razões por que os barramentos atuais são lentos já foram dadas: problemas técnicos de projeto, como atraso diferencial de barramento e necessidade de compatibilidade. Em nosso exemplo, admitiremos ainda que ler da memória leva 15 ns a partir do instante em que o endereço está estável. Como veremos em breve, com esses parâmetros, ler uma palavra levará três ciclos de barramento. O primeiro ciclo começa na borda ascendente de T1 e o terceiro termina na borda ascendente de T4, como mostra a figura. Observe que nenhuma das bordas ascendentes ou descendentes foi desenhada na linha vertical porque nenhum sinal elétrico pode trocar seu valor em tempo zero. Nesse exemplo, admitiremos que leva 1 ns para o sinal mudar. As linhas de clock, address, data, mreq, rd e wait, estão todas representadas na mesma escala de tempo. O início de T1 é definido pela borda ascendente do clock. A meio caminho de T1 a CPU coloca o endereço da palavra que ela quer nas linhas de endereço. Como o endereço não é um valor único, como o clock, não podemos mostrá-lo como uma linha única na figura; em vez disso, ele é mostrado como duas linhas que se cruzam no ins- tante em que o endereço muda. Além disso, a área sombreada antes do cruzamento indica que o valor nessa área não é importante. Usando essa mesma convenção, vemos que o conteúdo das linhas de dados não é significativo até uma boa porção de T3. Depois que as linhas de endereço tiverem uma chance de se acomodar a seus novos valores, mreq e rd são ativados. O primeiro indica que é a memória (e não um dispositivo de E/S) que está sendo acessada e o segun- do é ativado (valor 0) para leituras e negado (valor 1) para escritas. Uma vez que a memória leva 15 ns após o endereço estar estável (a meio caminho no primeiro ciclo de clock), ela não pode entregar os dados requisitados durante T2. Para dizer à CPU que não os espere, a memória ativa a linha wait no início de T2. Essa ação irá inserir estados de espera (ciclos extras de barramento) até que a memória conclua e desative wait. Em nosso exemplo, foi inserido um estado de espera (T2) porque a memória é muito lenta. No início de T3, quando está certa de que terá os dados durante o ciclo corrente, a memória nega wait. Durante a primeira metade de T3, a memória coloca os dados nas linhas de dados. Na borda descendente de T3, a CPU mostra a linha de dados, isto é, lê a linha, armazenando (latching) o valor em um registrador interno. Após ter lido os dados, a CPU nega mreq e rd. Se for preciso, outro ciclo de memória pode começar na próxima borda ascendente do clock. Essa sequência pode ser repetida indefinidamente.
  • 171. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 152 Na especificação temporal da Figura 3.38(b), esclarecemos melhor oito símbolos que aparecem no diagrama. TAD, por exemplo, é o intervalo de tempo entre a borda ascendente do clock T1 e o estabelecimento das linhas de endereço. Conforme a especificação de temporização, TAD ≤ 4 ns. sso significa que o fabricante da CPU garante que durante qualquer ciclo de leitura a CPU entregará o endereço a ser lido dentro de 4 ns a partir do ponto médio da borda ascendente de T1. Figura 3.38 (a) Temporizac a o de leitura em um barramento s ncrono. (b) Especificac a o de alguns tempos cr ticos. Tempo (a) TAD TM TDS TMH TRH TDH TRL Φ T1 T2 T3 MREQ RD WAIT TML ADDRESS DATA Ciclo de leitura com 1 estado de espera Endereço de memória a ser lido Dados Símbolo Parâmetro Mín. Máx. Unidade TAD Atraso de saída do endereço 4 ns TML Endereço estável antes de MREQ 2 ns TM Atraso de MREQ desde a borda descendente de Φ em T1 3 ns TRL Atraso de RD desde a borda descendente de Φ em T1 3 ns TDS Tempo de ajuste dos dados antes da borda descendente de Φ 2 ns TMH Atraso de MREQ desde a borda descendente de Φ em T3 3 ns TRH Atraso de RD desde a borda descendente de Φ em T3 3 ns TDH Tempo de sustentação dos dados desde a negação de RD 0 ns (b) As especificações de temporização também requerem que os dados estejam disponíveis nas linhas de dados no mínimo TDS (2 nanossegundos) antes da borda descendente de T3 para lhes dar tempo para se acomodarem antes que a CPU os leia. A combinação de restrições impostas a Tad e TDS significa que, na pior das hipóteses, a memória terá somente 25 – 4 – 2 = 19 ns desde o instante em que o endereço aparece até o instante em que ela deve produzir os dados. Como 10 ns é suficiente, até mesmo no pior caso, uma memória de 10 ns sempre pode responder durante T3. Uma memória de 20 ns, entretanto, perderia o momento por pouco e teria de inserir um segundo estado de espera e responder durante T4.
  • 172. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 153 A especificação de temporização garante ainda mais que o endereço será estabelecido pelo menos 2 nanos- segundos antes de mreq ser ativado. Esse tempo pode ser importante se mreq comandar a seleção de chip no chip de memória, porque algumas memórias requerem um tempo de estabelecimento de endereço antes da seleção do chip. Claro que o projetista do sistema não deve escolher um chip de memória que necessite de um tempo de estabelecimento de 3 ns. As limitações impostas a TM e TRL significam que ambos, mreq e rd, serão ativados dentro de 3 ns a partir da borda descendente T1 do clock. No pior caso, o chip de memória terá somente 10 + 10 – 3 – 2 = 15 ns após a ativação de mreq e rd para levar seus dados até o barramento. Essa restrição é adicional ao (e independente do) intervalo de 15 ns necessário após o endereço estar estável. TMH e TRH informam quanto tempo leva para mreq e rd serem negados após a leitura dos dados. Por fim, TDH informa por quanto tempo a memória deve sustentar os dados no barramento após a negação de rd. No que diz respeito a nosso exemplo de CPU, a memória pode remover os dados do barramento tão logo rd tenha sido negado; porém, em algumas CPUs modernas, os dados devem ser conservados estáveis durante um pouco mais de tempo. Gostaríamos de destacar que a Figura 3.38 é uma versão muito simplificada das restrições reais de tempo. Na realidade, sempre são especificados muitos mais tempos críticos. Ainda assim, ela nos dá uma boa ideia do modo de funcionamento de um barramento síncrono. Uma última coisa que vale a pena mencionar é que sinais de controle podem ser ativados baixos ou altos. Cabe aos projetistas do barramento determinar o que é mais conveniente, mas a escolha é, em essência, arbitrária. Podemos entendê-la como equivalente em hardware à decisão que o programador toma de representar blocos de discos livres em um mapa de bits como 0s ou 1s. Barramentos ass ncronos Embora seja fácil trabalhar com barramentos síncronos por causa de seus intervalos discretos de tempo, eles também têm alguns problemas. Por exemplo, tudo funciona como múltiplos do clock do barramento. Ainda que CPU e memória possam concluir uma transferência em 3,1 ciclos, elas terão de prolongar o ciclo até 4,0 porque ciclos fracionários são proibidos. Pior ainda, uma vez escolhido o ciclo do barramento e construídas placas de memória e E/S para ele, é difícil aproveitar futuros avanços da tecnologia. Por exemplo, suponha que alguns anos após a construção do sistema da Figura 3.38 sejam lançadas novas memórias com tempos de acesso de 8 ns em vez de 15 ns, que eliminam o estado de espera e dão mais velocidade à máquina. Então, suponha que sejam lançadas memórias de 4 ns. Não haveria nenhum ganho adicional de desempenho porque, com esse projeto, o tempo mínimo para uma leitura é dois ciclos. Exprimindo esses fatos em termos um pouco diferentes, se um barramento síncrono tiver uma coleção hete- rogênea de dispositivos, alguns rápidos, alguns lentos, ele tem de ser ajustado para o mais lento, e os mais rápidos não podem usar todo o seu potencial. Pode-se utilizar tecnologia mista passando para um barramento assíncrono, isto é, que não tenha um clock mestre, como mostra a Figura 3.39. Em vez de vincular tudo ao clock, quando o mestre de barramento tiver ati- vado o endereço, mreq, rd e tudo o mais que precisa, em seguida ele ativa um sinal especial que denominaremos msyn (Master SYNchronization). Quando o escravo vê esse sinal, ele realiza o trabalho com a maior rapidez que puder e, ao concluir essa fase, ativa ssyn (Slave SYNchronization). Assim que o mestre perceber ssyn ativado, sabe que os dados estão disponíveis, portanto, ele os serializa e então desativa as linhas de endereço, junto com mreq, rd e msyn. Quando o escravo percebe a negação de msyn, sabe que o ciclo foi concluído, portanto, nega ssyn, e voltamos à situação original, com todos os sinais negados, esperando pelo próximo mestre. Diagramas temporais de barramentos assíncronos (e às vezes também os de barramentos síncronos) usam setas para mostrar causa e efeito, como na Figura 3.39. A ativação de msyn faz com que as linhas de dados sejam ativadas e também com que o escravo ative ssyn. A ativação de ssyn, por sua vez, causa a negação das linhas de endereço, mreq, rd e msyn. Por fim, a negação de msyn causa a negação e ssyn, que conclui a leitura e retorna o sistema a seu estado original.
  • 173. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 154 Figura 3.39 Operac a o de um barramento ass ncrono. ADDRESS MREQ RD MSYN DATA SSYN Dados Endereço de memória a ser lido Um conjunto de sinais que se interligam dessa maneira é denominado operação completa. A parte essencial consiste em quatro eventos: 1. msyn é ativado. 2. ssyn é ativado em resposta a msyn. 3. msyn é negado em resposta a ssyn. 4. ssyn é negado em resposta à negação de msyn. É preciso que fique claro que operações completas são independentes de temporização. Cada evento é causa- do por um evento anterior e não por um pulso de clock. Se determinado par mestre-escravo for lento, não afetará, de modo algum, um par mestre-escravo subsequente, que é muito mais rápido. Agora, a vantagem de um barramento assíncrono já deve estar bem clara, mas a verdade é que a maioria dos barramentos é síncrona. A razão é que é mais fácil construir um sistema síncrono. A CPU apenas ativa seus sinais e a memória apenas reage. Não há realimentação (causa e efeito), mas, se os componentes foram escolhidos adequadamente, tudo funcionará sem dependência. Além disso, há muito dinheiro investido na tecnologia do barramento síncrono. 3.4.5 Arbitragem de barramento Até aqui ficou subentendido que há somente um mestre de barramento, a CPU. Na realidade, chips de E/S têm de se tornar mestres de barramento para ler e escrever na memória e também para causar interrupções. Coprocessadores também podem precisar se tornar mestres de barramento. Então, surge a pergunta: “O que acontece se dois ou mais dispositivos quiserem se tornar mestres de barramento ao mesmo tempo?” A resposta é que é preciso algum mecanismo de arbitragem de barramento para evitar o caos. Mecanismos de arbitragem podem ser centralizados ou descentralizados. Em primeiro lugar, vamos consi- derar a arbitragem centralizada. Uma forma particularmente simples de arbitragem centralizada é mostrada na Figura 3.40(a). Nesse esquema, um único árbitro de barramento determina quem entra em seguida. Muitas CPUs contêm o árbitro no chip de CPU, mas às vezes é preciso um chip separado. O barramento contém uma única linha de requisição OR cabeada que pode ser afirmada por um ou mais dispositivos a qualquer tempo. Não há nenhum modo de o árbitro dizer quantos dispositivos requisitaram o barramento. As únicas categorias que ele pode distinguir são algumas requisições e nenhuma requisição. Quando o árbitro vê uma requisição de barramento, emite uma concessão que ativa a linha de concessão de barramento. Essa linha está ligada a todos os dispositivos de E/S em série, como um cordão de lâmpadas de
  • 174. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 155 árvore de Natal. Quando o dispositivo que está fisicamente mais próximo do árbitro vê a concessão, verifica para confirmar se fez uma requisição. Caso positivo, toma o barramento, mas não passa a concessão adiante na linha. Se não fez uma requisição, ele propaga a concessão até o próximo dispositivo na linha que se comporta da mesma maneira, e assim por diante, até algum deles aceitar a concessão e tomar o barramento. Esse esquema é denomi- nado encadeamento em série (daisy chaining). Ele tem a propriedade de designar prioridades aos dispositivos dependendo da distância entre eles e o árbitro. O que estiver mais próximo vence. Para contornar as prioridades implícitas baseadas na distância em relação ao árbitro, muitos barramentos têm vários níveis de prioridade. Para cada nível de prioridade há uma linha de requisição e uma linha de concessão de barramento. O barramento da Figura 3.40(b) tem dois níveis, 1 e 2 (barramentos reais costumam ter 4, 8 ou 16 níveis). Cada dispositivo está ligado a um dos níveis de requisição do barramento, sendo que os mais críticos em relação ao tempo estão ligados aos níveis com prioridade mais alta. Na Figura 3.40(b), os dispositivos 1, 2 e 4 usam prioridade 1, enquanto os dispositivos 3 e 5 usam prioridade 2. Se vários níveis de prioridade são requisitados ao mesmo tempo, o árbitro emite uma concessão somente ao de prioridade mais alta. Entre os dispositivos da mesma prioridade, é usado o encadeamento em série. Na Figura 3.40(b), se ocorrer algum conflito, o dispositivo 2 vence o dispositivo 4, que vence o 3. O dispositivo 5 tem a menor prioridade porque está no final da linha de encadeamento de menor prioridade. Figura 3.40 (a) A rbitro de barramento centralizado de um n vel usando encadeamento em se rie. (b) Mesmo a rbitro, mas com dois n veis. Requisição de barramento nível 1 Requisição de barramento nível 2 Concessão de barramento nível 2 Concessão de barramento nível 1 (a) (b) 1 2 3 4 5 1 2 3 4 5 Requisição de barramento Árbitro Concessão de barramento Concessão de barramento pode ser ou não propagada ao longo da cadeia Dispositivos de E/S Árbitro A propósito, tecnicamente não é necessário ligar a linha de concessão de barramento de nível 2 em série passando pelos dispositivos 1 e 2, já que eles não podem fazer requisições nessa linha. Contudo, por conveniência de execução, é mais fácil ligar todas as linhas de concessão passando por todos os dispositivos, em vez de fazer ligações especiais que dependem da prioridade de dispositivo. Alguns árbitros têm uma terceira linha que um dispositivo ativa quando aceita uma concessão e pega o barra- mento. Tão logo tenha ativado essa linha de reconhecimento, as linhas de requisição e concessão podem ser nega- das. O resultado é que outros dispositivos podem requisitar barramento enquanto o primeiro o estiver usando. No instante em que a transferência for concluída, o próximo mestre de barramento já terá sido selecionado. Ele pode começar logo que a linha de reconhecimento tenha sido negada, quando então pode ser iniciada a próxima rodada de arbitragem. Esse esquema requer uma linha de barramento extra e mais lógica em cada dispositivo, mas faz melhor uso de ciclos de barramento.
  • 175. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 156 Em sistemas em que a memória está no barramento principal, a CPU deve competir pelo barramento com todos os dispositivos de E/S em praticamente todos os ciclos. Uma solução comum para essa situação é dar à CPU a prioridade mais baixa, de modo que ela obtenha o barramento apenas quando ninguém mais o quiser. Nesse caso, a ideia é que a CPU sempre pode esperar, mas os dispositivos de E/S muitas vezes precisam adqui- rir logo o barramento ou então perdem os dados que chegam. Discos que giram a alta velocidade não podem esperar. Em muitos sistemas modernos de computadores, esse problema é evitado ao se colocar a memória em um barramento separado dos dispositivos de E/S de modo que estes não tenham de competir pelo acesso ao barramento. Também é possível haver arbitragem de barramento descentralizada. Por exemplo, um computador poderia ter 16 linhas de requisição de barramento priorizadas. Quando um dispositivo quer usar o barramento, ele afirma sua linha de requisição. Todos os dispositivos monitoram todas as linhas de requisição, de modo que, ao final de cada ciclo de barramento, cada dispositivo sabe se foi o requisitante de prioridade mais alta e, portanto, se tem permissão de usar o barramento durante o próximo ciclo. Comparado à arbitragem centralizada, o método descentralizado requer mais linhas de barramento, mas evita o custo potencial do árbitro. Além disso, limita o número de dispositivos ao número de linhas de requisição. Outro tipo de arbitragem de barramento descentralizada, mostrado na Figura 3.41, usa apenas três linhas, não importando quantos dispositivos estiverem presentes. A primeira é uma linha OR cabeada para requisitar o barramento. A segunda é denominada busy e é ativada pelo mestre de barramento corrente. A terceira linha é usada para arbitrar o barramento. Ela está ligada por encadeamento em série a todos os dispositivos. O início dessa cadeia é ativado ligando-o a uma fonte de alimentação. Figura 3.41 Arbitragem de barramento descentralizada. V 1 2 3 4 5 CC Requisição de barramento Busy (ocupado) Linha de arbitragem Entrada Saída Entrada Saída Entrada Saída Entrada Saída Entrada Saída Quando nenhum dispositivo quiser o barramento, a linha de arbitragem ativada é propagada por todos os outros. Para adquirir o barramento, um dispositivo primeiro verifica para ver se o barramento está ocioso e se o sinal de arbitragem que está recebendo, in (entrada), está ativado. Se in estiver negado, o dispositivo em ques- tão não pode se tornar o mestre de barramento e o sinal out (saída) é negado. Entretanto, se in for ativado, o dispositivo nega out, o que faz seu vizinho seguinte na cadeia ver in negado e negar seu próprio out. Daí, todos os dispositivos depois dele na cadeia veem in negado e, por sua vez, negam out. Quando o processo terminar, somente um dispositivo terá in ativado e out negado, e é ele que se torna o mestre de barramento, ativa busy e out e inicia sua transferência. Um pouco de raciocínio revelará que o dispositivo mais à esquerda que quiser o barramento o obtém. Assim, esse esquema é similar à arbitragem original por encadeamento em série, com a exceção de não ter o árbitro. Por isso é mais barato, mais rápido e não está sujeito a falhas do árbitro. 3.4.6 Operac o es de barramento Até agora, discutimos apenas ciclos de barramento comuns, com um mestre (em geral, a CPU) lendo de um escravo (em geral, a memória) ou escrevendo nele. Na verdade, existem vários outros tipos de ciclos de barra- mento. Em seguida, vamos estudar alguns deles.
  • 176. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 157 Em geral, só uma palavra é transferida por vez. Contudo, quando é usado caching, é desejável buscar uma linha inteira de cache (por exemplo, 8 palavras de 64 bits consecutivas) por vez. Transferências de blocos costu- mam ser mais eficientes do que transferências individuais sucessivas. Quando uma leitura de bloco é iniciada, o mestre de barramento informa ao escravo quantas palavras serão transferidas, por exemplo, colocando o núme- ro de palavras nas linhas de dados durante T1. Em vez de retornar apenas uma palavra, o escravo entrega uma durante cada ciclo até esgotar aquele número de palavras. A Figura 3.42 mostra uma versão modificada da Figura 3.38(a), mas agora com um sinal extra, block, que é ativado para indicar que foi requisitada uma transferência de bloco. Nesse exemplo, uma leitura de bloco de 4 palavras demora 6 ciclos em vez de 12. Figura 3.42 Transfere ncia de bloco. Φ T1 T2 T3 T4 T5 T6 T7 ADDRESS DATA MREQ RD WAIT BLOCK Endereço de memória a ser lido Contador Dados Dados Dados Dados Há também outros tipos de ciclos de barramento. Por exemplo, em um sistema multiprocessador com duas ou mais CPUs no mesmo barramento, muitas vezes é necessário garantir que só uma CPU por vez use alguma estrutura de dados crítica na memória. Um modo típico de organizar isso é ter uma variável na memória que é 0 quando nenhuma CPU estiver usando a estrutura de dados e 1 quando esta estiver em uso. Se uma CPU quiser obter acesso à estrutura de dados, deve ler a variável e, se esta for 0, passá-la para 1. O problema é que, com um pouco de má sorte, duas CPUs podem ler a variável em ciclos de barramento consecutivos. Se cada uma perceber que a variável é 0, então cada uma passa a variável para 1 e acha que é a única CPU que está usando a estrutura de dados. Essa sequência de eventos leva ao caos. Para evitar essa situação, sistemas multiprocessadores costumam ter um ciclo de barramento especial ler- -modificar-escrever que permite a qualquer CPU ler uma palavra da memória, inspecionar e modificar essa pala- vra, e escrevê-la novamente na memória, tudo sem liberar o barramento. Esse tipo de ciclo evita que uma CPU rival possa usar o barramento e assim interferir com a operação da primeira CPU. Outro tipo importante de ciclo de barramento é o usado para manipular interrupções. Quando ordena que um dispositivo de E/S faça algo, a CPU espera uma interrupção quando o trabalho for concluído. A sinalização da interrupção requer o barramento. Uma vez que vários dispositivos podem querer causar uma interrupção simultaneamente, os mesmos tipos de problemas de arbitragem que tivemos nos ciclos de barramento comuns também estão presentes aqui. A solução normal é atribuir prioridades a dispositivos e usar um árbitro centralizado para dar prioridade aos dis- positivos mais críticos em relação ao tempo. Existem chips controladores de interrupção padronizados que são muito usados. Em PCs baseados em processador ntel, o chipset incorpora um controlador de interrupção 8259A, ilustrado na Figura 3.43.
  • 177. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 158 Figura 3.43 Utilizac a o do controlador de interrupc a o 8259A. D0-D7 CS A0 WR INTA RD INT IR0 IR1 IR2 IR3 IR4 IR5 IR6 IR7 VCC CPU Controlador de interrupção 8259A Clock Teclado Disco Impressora Até oito controladores de E/S 8259A podem ser conectados direto às oito entradas irx (nterrupt Request – solicitação de interrupção) do 8259A. Quando qualquer um desses dispositivos quiser causar uma interrupção, ele ativa sua linha de entrada. Quando uma ou mais entradas são acionadas, o 8259A ativa int (NTerrupt – interrup- ção), que impulsiona diretamente o pino de interrupção na CPU. Quando a CPU puder manipular a interrupção, ela devolve o pulso ao 8259A por inta (NTerrupt Acknowledge – reconhecimento de interrupção). Nesse ponto, o 8259A deve especificar qual entrada causou interrupção passando o número daquela entrada para o barramento de dados. Essa operação requer um ciclo de barramento especial. Então, o hardware da CPU usa esse número para indexar em uma tabela de ponteiros, denominados vetores de interrupção, para achar o endereço do proce- dimento a executar para atender à interrupção. No interior do 8259A há diversos registradores que a CPU pode ler e escrever usando ciclos de barramento comuns e os pinos rd (ReaD), wr (WRite), cs (Chip Select) e a0. Quando o software tiver tratado da interrupção e estiver pronto para atender à seguinte, ele escreve um código especial em um dos registradores, que faz o 8259A negar NT, a menos que haja outra interrupção pendente. Esses registradores também podem ser escritos para colocar o 8259A em um de vários modos, mascarar um conjunto de interrupções e habilitar outras características. Quando mais de oito dispositivos de E/S estiverem presentes, os 8259As podem funcionar em cascata. No caso mais extremo, todas as oito entradas podem ser conectadas às saídas de mais oito 8259As, permitindo até 64 dispositivos de E/S em uma rede de interrupção de dois estágios. O hub controlador de E/S CH10 da ntel, um dos chips no chipset Core i7, incorpora dois controladores de interrupção 8259A. sso dá ao CH10 15 interrupções externas, uma a menos que as 16 interrupções nos dois controladores 8259A, pois uma das interrupções é usada para a operação em cascata do segundo 8259A para o primeiro. O 8259A tem alguns pinos dedicados a essa ope- ração em cascata, que omitimos por questão de simplicidade. Hoje, o “8259A” é, na realidade, parte de outro chip. Embora não tenhamos nem de perto esgotado a questão do projeto de barramento, o material que apresenta- mos até aqui deve oferecer fundamento suficiente para entender os aspectos essenciais do modo de funcionamen- to de um barramento e da interação entre CPUs e barramentos. Agora, vamos passar do geral para o específico e examinar alguns exemplos de CPUs reais e seus barramentos. 3.5 Exemplo de chips de CPUs Nesta seção, vamos examinar com algum detalhe os chips ntel Core i7, T OMAP4430 e Atmel ATmega168 no nível de hardware. 3.5.1 O Intel Core i7 O Core i7 é um descendente direto da CPU 8088 usada no BM PC original. O primeiro Core i7 foi lançado em novembro de 2008 como uma CPU de 731 milhões de transistores de quatro processadores que funcionava
  • 178. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 159 em 3,2 GHz com uma largura de linha de 45 nanômetros. Largura da linha quer dizer a largura dos fios entre transistores, assim como uma medida do tamanho dos próprios transistores. Quanto menor a largura da linha, mais transistores podem caber no chip. No fundo, a lei de Moore se refere à capacidade de os engenheiros de processo continuarem a reduzir as larguras das linhas. Para fins de comparação, os fios de cabelo humano ficam na faixa de 20 mil a 100 mil nanômetros de diâmetro, sendo o cabelo loiro mais fino do que o preto. A versão inicial da arquitetura Core i7 era baseada na arquitetura “Nahalem”; porém, as versões mais novas são montadas sobre a arquitetura “Sandy Bridge” mais recente. A arquitetura nesse contexto representa a organização interna da CPU, que costuma receber um codinome. Apesar de serem em geral pessoas sérias, os arquitetos de computador às vezes aparecerão com codinomes muito inteligentes para seus projetos. Uma arquitetura digna de nota foi a série K da AMD, projetada para quebrar a posição aparentemente invulnerável da ntel no segmento de CPU para desktop. O codinome dos processadores da série K foi “Kryptonite”, uma referência à única substância capaz de ferir o Super-homem, e um golpe inteligente na dominante ntel. O novo Core i7 baseado na Sandy Bridge evoluiu para ter 1,16 bilhão de transistores e trabalha em veloci- dades de até 3,5 GHz, com larguras de linha de 32 nanômetros. Embora o Core i7 esteja longe do 8088 com 29 mil transistores, ele é totalmente compatível com o 8088 e pode rodar sem modificação os programas binários do 8088 (sem falar também nos programas para todos os processadores intermediários). Do ponto de vista de software, o Core i7 é uma máquina completa de 64 bits. Tem todas as mesmas carac- terísticas SA de nível de usuário que os chips 80386, 80486, Pentium, Pentium , Pentium Pro, Pentium  e Pentium 4, inclusive os mesmos registradores, as mesmas instruções e uma execução completa no chip do padrão EEE 754 de ponto flutuante. Além disso, tem algumas novas instruções destinadas principalmente a operações criptográficas. O processador Core i7 é uma CPU multicore (de múltiplos núcleos), de modo que o substrato de silício contém vários processadores. A CPU é vendida com um número variável de processadores, que vai de 2 a 6, com outras configurações planejadas para o futuro próximo. Se os programadores escreverem um programa paralelo, usando threads e locks, é possível obter ganhos significativos na velocidade do programa, explorando o paralelismo nos múltiplos processadores. Além disso, as CPUs individuais são “hyperthreaded”, de modo que várias threads de hardware podem estar ativas simultaneamente. O hyperthreading (normalmente denominado “multithreading simultâneo” pelos arquitetos de computador) permite que latências muito curtas, como faltas de cache, sejam toleradas com trocas de thread de hardware. O threading baseado no software só pode tolerar latências muito longas, como faltas de página, devido às centenas de ciclos necessárias para executar as trocas de threads baseadas em software. Em sua parte interna, no nível da microarquitetura, o Core i7 é um projeto bastante capaz. Ele é baseado na arquitetura de seus predecessores, o Core 2 e Core 2 Due. O processador Core i7 pode executar até quatro ins- truções ao mesmo tempo, tornando-o uma máquina superescalar de largura 4. Examinaremos a microarquitetura no Capítulo 4. Todos os processadores Core i7 têm três níveis de cache. Cada processador em um processador Core i7 tem uma cache de dados de nível 1 (L1) com 32 KB e uma de instruções de nível 1 com 32 KB. Cada núcleo também tem sua própria cache de nível 2 (L2) com 256 KB. A cache de segundo nível é unificada, significando que pode ter uma mistura de instruções e dados. Todos os núcleos compartilham uma só cache unificada de nível 3 (L3), cujo tamanho varia de 4 a 15 MB, dependendo do modelo de processador. Ter três níveis de cache melhora sig- nificativamente o desempenho do processador, mas com um grande custo na área de silício, pois as CPUs Core i7 podem ter até 17 MB de cache total em um único substrato de silício. isto que todos os chips Core i7 têm múltiplos processadores com caches de dados privadas, surge um pro- blema quando uma CPU modifica uma palavra na cache privada que esteja contida na de outro processador. Se o outro processador tentar ler aquela palavra da memória, obterá um valor ultrapassado, já que palavras de cache modificadas não são escritas de imediato de volta na memória. Para manter a consistência da memória, cada CPU em um sistema microprocessador escuta (snoops) o barramento de memória em busca de referências de palavras que tenha em cache. Quando vê uma dessas referências, ela se apressa em fornecer os dados requisitados antes que a memória tenha chance de fazê-lo. Estudaremos a escuta (snooping) no Capítulo 8.
  • 179. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 160 Dois barramentos externos principais são usados nos sistemas Core i7, ambos síncronos. Um barramento de memória DDR3 é usado para acessar a DRAM de memória principal, e um barramento PC Express conecta o processador a dispositivos de E/S. ersões avançadas do Core i7 incluem memória múltipla e barramentos PC Express, e elas também incluem uma porta Quick Path nterconnect (QP). A porta QP conecta o processador a uma interconexão multiprocessadora externa, permitindo a montagem de sistemas com mais de seis proces- sadores. A porta QP envia e recebe requisições de coerência de cache, mais uma série de outras mensagens de gerenciamento de multiprocessador, como interrupções interprocessador. Um problema com o Core i7, bem como com a maioria das outras CPUs modernas do tipo desktop, é a energia que consome e o calor que gera. Para impedir danos ao silício, o calor deve ser afastado do substrato do processador logo após ser produzido. O Core i7 consome entre 17 e 150 watts, dependendo da frequência e do modelo. Por consequência, a ntel está sempre buscando meios de controlar o calor produzido por seus chips de CPU. As tecnologias de resfriamento e os dissipadores de calor são vitais para evitar que o silício se queime. O Core i7 vem em um pacote LGA quadrado com 37,5 mm de borda. Ele contém 1.155 pinos na parte infe- rior, dos quais 286 são para alimentação e 360 são aterramento, para reduzir o ruído. Os pinos são arrumados mais ou menos como um quadrado de 40 × 40, com os 17 × 25 do meio faltando. Além disso, 20 outros pinos estão faltando no perímetro em um padrão assimétrico, para impedir que o chip seja inserido incorretamente em sua base. A disposição física dos pinos aparece na Figura 3.44. Figura 3.44 Disposic a o f sica dos pinos no Core i7. O chip é equipado com uma placa de montagem para um dissipador distribuir o calor e um ventilador para resfriá-lo. Para ter uma ideia do tamanho do problema da potência, ligue uma lâmpada incandescente de 150 watts, deixe-a aquecer e depois coloque suas mãos ao seu redor (mas não a toque). Essa quantidade de calor deve ser dissipada continuamente por um processador Core i7 de última geração. Em consequência, quando o Core i7 não tiver mais utilidade como uma CPU, ele sempre poderá ser usado como um fogareiro em acampamentos. De acordo com as leis da física, qualquer coisa que emita muito calor deve absorver muita energia. Não é interessante usar muita energia em um computador portátil com carga de bateria limitada porque a bateria se esgota rapidamente. Para resolver essa questão, a ntel oferece um meio de pôr a CPU para dormir quando ela
  • 180. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 161 estiver ociosa e de fazê-la cair em sono profundo quando é provável que fique adormecida durante algum tempo. Há cinco estados oferecidos, que vão de totalmente ativa a sono profundo. Nos estados intermediários são habi- litadas algumas funcionalidades (tal como escuta de cache e manipulação de interrupção), mas outras funções são desativadas. Quando em estado de sono profundo, os valores de registradores são preservados, mas as caches são esvaziadas e desligadas. Nesse estado, é preciso que haja um sinal de hardware para despertá-la. Ainda não sabe- mos se um Core i7 pode sonhar quando está em sono profundo. Pinagem lo gica do Core i7 Os 1.155 pinos do Core i7 são usados para 447 sinais, 286 conexões de energia elétrica (em diversas volta- gens diferentes), 360 terras e 62 reservados para uso futuro. Alguns dos sinais lógicos usam dois ou mais pinos (tal como o endereço de memória requisitado), de modo que há somente 131 sinais diferentes. Uma pinagem lógica um pouco simplificada é dada na Figura 3.45. No lado esquerdo da figura, há cinco grupos principais de sinais de barramento; no lado direito, há diversos sinais variados. Figura 3.45 Pinagem lo gica do Core i7. Diagnósticos Monitoramento térmico Gerenciamento de energia Detecção de energia Configuração Diversos 18 124 124 80 16 21 286 360 4 10 7 24 12 Canal de memória DDR #1 Canal de memória DDR #2 Canal PCIe Interface de mídia direta Interface de monitor flexível CPU do Core i7 CK Energia Terra amos examinar os sinais, começando com os do barramento. Os dois primeiros sinais são usados para a interface com DRAM compatível com DDR3. Esse grupo oferece endereço, dados, controle e clock ao banco de DRAMs. O Core i7 admite dois canais DRAM DDR3 independentes, rodando com um clock de barramento de 666 MHz que transfere nas duas bordas, para permitir 1.333 milhões de transações por segundo. A interface DDR3 tem 64 bits de largura, e assim, as duas interfaces DDR3 trabalham em sequência para dar aos programas com muita utilização de memória até 20 gigabytes de dados a cada segundo. O terceiro grupo do barramento é a interface PC Express, que é usada para conectar periféricos diretamente à CPU Core i7. A interface PC Express é uma interface serial de alta velocidade, com cada enlace serial único formando uma “via” de comunicação com os periféricos. O enlace do Core i7 é uma interface x16, significando que pode utilizar 16 vias simultaneamente para uma largura de banda agregada de 16 GB/s. Apesar de ser um canal serial, um rico conjunto de comandos trafega pelos enlaces PC Express, incluindo comandos de leituras de dispositivo, escrita, interrupção e configuração. O grupo seguinte é a Direct Media nterface (DM), que é usada para conectar a CPU do Core i7 ao seu chip- set correspondente. A interface DM é semelhante à interface PC Express, embora trabalhe com cerca de metade da velocidade, pois quatro vias podem fornecer apenas taxas de transferência de dados de até 2,5 GB por segundo.
  • 181. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 162 O chipset de uma CPU contém um rico conjunto de suporte para interface de periférico adicional, exigido para sistemas de mais alto nível, com muitos dispositivos de E/S. O chipset do Core i7 é composto dos chips P67 e CH10. O chip P67 é o canivete suíço dos chips, oferecendo interfaces SATA, USB, Audio, PCe e memória flash. O chip CH10 oferece suporte para interface legada, incluindo uma interface PC e a funcionalidade de contro- le de interrupção do 8259A. Além disso, o CH10 contém alguns outros circuitos, como clocks de tempo real, temporizadores de eventos e controladores de acesso direto à memória (DMA). Ter chips como esses simplifica bastante a construção de um PC completo. O Core i7 pode ser configurado para usar interrupções do mesmo modo que o 8088 (para fins de compati- bilidade) ou também pode usar um novo sistema de interrupção que utiliza um dispositivo denominado PIC (dvanced Programmable Interrupt Controller  controlador de interrupção programável avançado). O Core i7 pode funcionar em quaisquer de várias tensões predefinidas, mas tem de saber qual delas. Os sinais de gerenciamento de energia são usados para seleção automática de tensão da fonte de alimentação, para informar à CPU que a energia está estável e outros assuntos relacionados com a energia. O controle dos vários estados de sono também é feito aqui, já que o sono acontece por razões de gerenciamento de energia. A despeito de seu sofisticado gerenciamento de energia, o Core i7 pode ficar muito quente. Para proteger o silício, cada processador Core i7 contém vários sensores de calor internos, que detectam quando o chip está para superaquecer. O grupo de monitoramento térmico trata do gerenciamento térmico, permitindo que a CPU indi- que a seu ambiente que está em risco de superaquecimento. Um dos pinos é ativado pela CPU caso a temperatura atinja 130°C (266°F). Se uma CPU alguma vez atingir essa temperatura, provavelmente estará sonhando com sua aposentadoria e posterior transformação em fogareiro de acampamento. Até mesmo em temperaturas de fogareiro de acampamento você não precisa se preocupar com a segurança do Core i7. Se os sensores internos detectarem que o processador está para superaquecer, ele iniciará o estrangu- lamento térmico, uma técnica que logo reduz a geração de calor, usando o processador apenas a cada N-ésimo ciclo de clock. Quanto maior o valor de N, mais o processador é estrangulado, e mais rápido ele se resfriará. É claro que o custo desse estrangulamento é uma diminuição no desempenho do sistema. Antes da invenção do estrangulamento térmico, as CPUs se queimavam se seu sistema de resfriamento falhasse. A evidência desses tem- pos negros do gerenciamento térmico da CPU pode ser achada procurando-se por “exploding CPU” no YouTube. O vídeo é falso, mas o problema não. O sinal Clock fornece o clock do sistema ao processador, que internamente é usado para gerar uma variedade de clocks com base em um múltiplo ou fração do clock do sistema. Sim, é possível gerar um múltiplo da frequência de clock, usando um dispositivo muito inteligente, chamado de delay-locked loop, ou DLL. O grupo Diagnósticos contém sinais para testar e depurar sistemas em conformidade com o padrão de testes EEE 1149.1 JTAG (Joint Test Action Group). Finalmente, o grupo Diversos é uma miscelânea de outros sinais que possuem diversas finalidades especiais. Paralelismo no barramento de memo ria do DDR3 do Core i7 CPUs modernas como o Core i7 colocam grandes demandas sobre as memórias DRAM. Os processadores individuais podem criar requisições de acesso muito mais depressa do que uma DRAM lenta consegue produzir valores, e esse problema é aumentado quando vários processadores estão fazendo requisições simultâneas. Para evitar que as CPUs morram por falta de dados, é essencial conseguir o máximo de vazão possível da memória. Por esse motivo, o barramento de memória DDR3 do Core i7 pode ser operado de uma forma paralela, com até quatro transações de memória simultâneas ocorrendo ao mesmo tempo. imos o conceito de paralelismo (ou pipelining) no Capítulo 2, no contexto de uma CPU em paralelo (ver Figura 2.4), mas as memórias também podem trabalhar com paralelismo. Para permitir o paralelismo, as requisições à memória do Core i7 têm três etapas: 1. A fase ACTATE da memória, que “abre” uma linha de memória DRAM, aprontando-a para acessos subsequentes à memória.
  • 182. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 163 2. A fase READ ou WRTE da memória, na qual vários acessos podem ser feitos a palavras individuais dentro da linha DRAM aberta ou a várias palavras sequenciais dentro da linha de DRAM atual, usando um modo de rajada. 3. A fase PRECHARGE, que “fecha” a linha de memória DRAM atual e prepara a memória DRAM para o próximo comando ACTATE. O segredo do barramento de memória com paralelismo do Core i7 é que as DRAMs DDR3 são organizadas com vários bancos dentro do chip de DRAM. Um banco é um bloco de memória DRAM, que pode ser acessa- do em paralelo com outros bancos de memória DRAM, mesmo que estejam contidos no mesmo chip. Um chip DRAM DDR3 típico terá até 8 bancos de DRAM. Porém, a especificação de interface DDR3 permite apenas até quatro acessos simultâneos sobre um único canal DDR3. O diagrama de temporização da Figura 3.46 ilustra o Core i7 fazendo 4 acessos à memória para três bancos de DRAM distintos. Os acessos são totalmente sobrepostos, de modo que as leituras de DRAM ocorrem em paralelo dentro do chip de DRAM. Com setas no diagrama de temporização, a figura mostra quais comandos levam a outras operações. Figura 3.46 Requisic o es de memo ria com paralelismo na interface DDR3 do Core i7. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 Ciclo de barramento CK CMD ADDR DATA ACT banco 0 ACT banco 1 READ banco 0 READ banco 1 ACT banco 2 PCHRG banco 0 READ banco 2 ACT banco 0 PCHRG banco 1 READ banco 0 PCHRG banco 2 PCHRG banco 0 linha banco 0 linha banco 1 col banco 0 col banco 1 linha banco 2 col banco 2 linha banco 0 col banco 0 dados banco 0 dados banco 1 dados banco 0 dados banco 2 Como vemos na Figura 3.46, a interface de memória DDR3 tem quatro caminhos de sinal principais: clock de barramento (CK), comando de barramento (CMD), endereço (ADDR) e dados (DATA). O sinal CK de clock de barramento orquestra toda a atividade deste. O comando de barramento CMD indica qual atividade é requi- sitada da DRAM de conexão. O comando ACTATE especifica o endereço de linha de DRAM a ser aberta por meio do sinal ADDR. Quando um READ é executado, o endereço de coluna da DRAM é dado por meio de sinais ADDR, e a DRAM produz o valor de leitura após um tempo fixo sobre os sinais DATA. Por fim, o comando PRECHARGE indica ao banco para pré-carregar por meio dos sinais ADDR. Para a finalidade do exemplo, o comando ACTATE deverá preceder o primeiro READ para o mesmo banco por dois ciclos de barramento DDR3, e os dados são produzidos um ciclo após o comando READ. Além disso, a operação PRECHARGE deverá ocorrer pelo menos dois ciclos de barramento após a última operação READ para o mesmo banco de DRAM. O paralelismo nas requisições de memória pode ser visto na sobreposição das requisições de READ para os diferentes bancos de DRAM. Os dois primeiros acessos READ aos bancos 0 e 1 são completamente superpostos, pro- duzindo resultados nos ciclos de barramento 3 e 4, respectivamente. O acesso ao banco 2 é em parte superposto ao primeiro acesso do banco 1, e por fim a segunda leitura do banco 0 é parcialmente superposta ao acesso ao banco 2.
  • 183. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 164 ocê pode estar questionando como o Core i7 sabe quando os dados do comando READ retornarão e quando ele pode fazer uma nova requisição à memória. A resposta é que ele sabe quando receber e iniciar requisições porque modela totalmente as atividades internas de cada DRAM DDR3 conectada. Assim, ele antecipará o retorno dos dados no ciclo correto e saberá evitar o início de uma operação de pré-carga antes que se passem dois ciclos de sua última operação de leitura. O Core i7 pode antecipar todas essas atividades porque a interface de memória DDR3 é uma interface de memória síncrona. Assim, todas as atividades usam um número bem conhecido de ciclos de barramento DDR3. Mesmo com todo esse conhecimento, a criação de uma interface de memória DDR3 com paralelismo completo e com alto desempenho é uma tarefa longe de ser trivial, exigindo muitos temporiza- dores internos e detectores de conflito para realizar o tratamento eficaz da requisição de DRAM. 3.5.2 O sistema-em-um-chip Texas Instruments OMAP4430 Como nosso segundo exemplo de um chip de CPU, examinaremos agora o sistema-em-um-chip Texas nstruments (T) OMAP4430. O OMAP4430 realiza o conjunto de instruções ARM e é voltado para aplicações móveis e embutidas, como smartphones, tablets e dispositivos da nternet. Com um nome apropriado, um sistema-em-um-chip incorpora uma grande variedade de dispositivos, de modo que, combinado com periféricos físicos (tela sensível ao toque, memória flash etc.), ele executa um dispositivo de computação completo. O sistema OMAP4430 inclui dois núcleos ARM A9, aceleradores adicionais e uma grande gama de inter- faces periféricas. A organização interna do OMAP4430 aparece na Figura 3.47. Os núcleos ARM A9 são micro- arquiteturas superescalares de largura 2. Além disso, existem mais três processadores aceleradores no substrato OMAP4430: o processador gráfico POWERR SG540, um processador de sinal de imagem (SP) e um processa- dor de vídeo A3. O SG540 oferece uma renderização 3D programável eficaz, semelhante às GPUs encontradas em PCs desktop, apesar de menores e mais lentas. O SP é um processador programável projetado para manipula- ção eficiente da imagem, para o tipo de operações que seriam exigidas em uma câmera digital avançada. O A3 executa codificação e decodificação eficientes de vídeo, com desempenho suficiente para dar suporte a aplicações 3D, como as encontradas em consoles de jogos portáteis. Há também no sistema OMAP4430 uma gama de inter- faces periféricas, incluindo uma tela sensível ao toque e controladores de teclado, DRAM e interfaces flash, USB e HDM. A Texas nstruments detalhou um roteiro para a série OMAP de CPUs. Projetos futuros terão mais de tudo – mais núcleos ARM, mais GPUs e mais periféricos diversos. Figura 3.47 Organizac a o interna do sistema-em-um-chip OMAP4430. SDRC IVA-HD 1080P 256KB SL2 mini64 466MHz 32KB L1 128KB L2 back-end de áudio LP L3 C2C EMIF1 LPDDR2 (400MHz) EMIF0 LPDDR2 (400MHz) L3 RAM no chip 48KB DAP Debug & trace MMCSD (w/DMA) 8-bit DDR Crypto DMA AES/SHA Periféricos L4 Per / emu / core / ABE Power Reset Clocks Manager GPMC NAND/NOR externo IVA3 DMM Segundo canal LPDDR2 LPDDR2 NAND/NOR cJTAG STP ETM 8-bit HS-MMC (x) 4-bit HS-MMC (x) 12C (x) UART (x) SPI (x) McBS (x) Slimbus GPIOs (max) RESET, CLOCKS, POWER CTRLS Modem ou acelerador externo Falante E/S Mic A e D E/S PMIC E/S IRQs Ducati 200Mhz Imagem Câmera E/S Requisição de DMA USB2.0 OTG USB2.0 HDMI TV PAL/NTSC Display múltiplo E/S C2C Acelerador de segurança ARMv7 MPU 32KB/32KB L1 1MB L2 64KB.RAM 128KB ROM SGX540 2D/3D C2C 200MHz (DDR) DSS Display (DSI/HDMI) SDMA SIMCOP 3-port USB-HS Host UNIPRO Extensões HSI ISP5 HSI USB-HS Interconexão de alta largura de banda com suporte de memória multicanal
  • 184. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 165 O sistema OMAP4430 foi lançado no início de 2011 com dois núcleos ARM A9 rodando a 1 GHz usando uma implementação de silício de 45 nanômetros. Um aspecto chave do projeto do OMAP4430 é que ele realiza quantidades significativas de cálculo com muito pouca potência, pois é visado para aplicações móveis, alimenta- das por uma bateria. Em tais aplicações, quanto mais eficiente for a operação do projeto, mais tempo o usuário poderá ficar sem carregar a bateria. Os muitos processadores do OMAP4430 são incorporados para dar suporte à missão de operação com baixa potência. O processador gráfico, SP, e o A3 são todos aceleradores programáveis que fornecem capacidades de cálculo eficientes com significativamente menos energia em comparação com as mesmas tarefas sendo executadas apenas nas CPUs ARM A9. Totalmente alimentado, o sistema MAP4430 consome apenas 600 mW de potência. Em comparação com o Core i7 avançado, o OMAP4430 usa cerca de 1/250 de sua potência. O OMAP4430 tam- bém executa um modo de sono muito eficaz; quando todos os componentes estão dormindo, o projeto consome somente 100 µW. Modos de sono eficientes são fundamentais para aplicações móveis com longos períodos de tempo de standby, como um telefone celular. Quanto menos energia usada no modo de sono, mais tempo o tele- fone celular durará no modo standby. Para reduzir ainda mais as demandas de potência do OMAP4430, o projeto incorpora uma série de facilida- des de gerenciamento de energia, incluindo a escalada dinâmica de tensão e o chaveamento de energia. A escala- da dinâmica de tensão permite que os componentes sejam executados mais devagar em uma tensão inferior, o que reduz bastante os requisitos de potência. Se você não precisa da velocidade de computação mais ardente da CPU, a tensão do projeto pode ser reduzida para que a CPU trabalhe em uma velocidade mais lenta e muita energia será economizada. O chaveamento de energia é uma técnica de gerenciamento ainda mais agressiva, na qual um componente é desligado por completo quando não estiver em uso, eliminando assim seu consumo de energia. Por exemplo, em uma aplicação de tablet, se o usuário não estiver assistindo a um filme, o processador de vídeo A3 é completamente desligado e não consome energia. Por outro lado, quando o usuário está assistindo a um filme, o processador de vídeo A3 trabalha ao máximo em suas tarefas de decodificação de vídeo, enquanto as duas CPUs ARM A9 estão dormindo. Apesar de sua tendência para uma operação com economia de energia, os núcleos ARM A9 utilizam uma microarquitetura bastante capaz. Eles podem decodificar e executar até duas instruções a cada ciclo. Conforme aprenderemos no Capítulo 4, essa taxa de execução representa a vazão máxima da microarquitetura. Mas não espere que ela execute suas muitas instruções a cada ciclo. Em vez disso, pense nessa taxa como o desempenho máximo garantido pelo fabricante, um nível que o processador nunca excederá, não importa o que aconteça. Em muitos ciclos, menos de duas instruções serão executadas devido aos milhares de “hazards” (acasos) que podem adiar as instruções, levando a uma vazão de execução mais baixa. Para resolver muitos desses limitadores de vazão, o ARM A9 incorpora um poderoso previsor de desvio, escalonamento de instruções fora de ordem e um sistema de memória altamente otimizado. O sistema de memória do OMAP4430 tem duas caches L1 internas principais para cada processador ARM A9: uma de 32 KB para instruções e uma de 32 KB para dados. Assim como o Core i7, ele também usa uma cache nível 2 (L2) no chip, mas, diferente do Core i7, ela é uma memória de 1 MB relativamente pequena em tamanho, sendo compartilhada por ambos os núcleos ARM A9. As caches são alimentadas com canais de DRAM duais LPDDR2 de baixa potência. LPDDR2 é derivada do padrão de interface de memória DDR2, porém alterada para exigir menos fios e operar em tensões mais eficientes em termos de potência. Além disso, o controlador de memória incorpora uma série de otimizações de acesso à memória, como a pré-busca de memória ladrilhada e o suporte para rotação na memória. amos discutir caching em detalhes no Capítulo 4, mas é bom dizer algumas palavras sobre ela aqui. Toda memória principal é dividida em linhas (blocos) de cache de 32 bytes. As 1.024 linhas de instrução mais usadas e as 1.024 linhas de dados mais usadas estão na cache de nível 1. Linhas de cache que são muito usadas mas não cabem na de nível 1 são mantidas na de nível 2. Essa cache contém linhas de dados e linhas de instrução de ambas as CPUs ARM A9 misturadas aleatoriamente. A cache de nível 2 contém as 32.768 linhas acessadas mais recentemente na memória principal.
  • 185. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 166 Quando há uma ausência na cache de nível 1, a CPU envia o identificador da linha que está procurando (endereço de tag) para a cache de nível 2. A resposta (dados de tag) informa à CPU se a linha está ou não na cache de nível 2 e, se estiver, informa também o estado em que esta se encontra. Se a linha estiver na cache, a CPU vai pegá-la. Para obter um valor da cache de nível 2, são necessários 19 ciclos. Esse é um longo tempo para esperar os dados, de modo que programadores inteligentes otimizarão seus programas para usar menos dados, aumentando a probabilidade de achar os dados na cache rápida de nível 1. Se a linha de cache não estiver na cache de nível 2, ela deve ser buscada da memória principal por meio da interface de memória LPDDR2. A interface LPDDR2 do OMAP4430 é executada no chip de modo que a DRAM LPDDR2 possa ser conectada diretamente ao OMAP4430. Para acessar a memória, a CPU primeiro deve enviar a parte superior do endereço da DRAM ao chip de DRAM, usando as 13 linhas de endereço. Essa operação, cha- mada ACTIVATE, carrega uma linha inteira de memória da DRAM para um buffer de linha. Depois disso, a CPU pode emitir vários comandos read ou write, enviando o restante do endereço nas mesmas 13 linhas de endereço e enviando (ou recebendo) os dados para a operação nas 32 linhas de dados. Enquanto espera os resultados, a CPU pode perfeitamente continuar executando outro trabalho. Por exem- plo, uma ausência na cache durante a busca antecipada de uma instrução não inibe a execução de uma ou mais instruções já buscadas, cada uma das quais pode se referir a dados que não estão em quaisquer das caches. Assim, várias transações com as mesmas interfaces LPDDR2 podem estar pendentes ao mesmo tempo, até para o mesmo processador. Cabe ao controlador de memória monitorar tudo isso e fazer requisições de memória propriamente ditas na ordem mais eficiente. Quando os dados por fim chegam da memória, podem vir em 4 bytes por vez. Uma operação de memória pode utilizar uma leitura ou escrita no modo rajada, permitindo que vários endereços contíguos dentro da mesma linha da DRAM sejam lidos ou escritos. Esse modo é particularmente eficaz para ler ou escrever blocos de cache. Apenas por registro, a descrição do OMAP4430 dada aqui, como a do Core i7 antes dele, foi bastante simplificada, mas a essência de sua operação foi descrita. O OMAP4430 vem em uma matriz em grade de bola (PBGA) de 547 pinos, conforme mostra a Figura 3.48. Uma matriz em grade de bola é semelhante a uma matriz de grade de terra, exceto que as conexões no chip são pequenas bolas de metal, em vez de plataformas quadradas usadas na LGA. Os dois pacotes não são compatíveis, oferecendo mais evidência de que você não pode encaixar uma ponta quadrada em um furo redondo. O pacote do OMAP4430 consiste em uma matriz retangular de 28 × 26 bolas, com os dois anéis de bolas mais internos faltando, e mais duas meias linhas e colunas assimétricas de bolas faltando, para impedir que o chip seja inserido incorretamente no soquete BGA. Figura 3.48 A pinagem sistema-em-um-chip OMAP4430.
  • 186. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 167 É difícil comparar um chip CSC (como o Core i7) e um chip RSC (como o OMAP4430) apenas com base na velocidade do clock. Por exemplo, os dois núcleos ARM A9 no OMAP4430 têm uma velocidade máxima de execução de quatro instruções por ciclo de clock, dando-lhe quase a mesma taxa de execução dos processadores superescalares de largura 4 do Core i7. Entretanto, o Core i7 alcança execução de programa mais rápida, pois tem até seis processadores rodando com uma velocidade de clock 3,5 vezes mais rápida (3,5 GHz) que o OMAP4430. O OMAP4430 pode parecer uma tartaruga correndo ao lado da lebre do Core i7, mas a tartaruga usa muito menos potência, e pode terminar primeiro, ainda mais se a bateria da lebre não for muito grande. 3.5.3 O microcontrolador Atmel ATmega168 Tanto o Core i7 quanto a OMAP4430 são exemplos de CPUs de alto desempenho projetadas para construir dispositivos de computação altamente eficazes, com o Core i7 voltado para aplicações de desktop enquanto o OMAP4430 é voltado para aplicações móveis. Quando pensam em computadores, são esses os tipos de sistemas que muitas pessoas têm em mente. Entretanto, existe todo outro universo de computadores que na verdade é muito maior: sistemas embutidos. Nesta seção, vamos examinar brevemente esse outro universo. Talvez não seja um grande exagero dizer que todo equipamento elétrico que custe mais de 100 dólares tem um computador dentro dele. Hoje, é certo que televisores, telefones celulares, agendas eletrônicas, fornos de micro-ondas, filmadoras, aparelhos de DD, impressoras a laser, alarmes antifurto, aparelhos de surdez, jogos eletrônicos e outros incontáveis dispositivos são todos controlados por computador. Os computadores que estão dentro desses aparelhos costumam ser otimizados para baixo preço e não para alto desempenho, o que provoca compromissos diferentes dos feitos para CPUs de tecnologia avançada que estudamos até aqui. Como mencionamos no Capítulo 1, o Atmel ATmega168 provavelmente é o microcontrolador mais popular em uso hoje, em grande parte por causa de seu custo muito baixo (cerca de 1 dólar). Como veremos em breve, ele também é um chip versátil, portanto, fazer interface com ele é algo simples e barato. Agora, vamos examinar esse chip, cuja pinagem física é mostrada na Figura 3.49. Figura 3.49 Pinagem f sica do ATmega168. PC5 PC4 PC3 PC2 PC1 PC0 GND AREF AVCC PB4 PB3 PB2 PB1 PB5 28 27 26 25 24 23 22 21 20 19 18 17 16 15 1 2 3 4 5 6 7 8 9 10 11 12 13 14 PC6 PD0 PD1 PD2 PD3 PD4 VCC GND PB6 PB7 PD5 PD6 PD7 PB0 Como podemos ver na figura, o ATmega168 normalmente vem em um pacote padrão de 28 pinos, embo- ra haja outros pacotes disponíveis. À primeira vista, você talvez tenha notado que a pinagem nesse chip é um pouco estranha em comparação com os dois projetos anteriores que examinamos. Em particular, esse chip não tem linhas de endereço e dados. sso porque não foi projetado para ser conectado à memória, só a dispositivos. Toda a memória, SRAM e flash, está contida dentro do processador, evitando a necessidade de quaisquer pinos de endereço e dados, como mostra a Figura 3.50.
  • 187. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 168 Figura 3.50 Arquitetura interna e pinagem lo gica do ATmega168. 2 6 GND VCC BARRAMENTO DE DADOS Temporizador watchdog Oscilador watchdog Circuitos osciladores/ geração de clock EEPROM Supervisão de energia POR/BOD & RESET Flash debugWIRE Lógica de programa SRAM CPU T/C 0 de 8 bits T/C 1 de 16 bits Conv. A/D T/C 2 de 8 bits Comp. analógico Lacuna de banda interna PORTA D (8) PORTA B (8) PORTA C (7) USART 0 SPI TWI AVCC AREF GND RESET PD[0..7] PB[0..7] PC[0..6] ADC[6..7] XTAL[1..2] Em vez de pinos de endereço e dados, o ATmega168 tem 27 portas de E/S digitais, 8 linhas na porta B e D, e 7 linhas na porta C. Essas linhas de E/S digitais são projetadas para serem conectadas aos periféricos de E/S, e cada uma pode ser configurada internamente pelo software de partida para ser uma entrada ou uma saída. Por exemplo, quando usada em um forno de micro-ondas, uma linha de E/S digital seria uma entrada do sensor de “porta aberta”. Outra linha de E/S digital seria uma saída usada para ligar e desligar o gerador do micro-ondas. O software no ATmega168 verificaria se a porta estava fechada antes de ligar o gerador do micro-ondas. Se a porta de repente for aberta, o software deverá cortar a energia. Na prática, as interconexões de hardware também estão sempre presentes.
  • 188. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 169 Como opção, seis das entradas da porta C podem ser configuradas para serem E/S analógica. Pinos de E/S analógica podem ler o nível de tensão de uma entrada ou definir o nível de tensão de uma saída. Estendendo nosso exemplo de forno de micro-ondas, alguns aparelhos têm um sensor que permite ao usuário aquecer o alimento até determinada temperatura. O sensor de temperatura seria conectado a uma entrada de porta C, e o software poderia ler a tensão do sensor e depois convertê-la em uma temperatura usando uma função de tradução específica do sensor. Os pinos restantes no ATmega168 são a entrada de tensão (vcc), dois pinos de terra (gnd) e dois pinos para configurar os circuitos de E/S analógica (aref, avcc). A arquitetura interna do ATmega168, como a do OMAP4430, é um sistema-em-um-chip com uma rica matriz de dispositivos internos e memória. O ATmega168 vem com até 16 KB de memória flash interna, para armazenamento de informações não voláteis que mudam com pouca frequência, como instruções de programa. Ele também inclui até 1 KB de EEPROM, a memória não volátil que pode ser gravada pelo software. A EEPROM guarda dados de configuração do sistema. De novo, usando nosso exemplo de micro-ondas, a EEPROM armaze- naria um bit indicando se o micro-ondas mostrará a hora em formato de 12 ou 24 horas. O ATmega168 também incorpora até 1 KB de SRAM interna, onde o software pode armazenar variáveis temporárias. O processador interno roda o conjunto de instruções AR, que é composto de 131 instruções, cada uma com 16 bits de extensão. O processador tem 8 bits, o que significa que opera sobre valores de dados de 8 bits, e internamente seus registradores possuem um tamanho de 8 bits. O conjunto de instruções incorpora instruções especiais que permitem ao processador de 8 bits operar de modo eficiente sobre tipos de dados maiores. Por exemplo, para realizar adições de 16 bits ou maiores, o processador fornece a instrução “add- -with-carry” (somar com vai-um), que soma dois valores e mais o “vai-um” da adição anterior. Os outros componentes internos englobam o clock em tempo real e uma variedade de lógica de interface, incluindo suporte para enlaces seriais, enlaces PWM (pulse-width-modulated – modulado por largura de pulso), enlaces 2C (barramento nter-C) e controladores analógico e digital. 3.6 Exemplos de barramentos Barramentos são a cola que mantém a integridade dos sistemas de computadores. Nesta seção, examinaremos minuciosamente alguns barramentos populares: o PC e o USB (Universal Serial Bus – barramento serial univer- sal). O PC é o principal barramento de E/S usado hoje em dia nos PCs. Ele pode ter duas formas, o barramento PC mais antigo, e o novo e muito mais rápido barramento PC Express (PCe). O Universal Serial Bus é um barramento de E/S cada vez mais popular para periféricos de baixa velocidade, como mouses e teclados. Uma segunda e terceira versões do barramento USB rodam com velocidades muito mais altas. Nas próximas seções, veremos esses barramentos um por vez, para ver como eles funcionam. 3.6.1 O barramento PCI No BM PC original, a maioria das aplicações era baseada em texto. De modo gradual, com a introdução do Windows, pouco a pouco começaram a ser usadas as interfaces gráficas de usuário. Nenhuma dessas aplicações exigia demais do barramento SA. Contudo, com o passar do tempo, quando muitas aplicações, em especial jogos em multimídia, começaram a usar computadores para exibir vídeo em tela cheia e com movimento completo, a situação mudou radicalmente. amos fazer um cálculo simples. Considere um vídeo colorido de 1.024 × 768 com 3 bytes/pixel. Um quadro contém 2,25 MB de dados. Para um movimento suave, são necessárias ao menos 30 telas por segundo para uma taxa de dados de 67,5 MB por segundo. Na verdade, é pior do que isso, pois para apresentar um vídeo a partir de um disco rígido, CD-ROM ou DD, os dados devem passar do drive de disco para o barra- mento e ir até a memória. Então, para a apresentação, os dados devem novamente percorrer o barramento até o adaptador gráfico. Portanto, precisamos de uma largura de banda de barramento de 135 MB por segundo só para o vídeo, sem contar a largura de banda de que a CPU e outros dispositivos precisam.
  • 189. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 170 O predecessor do barramento PC, o SA, funcionava à taxa máxima de 8,33 MHz e podia transferir 2 bytes por ciclo para uma largura de banda máxima de 16,7 MB/s. O barramento SA avançado, denominado ESA, podia movimentar 4 bytes por ciclo, para alcançar 33,3 MB/s. Claro que nenhuma dessas taxas sequer chegava perto do que era necessário para apresentação de vídeo completo em tela. Com o vídeo de HD completo moderno, a situação é ainda pior. sso exige 1.920 × 1.080 quadros a 30 qua- dros/segundo para uma taxa de dados de 155 MB/s (ou 310 MB/s se os dados tiverem que atravessar o barramento duas vezes). É claro que o barramento ESA sequer chegar perto de tratar disso. Em 1990, a ntel percebeu o que estava para acontecer e desenvolveu um novo barramento com uma largura de banda muito mais alta do que a do próprio barramento ESA. Foi denominado barramento PCI (Peripheral Component Interconnect Bus  barramento de interconexão de componente periférico). Para incentivar sua utilização, a ntel patenteou o PC e então passou todas as patentes para domínio público, de modo que qualquer empresa podia construir periféricos para esse barramento sem ter de pagar royalties. Ela também organizou um consórcio de empresas, o PC Special nterest Group, para gerenciar o futuro desse barramento. O resultado foi que o PC alcançou enorme popularidade. Praticamente todos os computadores com chips ntel a partir do Pentium têm barramento PC, e muitos outros computadores também. Esse barramento é apresentado com todos os detalhes tétricos em Shanley e Anderson (1999) e Solari e Willse (2004). O barramento PC original transferia 32 bits por ciclo e funcionava em 33 MHz (tempo de ciclo de 30 ns) para uma largura de banda total de 133 MB/s. Em 1993, foi lançado o PC 2.0 e em 1995 saiu o PC 2.1. O PC 2.2 tem características para computadores portáteis (principalmente para economizar energia da bateria). O barramento PC funciona em até 66 MHz e pode manipular transferências de 64 bits para uma largura de banda total de 528 MB/s. Com esse tipo de capacidade, o vídeo de tela inteira e movimento total é viável (admitindo que o disco e o resto do sistema estejam à altura do serviço). Seja como for, o PC não será o gargalo. Mesmo que 528 MB/s pareça muito rápido, ainda há dois problemas. Primeiro, não era muito bom para um barramento de memória. Segundo, não era compatível com todas aquelas antigas placas SA que havia por aí. A solução imaginada pela ntel foi projetar computadores com três ou mais barramentos, conforme mostra a Figura 3.51. Nessa figura, vemos que a CPU pode se comunicar com a memória principal por um barramento de memó- ria especial, e que um barramento SA pode ser conectado ao PC. Esse arranjo atendia a todos os requisitos e, por consequência, foi amplamente usado na década de 1990. Dois componentes fundamentais dessa arquitetura são os dois chips de pontes, fabricados pela ntel – daí seu interesse em todo esse projeto. A ponte PC conecta a CPU, a memória e o barramento PC. A ponte SA conecta o barramento PC ao SA e também suporta um ou dois discos DE. Quase todos os sistemas PC usando essa arquitetura vêm com um ou mais encaixes PC livres para acrescentar novos periféricos de alta velocidade e um ou mais encaixes SA para acrescentar periféricos de baixa velocidade. A grande vantagem do arranjo da Figura 3.51 é que a CPU tem uma largura de banda extremamente alta para a memória usando um barramento de memória proprietário; o PC oferece alta largura de banda para periféricos rápidos, como discos SCS, adaptadores gráficos etc.; e as antigas placas SA ainda podem ser usadas. A caixa USB na figura se refere ao Universal Serial Bus, que será discutido mais adiante neste capítulo. Seria bom se houvesse apenas um tipo de placa PC. Porém, não é esse o caso. Há opções para tensão, lar- gura e temporização. Computadores mais antigos usam em geral 5 volts e os mais novos tendem a usar 3,3 volts, portanto, o barramento PC suporta ambos. Os conectores são os mesmos, exceto por dois pedacinhos de plástico que estão lá para impedir que as pessoas insiram uma placa de 5 volts em um barramento PC de 3,3 volts ou vice-versa. Felizmente, existem placas universais que suportam ambas as tensões e podem ser ligadas a quaisquer dos tipos de encaixe. Além da opção de tensão, as placas também têm versões de 32 bits e 64 bits. As placas de 32 bits têm 120 pinos; as de 64 bits têm os mesmos 120 pinos mais 64 pinos adicionais. Um sistema de barramento PC que suporta placas de 64 bits também pode aceitar placas de 32 bits, mas o inverso não é verdade. Por fim, barramentos e placas PC podem funcionar em 33 MHz ou 66 MHz. A opção é feita ligando um pino à fonte de energia ou ao fio terra. Os conectores são idênticos para ambas as velocidades.
  • 190. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 171 Figura 3.51 Arquitetura de um dos primeiros sistemas Pentium. Os barramentos representados por linhas mais largas te m mais largura de banda do que os representados por linhas mais finas, mas a figura na o esta  em escala. Barramento de cache Barramento local Barramento de memória Cache de nível 2 CPU Ponte PCI Memória principal Barramento PCI SCSI USB Mouse Teclado Ponte ISA Disco IDE Adaptador gráfico Mo- nitor Encaixe PCI disponível Barramento ISA Modem Placa de som Impres- sora Encaixe ISA disponível No final da década de 1990, quase todos concordavam que o barramento SA estava morto, portanto, os novos projetos o excluíram. Contudo, nessa mesma época a resolução de monitores tinha aumentado, em alguns casos para 1.600 × 1.200, e a demanda por vídeo de tela inteira e movimento total também cresceu, em especial no con- texto de jogos de alto grau de interação, portanto, a ntel acrescentou mais um outro barramento só para comandar a placa gráfica. Esse barramento foi denominado barramento GP (ccelerated Graphics Port bus  barramento de porta gráfica acelerada). A versão inicial, AGP 1.0, funcionava a 264 MB/s, o que foi definido como 1x. Embora mais lento que o barramento PC, foi dedicado a comandar a placa gráfica. Com o passar dos anos, saíram novas versões, com AGP 3.0 funcionando a 2,1 GB/s (8x). Hoje, até mesmo o barramento AGP 3.0 de alto desempenho foi substituído por outros ainda mais rápidos, em particular, o PC Express, que pode bombear incríveis 16 GB/s de dados por enlaces de barramento serial de alta velocidade. Um sistema Core i7 moderno é ilustrado na Figura 3.52. Em um sistema moderno baseado no Core i7, diversas interfaces foram integradas diretamente no chip da CPU. Os dois canais de memória DDR3, rodando a 1.333 transações/s, conectam-se à memória principal e oferecem uma largura de banda agregada de 10 GB/s por canal. Também integrado à CPU está um canal PC Express de 16 vias, que idealmente pode ser configurado em um único barramento PC Express de 16 bits ou barramentos PC Express independentes de 8 bits. As 16 vias juntas oferecem uma largura de banda de 16 GB/s para dispositivos de E/S. A CPU se conecta ao chip da ponte principal, o P67, por meio da interface de mídia direta (DM) serial de 20 Gb/s (2,5 GB/s). O P67 oferece interfaces para uma série de interfaces de E/S modernas de alto desempenho. Oito vias PC Express adicionais são fornecidas, mais interfaces de disco SATA. O P67 também executa 14 interfaces USB 2.0, Ethernet de 10G e uma de áudio. O chip CH10 oferece suporte a interface legada para dispositivos antigos. Ele está conectado ao P67 por meio de uma interface DM mais lenta. O CH10 implementa o barramento PC, Ethernet a 1G, portas USB e as clássicas interfaces PC Express e SATA. Sistemas mais novos não podem incorporar o CH10; isso é exigido apenas se o sistema precisa dar suporte a interfaces legadas.
  • 191. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 172 Figura 3.52 Estrutura do barramento de um Core i7 moderno. Gráficos PCI Express 2.0 ou Gráficos PCI Express 2.0 (opcional) Gráficos PCI Express 2.0 (opcional) 16 vias 16 GB/s 8 vias 8 GB/s 8 vias 8 GB/s Intel Core i7 DDR3 a 1.333 MHz DDR3 a 1.333 MHz DMI a 20 Gb/s 14 portas USB 2.0 de alta velocidade; EHCI dual; porta USB desabilitada MAC 100/1G/10G integrado à Intel Conexão de LAN Gigabit da Intel 40 Mb/s cada Chipset Intel P67 Express 5 Gb/s cada x1 Até 6 Gb/s2 Áudio de alta definição da Intel 8 PCI Express 2.0 6 portas seriais ATA; eSATA; desativação de porta Tecnologia de armazenamento rápido da Intel (opcional) 12 portas USB 2.0 de alta velocidade EHCI 6 PCI Express x1 MAC 10/100/1000 integrado à Intel GLCI LCI Conexão de LAN Gigabit da Intel 480 Mb/s cada 500 Mb/s cada x1 LPC ou SPI Suporte do BIOS 3 Gb/s cada Áudio de alta definição da Intel 6 portas seriais ATA; eSATA; desativação de porta PCI PCIe x1 Barramento SM ICH10 ICH10R 2 GB/s DMI Operac a o do barramento PCI Como todos os barramentos do PC desde o BM PC original, o barramento PC é síncrono. Todas as suas transações ocorrem entre um mestre, cujo nome oficial é iniciador, e um escravo, oficialmente denominado alvo. Para manter baixo o número de pinos PC, as linhas de endereços e dados são multiplexadas. Desse modo, nas placas PC são necessários somente 64 pinos para endereço mais sinais de dados, ainda que o PC suporte ende- reços de 64 bits e dados de 64 bits. Os pinos de endereço e de dados multiplexados funcionam da seguinte maneira. Em uma operação de leitu- ra, durante o ciclo 1, o mestre coloca o endereço no barramento. No ciclo 2, ele remove o endereço e o barramento muda de sentido, de modo que o escravo possa usá-lo. No ciclo 3, o escravo entrega os dados requisitados. Em operações de escrita, o barramento não tem de virar porque o mestre coloca o endereço e também os dados. Não obstante, a transação mínima ainda dura três ciclos. Se o escravo não conseguir responder em três ciclos, ele pode inserir estados de espera. Também são permitidas transferências de blocos sem limite de tamanho, assim como diversos outros tipos de ciclos de barramento.
  • 192. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 173 Arbitragem de barramento PCI Para usar o barramento PC, um dispositivo deve antes adquiri-lo. A arbitragem de barramento PC usa um árbitro de barramento centralizado, como mostra a Figura 3.53. Na maioria dos projetos, o árbitro de barramento é inserido em um dos chips de ponte. Todo dispositivo PC tem duas linhas dedicadas que vão dele até o árbitro. Uma linha, req#, é usada para requisitar o barramento. A outra linha, gnt#, é usada para receber concessões de barramento. Nota: req# é a forma do PC indicar req. Figura 3.53 O barramento PCI usa um a rbitro de barramento centralizado. REQ# GNT# REQ# GNT# REQ# GNT# REQ# GNT# Árbitro de PCI Dispositivo PCI Dispositivo PCI Dispositivo PCI Dispositivo PCI Para requisitar o barramento, um dispositivo PC (incluindo a CPU) ativa req# e espera até ver sua linha gnt# ativada pelo árbitro. Quando esse evento acontece, o dispositivo pode usar o barramento no próximo ciclo. O algoritmo usado pelo árbitro não é definido pela especificação do PC. Arbitragem por varredura circular, arbi- tragem por prioridade e outros esquemas são todos permitidos. Claro que um bom árbitro será justo, de modo a não deixar alguns dispositivos esperando para sempre. Uma concessão de barramento serve para uma transação apenas, embora em teoria o comprimento dessa transação não tenha limite. Se um dispositivo quiser executar uma segunda transação e nenhum outro dispo- sitivo estiver requisitando o barramento, ele pode entrar de novo, apesar de ser preciso inserir um ciclo ocioso entre transações. Contudo, em circunstâncias especiais, na ausência de disputa pelo barramento, um dispositivo pode fazer uma transação atrás da outra sem ter de inserir um ciclo ocioso. Se um mestre de barramento estiver realizando uma transferência muito longa e algum outro dispositivo requisitar o barramento, o árbitro pode negar a linha gnt#. O mestre de barramento em questão deve monitorar a linha gnt#; portanto, quando perce- ber a negação, deve liberar o barramento no próximo ciclo. Esse esquema permite transferências muito longas (que são eficientes) quando há só um mestre de barramento candidato, mas ainda assim dá resposta rápida a dispositivos concorrentes. Sinais de barramento PCI O barramento PC tem vários sinais obrigatórios, mostrados na Figura 3.54(a), e vários sinais opcionais, mostrados na Figura 3.54(b). O restante dos 120 ou 184 pinos são usados para energia, aterramento e diversas funções relacionadas, e não aparecem nessa lista. As colunas Mestre (iniciador) e Escravo (alvo) informam quem ativa o sinal em uma transação normal. Se o sinal for ativado por um dispositivo diferente (por exemplo, clk), ambas as colunas são deixadas em branco.
  • 193. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 174 Figura 3.54 (a) Sinais obrigato rios de barramento PCI. (b) Sinais opcionais de barramento PCI. Sinal Linhas Mestre Escravo Descrição CLK 1 Clock (33 MHz ou 66 MHz) AD 32 × × Linhas de endereço e de dados multiplexadas PAR 1 × Bit de paridade de endereço ou dados C/BE 4 × Comando de barramento/mapa de bits para bytes habilitados FRAME# 1 × Indica que AD e C/BE estão ativadas IRDY# 1 × Leitura: mestre aceitará; escrita: dados presentes IDSEL 1 × Seleciona espaço de configuração em vez de memória DEVSEL# 1 × Escravo decodificou seu endereço e está na escuta TRDY# 1 × Leitura: dados presentes; escrita: escravo aceitará STOP# 1 × Escravo quer interromper transação imediatamente PERR# 1 Erro de paridade de dados detectado pelo receptor SERR# 1 Erro de paridade de endereço ou erro de sistema detectado REQ# 1 Arbitragem de barramento: requisição de propriedade de barramento GNT# 1 Arbitragem de barramento: concessão de propriedade de barramento RST# 1 Restaura o sistema e todos os dispositivos (a) Sinal Linhas Mestre Escravo Descrição REQ64# 1 × Requisição para realizar transação de 64 bits ACK64# 1 × Permissão concedida para uma transação de 64 bits AD 32 × 32 bits adicionais de endereço ou dados PAR64 1 × Paridade para os 32 bits extras de endereço/dados C/BE# 4 × 4 bits adicionais para habilitações de bytes LOCK 1 × Trava o barramento para permitir múltiplas transações SBO# 1 Presença de dados em uma cache remota (para um multiprocessador) SDONE 1 Escuta realizada (para um multiprocessador) INTx 4 Requisição de uma interrupção JTAG 5 Sinais de testes IEEE 1149.1 JTAG M66EN 1 Ligado à energia ou ao terra (66 MHz ou 33 MHz) (b) Agora, vamos examinar brevemente cada um dos sinais do barramento PC. Começaremos com os obrigató- rios (32 bits) e em seguida passaremos para os opcionais (64 bits). O sinal clk comanda o barramento. A maioria dos outros sinais é síncrona com ele. Ao contrário do SA, uma transação de barramento PC começa na borda descendente do clk, que está no meio do ciclo, em vez de estar no início. Os 32 sinais ad são para endereços e dados (para transações de 32 bits). Em geral, durante o ciclo 1 o ende- reço é ativado e durante o ciclo 3 os dados são ativados. O sinal PAR é um bit de paridade para ad. O sinal c/be# é usado para duas coisas diferentes. No ciclo 1, ele contém o comando de barramento (leia 1 palavra, leia bloco etc.). No ciclo 2, contém um mapa de bits de 4 bits que informa quais bytes da palavra de 32 bits são válidos. Usando c/be# é possível ler ou escrever 1, 2 ou 3 bytes quaisquer, bem como uma palavra inteira. O sinal frame# é ativado pelo mestre para iniciar uma transação de barramento. nforma ao escravo que os comandos de endereço e barramento agora são válidos. Em uma leitura, usualmente o irdy# é ativado ao mesmo
  • 194. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 175 tempo em que o frame#. Ele informa que o mestre está pronto para aceitar dados que estão chegando. Em uma escrita, o irdy# é ativado mais tarde, quando os dados estão no barramento. O sinal idsel está relacionado ao fato de que todo dispositivo PC deve ter um espaço de configuração de 256 bytes que outros dispositivos possam ler (ativando idsel). Esse espaço de configuração contém propriedades do dispositivo. A característica plug-and-play de alguns sistemas operacionais usa o espaço de configuração para saber quais dispositivos estão no barramento. Agora, chegamos aos sinais ativados pelo escravo. O primeiro deles, devsel#, anuncia que o escravo detectou seu endereço nas linhas ad e está preparado para realizar a transação. Se devsel# não for ativado em certo limite de tempo, o mestre esgota sua temporização e supõe que o dispositivo endereçado está ausente ou avariado. O segundo sinal de escravo é trdy#, que ele ativa em leituras para anunciar que os dados estão nas linhas ad e em escritas para anunciar que está preparado para aceitar dados. Os três sinais seguintes são para notificar erros. O primeiro deles é stop#, que o escravo ativa se algo desas- troso acontecer e ele quiser abortar a transação corrente. O seguinte, perr#, é usado para notificar um erro de paridade no ciclo anterior. Para uma leitura, ele é ativado pelo mestre; para uma escrita, pelo escravo. Cabe ao receptor executar a ação adequada. Por fim, serr# é para reportar erros de endereço e de sistema. Os sinais req# e gnt# são para fazer arbitragem de barramento. Eles não são assegurados pelo mestre de transferência de dados em questão, mas por um dispositivo que quer se tornar mestre de barramento. O último sinal obrigatório é rst#, usado para reiniciar o sistema, seja porque o usuário apertou a tecla RESET seja porque algum dispositivo do sistema notou um erro fatal. Ativar esse sinal restaura todos os dispositivos e reinicia o computador. Agora, chegamos aos sinais opcionais, cuja maioria está relacionada à expansão de 32 bits para 64 bits. Os sinais req64# e ack64# permitem que o mestre peça permissão para conduzir uma transação de 64 bits e permite que o escravo aceite, respectivamente. Os sinais ad, par64 e c/be# são apenas extensões dos sinais correspondentes de 32 bits. Os três sinais seguintes não estão relacionados aos 32 bits contra 64 bits, mas a sistemas multiprocessadores, algo que as placas PC não são obrigadas a suportar. O sinal lock permite que o barramento seja travado para múl- tiplas transações. Os dois seguintes estão relacionados à escuta do barramento para manter coerência de cache. Os sinais intx são para requisitar interrupções. Uma placa PC pode conter até quatro dispositivos lógicos separados e cada um pode ter sua própria linha e requisição de interrupção. Os sinais jtag são para procedimento de teste EEE 1149.1 JTAG. Por fim, o sinal m66en é ligado alto ou é ligado baixo para estabelecer a velocidade de clock. Não deve mudar durante a operação do sistema. Transac o es de barramento PCI Na realidade, o barramento PC é muito simples (no que diz respeito a barramentos). Para ter uma ideia melhor dele, considere o diagrama temporal da Figura 3.55, onde podemos ver uma transação de leitura seguida por um ciclo ocioso, seguida por uma transação de escrita pelo mesmo mestre de barramento. Quando a borda descendente do clock acontece durante T1, o mestre põe o endereço de memória em ad e o comando de barramento em c/be#. Então, ativa frame# para iniciar a transação de barramento. Durante T2, o mestre libera o barramento de endereço para deixar que ele retorne em preparação para o comando do escravo durante T3. O mestre também muda c/be# para indicar quais bytes na palavra endereçada ele quer habilitar, isto é, quais quer que sejam lidos. Em T3, o escravo ativa devsel# de modo que o mestre saiba que ele obteve o endereço e está planejando res- ponder. Além disso, põe os dados nas linhas ad e ativa trdy# para informar ao mestre que fez isso. Se o escravo não puder responder com tanta rapidez, ainda assim ele ativaria devsel# para anunciar sua presença, mas manteria trdy# negado até que pudesse obter os dados que lá estão. Esse procedimento introduziria um ou mais estados de espera.
  • 195. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 176 Figura 3.55 Exemplos de transac o es de barramento PCI de 32 bits. Os tre s primeiros ciclos sa o usados para uma operac a o de leitura, em seguida um ciclo ocioso e depois tre s ciclos para uma operac a o de escrita. Φ T1 T2 T3 T4 T5 T6 T7 AD C/BE# FRAME# IRDY# DEVSEL# TRDY# Ciclo de barramento Escrita Retorno Leitura Ocioso Endereço Endereço Dados Dados Cmd. de leitura Habilitação Cmd. de leitura Habilitação Nesse exemplo (e muitas vezes na realidade), o ciclo seguinte é ocioso. Começando em T5, vemos o mesmo mestre iniciando uma escrita. Ele começa colocando o endereço e o comando no barramento, como sempre. Só que agora, no segundo ciclo, ele ativa os dados. Uma vez que o mesmo dispositivo está comandando as linhas ad, não há necessidade de um ciclo de retorno. Em T7, a memória aceita os dados. 3.6.2 PCI Express Embora o funcionamento do barramento PC seja adequado para a maioria das aplicações, a necessidade de maior largura de banda de E/S está causando uma confusão na antes limpa arquitetura interna do PC. A Figura 3.52 deixa claro que o barramento PC não é mais o elemento central que mantém unidas as partes do PC. O chip ponte se apossou de parte desse papel. A essência do problema é que há cada vez mais dispositivos de E/S muito rápidos para o barramento PC. Elevar a frequência de clock do barramento não é uma boa solução porque então os problemas de atraso diferen- cial no barramento, interferência na fiação e efeitos de capacitância só ficariam piores. Toda vez que um dispo- sitivo de E/S fica muito rápido para o barramento PC (como as placas gráficas, disco rígido, redes etc.), a ntel acrescenta uma porta especial para o chip ponte para permitir que o dispositivo contorne o barramento PC. Claro que isso tampouco é uma solução de longo prazo. Outro problema com o barramento PC é que as placas são muito grandes. Placas PC padrão costumam ter 17,5 cm por 10,7 cm e placas inferiores possuem 12,0 cm por 3,6 cm. Nenhuma delas cabe em laptops e, com certeza, não em dispositivos móveis. Os fabricantes gostariam de produzir dispositivos menores ainda. Além disso, alguns deles gostariam de repartir o espaço interno do PC, colocando a CPU e a memória dentro de uma pequena caixa selada e o disco rígido dentro do monitor. Com as placas PC é impossível fazer isso. Diversas soluções foram propostas, mas a que tem mais probabilidade de vencer (e em grande parte porque a ntel está por trás dela) é denominada PCI Express. Ela tem pouco a ver com o barramento PC e, na verdade,
  • 196. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 177 nem é um barramento, mas o pessoal do marketing não quer largar mão do famoso nome PC. PCs que contêm essa solução já estão no mercado há algum tempo. amos ver como eles funcionam. Arquitetura do PCI Express O coração da solução PC Express (em geral, abreviado como PCe) é se livrar do barramento paralelo com seus muitos mestres e escravos e passar para um projeto baseado em conexões seriais ponto a ponto de alta velocidade. Essa solução representa uma ruptura radical com a tradição do barramento SA/ESA/PC e toma emprestadas muitas ideias do mundo das redes locais, em especial a Ethernet comutada. A ideia básica se resume no seguinte: no fundo, um PC é um conjunto de chips de CPU, memória, controladores de E/S que precisa ser interconectado. O que o PC Express faz é fornecer um comutador de uso geral para conectar chips usando liga- ções seriais. Uma configuração típica é ilustrada na Figura 3.56. Figura 3.56 Sistema PCI Express t pico. Cache de nível 2 CPU Chip ponte Memória Comutador Ligações seriais em pares Disco Rede USB 2 Outro Gráficos Como mostra a figura, a CPU, a memória e a cache estão conectadas ao chip ponte no modo tradicional. A novidade aqui é um comutador conectado à ponte (talvez parte do próprio chip ponte ou integrado diretamente ao processador). Cada um dos chips de E/S tem uma conexão ponto a ponto dedicada com o comutador. Cada conexão consiste em um par de canais unidirecionais, um que vai para o comutador e outro que vem dele. Cada canal é com- posto de dois fios, um para o sinal e outro para o terra, para dar imunidade contra ruído alto durante a transmissão de alta velocidade. Essa arquitetura substituirá a atual por um modelo muito mais uniforme, no qual todos os dispo- sitivos são tratados igualmente. A arquitetura PC Express tem três pontos de diferença em relação ao antigo barramento PC. Já vimos dois deles: um comutador centralizado contra um barramento multidrop e a utilização de conexões seriais ponto a ponto estreitas contra um barramento paralelo largo. O terceiro é mais sutil. O modelo conceitual que fundamen- ta o PC é o de um mestre de barramento que emite um comando a um escravo para ler uma palavra ou um bloco de palavras. O modelo do PC Express é o de um dispositivo que envia um pacote de dados a outro dispositivo. O conceito de um pacote, que consiste em um cabeçalho e em uma carga útil, é tirado do mundo das redes. O cabeçalho contém informação de controle, o que elimina a necessidade dos muitos sinais de controle presen- tes no barramento PC. A carga útil contém os dados a transferir. Na verdade, um PC com PC Express é uma miniatura de rede de comutação de pacotes.
  • 197. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 178 Além dessas três importantes rupturas com o passado, também há diversas pequenas diferenças. A quarta é que o código de detecção de erro é usado somente nos pacotes, o que dá um grau de confiabilidade mais alto do que o barramento PC. A quinta é que a conexão entre um chip e o comutador é mais longa do que era, até 50 cm, para permitir a repartição do sistema. A sexta é que o sistema pode ser expandido porque um dispositivo pode per- feitamente ser outro comutador, o que permite uma árvore de comutadores. A sétima é que dispositivos podem ser acrescentados ou removidos do sistema enquanto ele está em operação. Por fim, uma vez que conectores seriais são muito menores do que os antigos conectores PC, podem-se fabricar dispositivos e computadores muito menores. Em resumo, o PC Express é uma grande ruptura em relação ao barramento PC. Pilha de protocolos do PCI Express Condizente com o modelo de uma rede de comutação de pacotes, o sistema PC Express tem uma pilha de protocolos em camadas. Um protocolo é um conjunto de regras que governam a conversa entre duas partes. Uma pilha de protocolos é uma hierarquia de protocolos que tratam de questões diferentes em camadas diferentes. Por exemplo, considere uma carta comercial. Ela obedece a certas convenções referentes à localização e ao conteúdo do cabeçalho, ao endereço do destinatário, à data, aos cumprimentos, ao corpo, à assinatura e assim por dian- te. Podemos dizer que tudo isso junto é um protocolo de carta. Além disso, há outro conjunto de convenções referentes ao envelope, como tamanho, local e formato do endereço do remetente, local e formato do endereço do destinatário, local do selo e assim por diante. Essas duas camadas e seus protocolos são independentes. Por exemplo, é possível dar um formato completamente diferente à carta, mas usar o mesmo envelope, e vice-versa. Protocolos em camadas são um projeto modular flexível e há décadas são muito usados no mundo dos softwares de rede. A novidade, no caso, é montá-los no hardware do “barramento”. A pilha de protocolos do PC Express é mostrada na Figura 3.57(a). Ela é discutida a seguir. Figura 3.57 (a) Pilha de protocolos do PCI Express. (b) Formato de um pacote. (a) (b) Camada de software Camada de transação Camada de enlace Camada física Cabeçalho Cabeçalho Cabeçalho Seq # Seq # Quadro Quadro CRC CRC Carga útil Carga útil Carga útil amos examinar as camadas de baixo para cima. A camada mais baixa é a camada física. Ela trata da movi- mentação de bits de um remetente para um destinatário por uma conexão ponto a ponto. Cada conexão ponto a ponto consiste em um ou mais pares de enlaces simplex (isto é, unidirecionais). No caso mais simples, há um par em cada direção, mas também é permitido ter 2, 4, 8, 16 ou 32 pares. Cada enlace é denominado via. O número de vias em cada direção deve ser o mesmo. Produtos de primeira geração devem suportar uma taxa de dados de no mínimo 2,5 Gbps, mas espera-se que logo a velocidade passe para 10 Gbps em cada direção. Diferente dos barramentos SA/ESA/PC, o PC Express não tem um clock mestre. Os dispositivos têm liberdade para começar a transmitir tão logo tenham dados a enviar. Essa liberdade deixa o sistema mais rápido, mas também leva a um problema. Suponha que um bit 1 seja codificado como +3 volts e um bit 0, como 0 volt. Se os primeiros bytes forem todos 0s, como o destinatário sabe que dados estão sendo transmitidos? Afinal, uma sequência de 0 bits parece o mesmo que um enlace ocioso. O problema é resolvido usando o que denominamos codificação 8b/10b. Nesse esquema, 10 bits são usados para codificar 1 byte de dados reais em um símbolo de 10 bits. Entre os 1.024 símbolos de 10 bits possíveis, foram escolhidos como legais os que têm suficientes transições de clock para manter remetente e destinatário sincronizados nas fronteiras de bits, mesmo sem um clock mestre. Uma consequência da codificação 8b/10b é que um enlace que tenha uma capacidade bruta de 2,5 Gbps só pode transmitir 2 Gbps (líquidos) de dados de usuário.
  • 198. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 179 Enquanto a camada física lida com transmissão de bits, a camada de enlace trata de transmissão de pacotes. Ela pega o cabeçalho e a carga útil passados para ela pela camada de transação e acrescenta a eles um número de sequência e um código de correção de erro denominado CRC (Cyclic Redundancy Check  verificação por redundância cíclica). O CRC é gerado pela execução de certo algoritmo no cabeçalho e nos dados da carga útil. Quando um pacote é recebido, o destinatário efetua alguns cálculos no cabeçalho e nos dados e compara o resultado com o CRC anexado ao pacote. Se forem compatíveis, ele devolve um curto pacote de reconhecimento confirmando sua correta chegada. Se não forem, o destinatário solicita uma retransmissão. Desse modo, a integri- dade dos dados melhora muito em relação ao sistema de barramento PC, que não tem nenhuma prescrição para verificação e retransmissão de dados enviados pelo barramento. Para evitar que um transmissor rápido soterre um receptor lento com pacotes que ele não pode manipu- lar, é usado um mecanismo de controle de fluxo que funciona da seguinte maneira: o receptor concede ao transmissor certo número de créditos que correspondem em essência à quantidade de espaço de buffer de que ele dispõe para armazenar pacotes que chegam. Quando os créditos se esgotam, o transmissor tem de parar de enviar pacotes até receber mais créditos. Esse esquema, que é muito usado em todas as redes, evita a perda de dados em consequência da incompatibilidade entre as velocidades do transmissor e do receptor. A camada de transação trata das ações do barramento. Ler uma palavra da memória requer duas transações: uma iniciada pela CPU ou canal DMA que está requisitando alguns dados e outra iniciada pelo alvo que está for- necendo os dados. Mas a camada de transação faz mais do que manipular leituras e escritas puras. Ela adiciona valor à transmissão de pacotes bruta oferecida pela camada de enlace. Para começar, ela pode dividir cada via em até oito circuitos virtuais, cada um manipulando uma classe de tráfego diferente. A camada de transação pode rotular pacotes de acordo com sua classe de tráfego, o que pode incluir atributos como “alta prioridade”, “baixa prioridade”, “não escute”, “pode ser entregue fora da ordem” e outros mais. O comutador pode usar esses rótulos para decidir qual pacote manipulará em seguida. Cada transação usa um dos quatro espaços de endereços: 1. Espaço da memória (para leituras e escritas comuns). 2. Espaço de E/S (para endereçar registradores de dispositivos). 3. Espaço de configuração (para inicialização do sistema etc.). 4. Espaço de mensagem (para sinalização, interrupções etc.). Os espaços de memória e E/S são semelhantes aos dos sistemas existentes. O espaço de configuração pode ser usado para executar características como plug-and-play. O espaço de mensagem assume o papel de muitos dos sinais de controle existentes. É necessário ter algo parecido com esse espaço porque nenhuma das linhas de controle do PC existe no PC Express. A camada de software faz a interface entre sistema PC Express e sistema operacional. Ela pode emular o barramento PC, possibilitando a execução de sistemas operacionais existentes não modificados em sistemas PC Express. Claro que uma operação como essa não irá explorar todo poder do PC Express, mas a compatibilidade é um mal necessário até que os sistemas operacionais sejam modificados para utilizar totalmente o PC Express. A experiência mostra que isso pode levar algum tempo. O fluxo de informações é ilustrado na Figura 3.57(b). Quando é dado um comando à camada de software, esta o passa para a camada de transação, que o formula em termos de um cabeçalho e uma carga útil. Então, essas duas partes são passadas para a camada de enlace, que acrescenta um número de sequência à sua parte anterior e um CRC à posterior. Em seguida, esse pacote ampliado é passado à camada física, que acrescenta informações de enquadramento de dados a cada extremidade para formar o pacote físico, que é, por fim, transmitido. Na extre- midade receptora ocorre o processo inverso – cabeçalho de enlace e as informações que acompanham o bloco de dados (trailer) são removidos e o resultado é passado para a camada de transação. O conceito do acréscimo de informações adicionais aos dados à medida que ele desce pela pilha de protoco- los já é usado há décadas no mundo das redes com grande sucesso. A grande diferença entre uma rede e o PC
  • 199. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 180 Express é que, no mundo das redes, o código nas várias camadas quase sempre é um software que faz parte do sistema operacional. No PC Express, ele faz parte do hardware do dispositivo. O PC Express é um assunto complicado. Para mais informações, consulte Mayhew e Krishnan, 2003; e Solari e Congdon, 2005. Ele ainda está evoluindo. Em 2007, o PCe 2.0 foi lançado. Ele admite 500 MB/s por via em até 32 vias, para uma largura de banda total de 16 GB/s. Depois veio o PCe 3.0 em 2011, que mudou a codificação de 8b/10b para 128b/130b e pode rodar a 8 bilhões de transações por segundo, o dobro do PCe 2.0. 3.6.3 Barramento serial universal (USB) O barramento PC e o PC Express são bons para anexar periféricos de alta velocidade a um computador, mas são muito caros para dispositivos de E/S de baixa velocidade, como teclados e mouses. Cada dispositivo padrão de E/S era conectado ao computador de modo especial, com alguns encaixes SA e PC livres para adicionar novos dispositivos. nfelizmente, esse esquema teve problemas desde o início. Por exemplo, cada novo dispositivo de E/S costuma vir com sua própria placa SA ou PC. Muitas vezes, o usuá- rio é responsável pelo ajuste de comutadores e pontes na placa e por assegurar que tais ajustes não entrem em con- flito com as outras placas. Então, ele precisa abrir a torre, inserir cuidadosamente a placa, fechar a torre e reiniciar o computador. Para muitos usuários, esse processo é difícil e sujeito a erros. Além disso, o número de encaixes SA e PC é muito limitado (em geral, dois ou três). Placas plug-and-play eliminam o ajuste das pontes, mas ainda assim o usuário tem de abrir o computador para inserir a placa e o número de encaixes do barramento continua limitado. Para tratar desse problema, em 1993, representantes de sete empresas (Compaq, DEC, BM, ntel, Microsoft, NEC e Northern Telecom) se reuniram para buscar a melhor maneira de anexar dispositivos de E/S a um computador. Desde então, centenas de outras empresas se juntaram a elas. O padrão resultante, lançado oficialmente em 1998, é denominado USB (Universal Serial Bus  barramento serial universal), e é amplamente executado em computadores pessoais. Uma descrição mais detalhada desse barramento pode ser encontrada em Anderson (1997) e Tan (1997). Alguns dos objetivos das empresas que conceberam o USB original e iniciaram o projeto eram os seguintes: 1. Usuários não terão de ajustar comutadores ou pontes em placas ou dispositivos. 2. Usuários não terão de abrir a torre para instalar novos dispositivos de E/S. 3. Haverá apenas um tipo de cabo, que servirá para conectar todos os dispositivos. 4. A energia para os dispositivos de E/S deve ser fornecida por esse cabo. 5. Até 127 dispositivos poderão ser ligados a um único computador. 6. O sistema deve suportar dispositivos de tempo real (por exemplo, som, telefone). 7. Os dispositivos poderão ser instalados com o computador em funcionamento. 8. Não será preciso reiniciar o computador após a instalação do dispositivo. 9. O custo de produção do novo barramento e de seus dispositivos de E/S não deve ser alto. O USB cumpre todos esses objetivos. É projetado para dispositivos de baixa velocidade, como teclados, mou- ses, câmeras fotográficas, scanners, telefones digitais e assim por diante. A versão 1.0 tem uma largura de banda de 1,5 Mbps, que é suficiente para teclados e mouses. A versão 1.1 funciona em 12 Mbps, que é suficiente para impressoras, câmeras digitais e muitos outros dispositivos. A versão 2.0 tem suporte para dispositivos com até 480 Mbps, que é suficiente para trabalhar com drives de disco externos, webcams de alta definição e interfaces de rede. O USB versão 3.0, recentemente definido, empurra as velocidades para acima de 5 Gbps; só o tempo dirá quais aplicações novas e ávidas por largura de banda aproveitarão essa interface com largura de banda ultra-alta. Um sistema USB consiste em um hub-raiz (root hub) que é ligado ao barramento principal (veja a Figura 3.51). Esse hub tem soquetes para cabos que podem ser conectados a dispositivos de E/S ou a hubs de expansão, para fornecer mais soquetes, de modo que a topologia de um sistema USB é uma árvore cuja raiz está no hub,
  • 200. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 181 dentro do computador. Há diferentes conectores na extremidade dos cabos do hub-raiz e na extremidade do dis- positivo para evitar que, por acidente, os usuários liguem dois soquetes entre si. O cabo consiste em quatro fios: dois para dados, um para energia (+5 volts) e um para terra. O sistema de sinalização transmite um 0 como uma transição de tensão e um 1 como ausência de uma transição da tensão, portanto, longas carreiras de 0s geram um fluxo regular de pulsos. Quando um novo dispositivo de E/S é ligado, o hub-raiz detecta esse evento e interrompe o sistema ope- racional, que então pesquisa para descobrir que dispositivo é e de quanta largura de banda USB ele precisa. Se o sistema operacional decidir que há suficiente largura de banda para o dispositivo, atribui um endereço exclusivo para ele (1–127) e descarrega esse endereço e outras informações em registradores de configura- ção dentro do dispositivo. Desse modo, novos dispositivos podem ser acrescentados com o computador em funcionamento, sem exigir nenhuma configuração da parte do usuário e sem ter de instalar novas placas SA ou PC. Placas não inicializadas começam com endereço 0, por isso, podem ser endereçadas. Para simplificar o cabeamento, muitos dispositivos USB contêm conexões internas que aceitam dispositivos USB adicionais. Por exemplo, um monitor poderia ter dois soquetes de conexão para acomodar os alto-falantes esquerdo e direito. Em termos lógicos, o sistema USB pode ser visto como um conjunto de ramificações que saem do hub-raiz para os dispositivos de E/S. Cada dispositivo pode subdividir sua própria ramificação em até 16 ramos secundá- rios para diferentes tipos de dados (por exemplo, áudio e vídeo). Dentro de cada ramo secundário, os dados fluem do hub-raiz até o dispositivo, ou ao contrário. Não há tráfego entre dois dispositivos de E/S. Exatamente a cada 1,00 ± 0,05 ms, o hub-raiz transmite um novo quadro para manter todos os dispositivos sincronizados em relação ao tempo. Um quadro é associado a um caminho de bit e consiste em pacotes, o primei- ro dos quais vem do hub-raiz até o dispositivo. Pacotes subsequentes no quadro também podem ir nessa direção ou voltar do dispositivo até o hub-raiz. A Figura 3.58 mostra uma sequência de quatro quadros. Na Figura 3.58, não há nenhum serviço a ser realizado nos quadros 0 e 2, portanto, basta um pacote SOF (Start of Frame – início do quadro). Ele é sempre transmitido para todos os dispositivos. O quadro 1 é uma son- dagem (poll), por exemplo, uma requisição para que um scanner devolva os bits que encontrou na imagem que está digitalizando. O quadro 3 consiste em entregar dados a algum dispositivo, por exemplo, uma impressora. O USB suporta quatro tipos de quadros: de controle, isócrono, de volume e de interrupção. Quadros de con- trole são usados para configurar dispositivos, transmitir-lhes comandos e inquirir seu estado. Quadros isócronos são para dispositivos de tempo real, como microfones, alto-falantes e telefones, que precisam enviar ou aceitar dados a intervalos de tempo exatos. Eles têm um atraso muito previsível, mas não fazem retransmissões quando Figura 3.58 Hub-raiz USB emite quadros a cada 1,00 ms. 0 SOF 2 SOF 1 SOF IN DATA ACK SYN PID PAYLOAD CRC 3 SOF OUT DATA ACK SYN PID PAYLOAD CRC Tempo (ms) Ocioso Quadro 0 Quadro 1 Quadro 2 Quadro 3 Pacotes da raiz Pacotes da raiz A partir do dispositivo Pacote de dados do dispositivo
  • 201. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 182 ocorrem erros. Quadros de volume são para grandes transferências de e para dispositivos para os quais não há requisitos de tempo real, como impressoras. Por fim, quadros de interrupção são necessários porque o USB não aceita interrupções. Por exemplo, em vez de fazer com que o teclado cause uma interrupção sempre que uma tecla é acionada, o sistema operacional pode fazer uma sondagem a cada 50 ms para coletar qualquer tecla acionada que esteja pendente. Um quadro consiste em um ou mais pacotes, alguns possivelmente na mesma direção. Existem quatro tipos de pacotes: permissão (token), dados, apresentação (handshake) e especial. Pacotes de permissão vêm da raiz até um dispositivo e servem para controle do sistema. Os pacotes SOF, N e OUT na Figura 3.58 são pacotes de permissão. O pacote SOF é o primeiro de cada quadro e marca seu início. Se não houver nenhum trabalho a realizar, o pacote SOF é o único no quadro. O pacote de permissão N é uma sondagem, que pede ao dispositivo que retorne certos dados. Campos no pacote N informam qual caminho está sendo sondado de modo que o dispositivo saiba quais dados retornar (se tiver múltiplos fluxos). O pacote de permissão OUT anuncia ao dispo- sitivo que serão enviados dados a ele. Um quarto tipo de pacote de permissão, SETUP (não mostrado na figura), é usado para configuração. Além do pacote de permissão há três outros tipos de pacote: DATA (usado para transmitir até 64 bytes de informação em qualquer direção), pacotes de apresentação e pacotes especiais. O formato de um pacote de dados é mostrado na Figura 3.58. Consiste em um campo de sincronização de 8 bits, um tipo de pacote (PD) de 8 bits, a carga útil (payload) e um CRC de 16 bits para detectar erros. São definidos três tipos de pacotes de apresentação: ACK (o pacote de dados anterior foi recebido corretamente), NAK (foi detectado um erro CRC) e STALL (favor esperar – agora estou ocupado). Agora, vamos examinar a Figura 3.58 mais uma vez. A cada 1,00 ms um quadro deve ser enviado do hub-raiz, mesmo que não haja trabalho a realizar. Os quadros 0 e 2 consistem em apenas um pacote SOF, indicando que não há trabalho a executar. O quadro 1 é uma sondagem, portanto, começa com pacotes SOF e N do computador ao dispositivo de E/S, seguidos por um pacote DATA do dispositivo para o computador. O pacote ACK informa ao dispositivo que os dados foram recebidos corretamente. Caso ocorra um erro, um NAK é devolvido ao dispositivo e o pacote é retransmitido quando for de volume, mas não quando os dados forem isócronos. A estrutura do quadro 3 é semelhante à do quadro 1, exceto que agora o fluxo de dados é do computador para o dispositivo. Após a conclusão do padrão USB em 1998, o pessoal que o projetou não tinha nada para fazer, então, come- çou a trabalhar em uma nova versão de alta velocidade do USB, denominada USB 2.0. Esse padrão é semelhante ao antigo USB 1.1 e compatível com ele, exceto pela adição de uma terceira velocidade, 480 Mbps, às duas exis- tentes. Além disso, há algumas pequenas diferenças, como interface entre hub-raiz e o controlador. O USB 1.1 tinha duas interfaces disponíveis. A primeira, UHCI (Universal Host Controller Interface  interface universal de controlador de hospedeiro), foi projetada pela ntel e passava grande parte da carga para os projetistas de software (leia-se: Microsoft). A segunda, OHCI (Open Host Controller Interface  interface aberta de controla- dor de hospedeiro), foi projetada pela Microsoft e passava grande parte da carga para os projetistas de hardware (leia-se: ntel). No USB 2.0, todos concordaram com uma nova interface única denominada EHCI (Enhanced Host Controller Interface  interface melhorada de controlador de hospedeiro). Agora que o USB funcionava a 480 Mbps, passou a competir com o barramento serial EEE 1394, mais conhe- cido como FireWire, que funciona a 400 Mbps ou 800 Mbps. isto que praticamente todo novo PC baseado no ntel agora vem com USB 2.0 ou USB 3.0 (ver a seguir), é provável que o 1394 desapareça no devido tempo. O desaparecimento não é tanto pela obsolescência quanto à guerra por territórios. O USB é um produto da indústria da computação, enquanto o 1394 vem do setor de eletrônica de consumo. Quando se trata de conectar câmeras a computadores, cada indústria queria que todos usassem seu cabo. Parece que o pessoal do computador ganhou essa. Oito anos depois da introdução do USB 2.0, o padrão de interface USB 3.0 foi anunciado. O USB 3.0 admite incríveis 5 Gbps de largura de banda pelo cabo, embora a modulação do enlace seja adaptativa, e provavelmente essa velocidade só poderá ser alcançada com cabeamento de qualidade profissional. Os dispositivos USB 3.0 são estruturalmente idênticos aos dispositivos USB anteriores, e executam totalmente o padrão USB 2.0. Se conecta- dos a um soquete USB 2.0, eles operarão corretamente.
  • 202. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 183 3.7 Interface Um sistema de computador típico de pequeno a médio porte consiste em um chip de CPU, chipset, chips de memória e alguns controladores de E/S, todos conectados por um barramento. Às vezes, todos esses dispositivos estão integrados a um sistema-em-um-chip, como o T OMAP4430. Já estudamos memórias, CPUs e barramentos com certo detalhe. Agora, chegou a hora de examinar a última parte do quebra-cabeça, as interfaces de E/S. É por meio dessas portas de E/S que o computador se comunica com o mundo exterior. 3.7.1 Interfaces de E/S Há inúmeras interfaces de E/S disponíveis no mercado e novas são lançadas o tempo todo. Entre as interfaces comuns estão UARTs, USARTs, controladores de CRT, controladores de disco e POs. Uma UR (Universal synchronous Receiver ransmitter  transmissor receptor assíncrono universal) é uma interface de E/S que pode ler um byte do barramento de dados e entregá-lo um bit por vez a um terminal por meio de uma linha serial, ou receber dados de um terminal. Em geral, as UARTs permitem várias velocidades de 50 a 19.200 bps; largura de caracteres de 5 a 8 bits; 1, 1,5 ou 2 bits de fim; e fornecem paridade par, ímpar ou nenhuma paridade, tudo sob con- trole de programa. USRs (Universal Synchronous synchronous Receiver ransmitters  transmissor receptor assíncrono síncrono universal) podem manipular transmissão síncrona usando uma variedade de protocolos, bem como executando todas as funções da UART. Como as UARTs se tornaram menos importantes com o desapareci- mento dos modems de telefone, agora vamos estudar a interface paralela como exemplo de uma interface de E/S. Interfaces PIO Uma interface PIO (Parallel Input/Output  entrada e saída paralela) típica é o ntel 8255A, mostrado na Figura 3.59. Ele tem uma série de linhas de E/S (por exemplo, 24 linhas de E/S no exemplo da figura) que podem fazer ligação com qualquer interface de dispositivo lógico digital, por exemplo, teclados, comutadores, luzes ou impressoras. Resumindo, o programa da CPU pode escrever um 0 ou 1, ou ler o estado de entrada de qualquer linha, o que dá grande flexibilidade. Um pequeno sistema com CPU que use uma interface PO pode controlar diversos dispositivos físicos, como um robô, torradeira ou microscópio eletrônico. As interfaces PO são encon- tradas frequentemente em sistemas embutidos. Figura 3.59 Uma interface PIO de 24 bits. Porta A Porta B Porta C CS WR RD A0-A1 RESET D0-D7 2 8 8 8 8 Interface de E/S Paralela (PIO) A interface PO é configurada com um registrador de configuração de 3 bits, que especifica se as três portas independentes de 8 bits devem ser usadas para entrada (0) ou saída (1) do sinal digital. A definição do valor apropriado no registrador de configuração permitirá qualquer combinação de entrada e saída para as três portas. Associado com cada porta há um registrador com amostragem de 8 bits. Para estabelecer as linhas em uma porta de saída, a CPU apenas escreve um número de 8 bits no registrador correspondente, e esse número aparece nas linhas de saída e fica ali até que o registrador seja reescrito. Para usar uma porta para entrada, a CPU apenas lê o registrador de 8 bits correspondente. É possível montar interfaces PO mais sofisticadas. Por exemplo, um modo de operação popular fornece apre- sentação com dispositivos externos. Assim, para enviar a um dispositivo que nem sempre está pronto para aceitar
  • 203. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 184 dados, a interface PO pode apresentar dados em uma porta de saída e esperar que o dispositivo devolva um pulso informando que aceitou os dados e quer mais. A lógica necessária para amostrar tais pulsos e torná-los disponíveis para a CPU inclui um sinal de pronto e mais uma fila de registradores de 8 bits para cada porta de saída. Pelo diagrama funcional da interface PO, podemos ver que, além dos 24 pinos para as três portas, ela tem oito linhas que se conectam diretamente com o barramento de dados, uma linha de seleção de chip (chip select), linhas de leitura e escrita, duas linhas de endereço e uma para reiniciar o chip. As duas linhas de endereço selecionam um dos quatro registradores internos correspondentes às portas A, B, C e ao registrador de configuração de porta. Em geral, as duas linhas de endereço estão conectadas aos bits de ordem baixa do barramento de endereço. A linha de seleção de chip permite que a interface PO de 24 bits seja combinada para formar interfaces PO maiores, acrescentando outras linhas de endereço e usando-as para selecionar a interface PO apropriada, ativando sua linha de seleção de chip. 3.7.2 Decodificac a o de enderec o Até agora fomos propositalmente superficiais sobre como a seleção do chip é ativada na memória e nos chips de E/S que já vimos. Agora, é hora de examinar com mais cuidado como isso é feito. amos considerar um com- putador embutido simples de 16 bits que consiste em uma CPU, uma EPROM de 2 KB × 8 bytes para o programa, uma RAM de 2 KB × 8 bytes para os dados e uma interface PO. Esse pequeno sistema pode ser usado como um protótipo para o cérebro de um brinquedo barato ou um eletrodoméstico simples. Uma vez em produção, a EPROM poderia ser substituída por uma ROM. A interface PO pode ser selecionada de um entre dois modos: como um verdadeiro dispositivo de E/S ou como parte da memória. Se optarmos por usá-la como um dispositivo de E/S, então devemos selecioná-la usando uma linha de barramento explícita que indica que um dispositivo de E/S está sendo referenciado, e não a memória. Se usarmos a outra abordagem, E/S mapeada para a memória, então temos de lhe designar 4 bytes do espaço de memória para as três portas e o registrador de controle. A escolha é, de certa forma, arbitrária. Escolheremos E/S mapeada para a memória porque ela ilustra alguns aspectos interessantes da interface de E/S. A EPROM necessita de 2 KB de espaço de endereço, a RAM também precisa de 2 K de espaço de endereço e a PO precisa de 4 bytes. Como o espaço de endereço de nosso exemplo é 64 K, temos de escolher onde colocar os três dispositivos. Uma opção possível é mostrada na Figura 3.60. A EPROM ocupa endereços até 2 K, a RAM ocupa endereços de 32 KB a 34 KB e a PO ocupa os 4 bytes mais altos do espaço de endereço, 65.532 a 65.535. Do ponto de vista do programador, não faz diferença quais endereços são usados; contudo, isso não acontece quando se trata da interface. Se tivéssemos optado por endereçar a PO via espaço de E/S, ela não precisaria de nenhum endereço de memória, mas precisaria de quatro espaços de endereço de E/S. Com as designações de endereço da Figura 3.60, a EPROM deve ser selecionada por quaisquer endereços de memória de 16 bits da forma 00000xxxxxxxxxxx (binário). Em outras palavras, qualquer endereço de memória cujos 5 bits de ordem alta são todos 0s cai na parte inferior da memória de 2 KB, portanto, na EPROM. Por isso, a seleção de chip da EPROM poderia ser ligada a um comparador de 5 bits, com uma de suas entradas perma- nentemente ligada a 00000. Uma maneira melhor de conseguir o mesmo efeito é usar uma porta OR de cinco entradas com as cinco entradas ligadas às linhas de endereço A11 a A15. Se, e somente se, todas a cinco linhas forem 0, a saída será 0, Figura 3.60 Localizac a o da EPROM, RAM e PIO em nosso espac o de enderec o de 64 KB. 0 4K 8K 12K 16K 20K 24K 28K 32K 36K 40K 44K 48K 52K 56K 60K 64K EPROM no endereço 0 RAM no endereço 8000H PIO em FFFCH
  • 204. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 185 o que ativa cs (que é ativado baixo). Esse método de endereçamento é ilustrado na Figura 3.61(a) e é chamado decodificação de endereço completo. O mesmo princípio pode ser usado para a RAM. Contudo, a RAM deve responder a endereços binários da forma 10000xxxxxxxxxxx, portanto, é preciso um inversor adicional, como mostra a figura. A decodifica- ção de endereços PO é um pouco mais complicada, porque é selecionada pelos quatro endereços da forma 11111111111111xx. Um possível circuito que assegure cs só quando o endereço correto aparecer no barramento de endereço é mostrado na figura. Ele usa duas portas nand de oito entradas para alimentar uma porta or. Contudo, se o computador de fato tiver apenas uma CPU, dois chips de memória e a PO, podemos usar um truque para conseguir uma decodificação de endereço muito mais simples. Esse truque se baseia no fato de que todos os endereços da EPROM, e somente endereços da EPROM, têm um 0 no bit de ordem alta, a15. Por conseguinte, basta ligar cs a a15 diretamente, como mostra a Figura 3.61(b). Figura 3.61 (a) Decodificac a o total de enderec o. (b) Decodificac a o parcial de enderec o. A0 A15 A0 A15 CS CS CS CS CS CS EPROM 2K × 8 RAM 2K × 8 PIO EPROM 2K × 8 RAM 2K × 8 PIO (a) (b) Barramento de endereço Barramento de endereço Nesse ponto, a decisão de colocar a RAM em 8000H pode parecer muito menos arbitrária. A decodifi- cação da RAM pode ser feita observando que somente endereços válidos da forma 10xxxxxxxxxxxxxx estão na RAM, portanto, 2 bits de decodificação são suficientes. De modo semelhante, qualquer endereço que comece com 11 deve ser um endereço PO. Agora, a lógica completa de decodificação são duas portas nand e um inversor.
  • 205. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 186 A lógica de decodificação de endereço da Figura 3.61(b) é denominada decodificação parcial de ende- reço, porque não são usados os endereços completos. Ela tem essa propriedade: uma leitura dos endereços 0001000000000000, 0001100000000000 ou 0010000000000000 dará o mesmo resultado. Na verdade, todo ende- reço na metade inferior do espaço de endereço selecionará a EPROM. Como os endereços extras não são usados, não há dano algum, mas se estivermos projetando um computador que poderá ser expandido no futuro (o que é improvável no caso de um brinquedo), devemos evitar a decodificação parcial porque ela ocupa muito espaço de endereço. Outra técnica comum de decodificação de endereço é usar um decodificador como o mostrado na Figura 3.13. Conectando as três entradas às três linhas de endereço de ordem alta, obtemos oito saídas correspondentes aos endereços nos primeiros 8 K, nos 8 K seguintes e assim por diante. Para um computador com oito RAMs, cada uma com 8 K × 8, um chip como esse fornece decodificação completa. Para um computador com oito chips de memória de 2 K × 8, um único decodificador também é suficiente, contanto que cada um dos chips de memória esteja localizado em porções distintas de 8 KB do espaço de endereço. (Lembre-se de que observamos anterior- mente que a posição dos chips de memória e E/S dentro do espaço de endereços tem importância.) 3.8 Resumo Computadores são construídos com base em chips de circuito integrado que contêm minúsculos elementos comutadores denominados portas. As portas mais comuns são and, or, nand, nor e not. Circuitos simples podem ser montados ao se combinar diretamente portas individuais. Circuitos mais complexos são multiplexadores, demultiplexadores, codificadores, decodificadores, deslo- cadores e ULAs. Funções booleanas arbitrárias podem ser programadas usando um FPGA. Se forem necessárias muitas funções booleanas, os FPGAs costumam ser mais eficientes. As leis da álgebra booleana podem ser usadas para transformar circuitos de uma forma para outra. Em muitos casos, é possível produzir circuitos mais econô- micos dessa maneira. A aritmética de computadores é efetuada por somadores. Um somador completo de um só bit pode ser cons- truído usando dois meios-somadores. Um somador para uma palavra multibit pode ser construído com a conexão de vários somadores completos de tal modo que permita o vai-um para seu vizinho da esquerda. Os componentes de memórias (estáticas) são latches e flip-flops, cada um dos quais pode armazenar um bit de informação. Esses bits podem ser combinados linearmente formando latches octais e flip-flops, ou por logaritmos formando memórias completas que usam palavras. Há memórias de vários tipos: RAM, ROM, PROM, EPROM, EEPROM e flash. RAMs estáticas não precisam ser renovadas; elas mantêm seus valores armazenados enquanto a energia estiver ligada. RAMs dinâmicas, por outro lado, devem ser renovadas periodicamente para compensar a fuga de corrente dos pequenos capacitores do chip. Os componentes de um sistema de computador são conectados por barramentos. Muitos pinos – não todos – de um chip de CPU típico comandam diretamente uma linha de barramento. Tais linhas podem ser divididas em linhas de endereço, de dados e de controle. Barramentos síncronos são comandados por um clock mestre. Barramentos assíncronos usam trocas completas para sincronizar o escravo com o mestre. O Core i7 é um exemplo de uma CPU moderna. Sistemas modernos que usam esse chip têm um barramento de memória, um barramento PCe e um barramento USB. A interconexão PCe é o modo mais comum de conectar as partes internas de um computador em altas velocidades. A ARM também é uma CPU moderna de alto nível, mas é voltada para sistemas embutidos e dispositivos móveis, onde o baixo consumo de energia é importante. O Atmel ATmega168 é um exemplo de um chip de baixo preço para aparelhos pequenos, baratos, e muitas outras aplicações sensíveis ao preço. Comutadores, luzes, impressoras e muitos outros dispositivos de E/S podem fazer interface com computadores usando interfaces de E/S paralela. Esses chips podem ser configurados como parte do espaço de E/S ou do espaço de memória, conforme a necessidade. Eles podem ser total ou parcialmente decodificados, dependendo da aplicação.
  • 206. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 187 Problemas 1. Circuitos analógicos estão sujeitos a ruído que pode distorcer sua saída. Os circuitos digitais são imunes ao ruído? Discuta sua resposta. 2. Um especialista em lógica entra em uma lancho- nete drive-in e diz: “Quero um hambúrguer ou um cachorro-quente e batatas fritas”. nfelizmente, o cozinheiro não sabe (ou não se importa) se “e” tem precedência sobre “ou”. Para ele, tanto faz uma ou outra interpretação. Quais dos seguintes casos são interpretações válidas do pedido? a. Apenas um hambúrguer. b. Apenas um cachorro-quente. c. Apenas batatas fritas. d. Um cachorro-quente e batatas fritas. e. Um hambúrguer e batatas fritas. f. Um cachorro-quente e um hambúrguer. g. Todo os três. h. Nada – o especialista em lógica passa fome por ser um espertinho. 3. Um missionário perdido no sul da Califórnia para em um entroncamento da rodovia. Ele sabe que duas gangues de motociclistas frequentam a área; uma delas sempre diz a verdade e a outra sempre mente. Ele quer saber qual estrada leva à Disneylândia. Que pergunta deve fazer? 4. Use a tabela verdade para mostrar que X = (X and Y) or (X and not Y). 5. Existem quatro funções booleanas de uma única variável e 16 funções de duas variáveis. Quantas funções de três variáveis existem? E de n variáveis? 6. Existem quatro funções booleanas de uma única variável e 16 funções de duas variáveis. Quantas fun- ções de quatro variáveis existem? 7. Mostre como a função and pode ser construída com base em duas portas nand. 8. Usando o chip multiplexador de três variáveis da Figura 3.12, execute uma função cuja saída é pari- dade das entradas, isto é, a saída é 1 se, e somente se, um número par de entradas for 1. 9. Ponha seu “capacete de raciocínio”. O chip mul- tiplexador de três variáveis da Figura 3.12 pode calcular uma função arbitrária de quatro variáveis booleanas. Descreva como e, a título de exemplo, desenhe o diagrama lógico para a função que é 0 se a palavra inglesa para a fila da tabela verdade tiver um número par de letras, é 1 se tiver um número ímpar de letras (por exemplo, 0000 = zero = quatro letras → 0; 0111 = seven = cinco letras → 1; 1101 = thirteen = oito letras → 0). Dica: se denominarmos a quarta entrada variável D, as oito linhas de entrada podem ser ligadas a Vcc, terra, D ou D. 10. Desenhe o diagrama lógico para um codificador de 2 bits, um circuito com quatro linhas de entrada, exatamente uma das quais é alta em qualquer instan- te dado, e duas linhas de saída cujo valor binário de 2 bits informa qual entrada é alta. 11. Desenhe o diagrama lógico para um demultiplexador de 2 bits, um circuito cuja única linha de entrada é direcionada para uma das quatro linhas de saída dependendo do estado das duas linhas de controle. 12. O que esse circuito faz? A B C D 13. Um chip comum é um somador de 4 bits. Quatro desses chips podem ser conectados para formar um somador de 16 bits. Quantos pinos você espera que tenha o chip do somador de 4 bits? Por quê? 14. Um somador de bits pode ser construído fazendo um arranjo em cascata de n somadores completos em série com o vem-um no estágio i, Ci, vindo da saída o estágio i – 1. O vem-um para o estágio 0, C0, é 0. Se cada estágio levar T nanossegundos para produzir sua soma e vai-um, o vem-um para o estágio i não será válido até iT nanossegundos após o início da adição. Para n grande, o tempo requerido para o vai- -um fazer o transporte (ripple) até o estágio de ordem alta pode ser inaceitavelmente longo. Projete um somador que funcione com mais rapidez. Dica: cada Ci pode ser expresso em termos dos bits de operando Ai – 1 e Bi – 1, bem como do vai-um Ci – 1. Usando essa relação, é possível expressar Ci como uma função das entradas para os estágios 0 a i – 1, de modo que todos os vai-um possam ser gerados simultaneamente. 15. amos admitir que todas as portas da Figura 3.18 tenham um atraso de propagação de 1 ns e que podemos ignorar todos os outros atrasos. Qual o menor tempo para esse circuito ter certeza de que um bit de saída é válido? 16. A ULA da Figura 3.19 é capaz de fazer adições de complemento 2 de oito bits. Ela também pode fazer subtrações de complemento 2? Se puder, explique como. Caso contrário, modifique-a para que possa efetuar subtrações.
  • 207. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 188 17. Uma ULA de 16 bits é composta de 16 ULAs de 1 bit, cada uma com um tempo de adição de 10 ns. Se houver 1 ns adicional de atraso de propagação de uma ULA para a seguinte, quanto tempo leva para aparecer o resultado de uma soma de 16 bits? 18. Às vezes, é útil que uma ULA de 8 bits como a da Figura 3.19 gere a constante –1 como saída. Proponha dois modos para fazer isso. Especifique os valores dos seis sinais de controle para cada um deles. 19. Qual é o estado quiescente das entradas S e R para um latch SR composto de duas portas nand? 20. O circuito da Figura 3.25 é um flip-flop que é dis- parado na borda ascendente do clock. Modifique esse circuito para produzir um flip-flop que é disparado na borda descendente. 21. A memória 4 × 3 da Figura 3.28 usa 22 portas and e três portas or. Se o circuito tivesse de ser expan- dido para 256 × 8, quantas portas de cada seriam necessárias? 22. Para ajudar a pagar o novo computador pessoal que comprou, você está prestando consultoria a novos fabricantes de chips SS. Um de seus clientes está pensando em produzir um chip que contém 4 flip- -flops D, cada um contendo Q e também Q, a pedido de um cliente potencialmente importante. O projeto proposto agrupa todos os quatro sinais de clock, tam- bém a pedido. Não há preset nem clear. Sua tarefa é fazer uma avaliação profissional do projeto. 23. À medida que cada vez mais memória é espremida em um único chip, o número de pinos necessários para endereçá-la também aumenta. Muitas vezes, é inconveniente ter grandes números de pinos de endereço em um chip. Proponha um meio de endereçar 2n palavras de memória usando menos do que n pinos. 24. Um computador com um barramento de dados de 32 bits de largura usa chips de memória RAM dinâmica de 1 M × 1. Qual é a menor memória (em bytes) que esse computador pode ter? 25. Referindo-nos ao diagrama temporal da Figura 3.38, suponha que você desacelerou o relógio para um período de 20 ns em vez de 10 ns, como mostra a figura, mas que as restrições de temporização per- maneceram inalteradas. Na pior das hipóteses, quanto tempo a memória teria para colocar os dados no bar- ramento durante T3 após mreq estar ativado? 26. Novamente com referência à Figura 3.38, suponha que o clock permaneceu a 100 MHz, mas TDS foi aumentado para 4 ns. Poderiam ser usados chips de memória de 10 ns? 27. Na Figura 3.38(b), TML é especificado para ser no mínimo 2 nanossegundos. ocê pode imaginar um chip no qual ele seja negativo? Especificamente, a CPU poderia ativar mreq antes de o endereço estar estável? Por que ou por que não? 28. Considere que a transferência de bloco da Figura 3.42 foi realizada no barramento da Figura 3.38. Quanto mais largura de banda obtemos usando uma transferência de bloco em comparação com trans- ferências individuais para blocos longos? Agora, considere que a largura do barramento é 32 bits, e não 8 bits. Responda à pergunta outra vez. 29. ndique os tempos de transição das linhas de endereço da Figura 3.39 como TA1 e TA2, e os tempos de transição de mreq como TMREQ1 e TMREQ2 e assim por diante. Anote todas as desigualdades implicadas pela troca completa. 30. Chips multicore, com várias CPUs no mesmo subs- trato, estão se tornando populares. Que vantagens elas têm em relação a um sistema consistindo de vários PCs conectados por uma Ethernet? 31. Por que os chips multicore apareceram de repente? Existem fatores tecnológicos que tenham preparado o caminho para eles? A lei de Moore tem alguma influência aqui? 32. Qual é a diferença entre o barramento de memória e o barramento PC? 33. A maioria dos barramentos de 32 bits permite leitu- ras e escritas de 16 bits. Há alguma ambiguidade sobre onde colocar os dados? Discuta. 34. Muitas CPUs têm um tipo especial de ciclo de barra- mento para reconhecimento de interrupção. Por quê? 35. Um computador de 32 bits com um barramento de 400 MHz requer quatro ciclos para ler uma palavra de 32 bits. Que largura de banda do barramento a CPU consome na pior das hipóteses, ou seja, con- siderando leituras ou escritas de ponta a ponta o tempo inteiro? 36. Um computador de 64 bits com um barramento de 400 MHz requer quatro ciclos para ler uma palavra de 64 bits. Que largura de banda do barramento a CPU consome na pior das hipóteses, ou seja, con- siderando leituras ou escritas de ponta a ponta o tempo inteiro? 37. Uma CPU de 32 bits com linhas de endereço A2–A31 requer que todas as referências à memória sejam alinha- das. sto é, palavras têm de ser endereçadas em múltiplos de 4 bytes, meias-palavras têm de ser endereçadas em bytes pares. Os bytes podem estar em qualquer lugar. Há quantas combinações legais para leituras de memória e quantos pinos são necessários para expressá-las? Dê duas respostas e justifique cada uma com um caso. 38. Chips de CPU modernos possuem um, dois ou até mesmo três níveis de cache no chip. Por que são necessários vários níveis de cache?
  • 208. C a p  t u l o 3 O n  v e l l o  g i c o d i g i t a l 189 39. Suponha que uma CPU tenha uma cache de nível 1 e uma de nível 2, com tempos de acesso de 1 ns e 2 ns, respectivamente. O tempo de acesso à memória principal é 10 ns. Se 20% dos acessos resultarem em presença na cache de nível 1 e 60% dos acessos resultarem em presença na cache de nível 2, qual é o tempo médio de acesso? 40. Calcule a largura de banda de barramento necessária para apresentar um filme em cores (1.280 × 960) a 30 quadros por segundo. Considere que os dados devam passar duas vezes pelo barramento, uma vez do CD-ROM para a memória e uma vez da memória para a tela. 41. Qual dos sinais da Figura 3.55 não é estritamente necessário para o funcionamento do protocolo de barramento? 42. Um sistema PC Express tem enlaces de 10 Mbps (capacidade bruta). Quantos fios de sinal são necessários em cada direção para operação 16x? Qual é a capacidade bruta em cada direção? Qual é a capacidade líquida em cada direção? 43. Um computador tem instruções que requerem dois ciclos de barramento cada: um para buscar a instru- ção e um para buscar os dados. Cada ciclo de bar- ramento leva 10 ns e cada instrução leva 20 ns (isto é, o tempo de processamento interno é desprezível). O computador também tem um disco com 2.048 setores de 512 bytes por trilha. O tempo de rotação do disco é 5 ms. A que porcentagem de sua veloci- dade normal o computador é reduzido durante uma transferência DMA se cada transferência DMA de 32 bits leva um ciclo de barramento? 44. A carga útil máxima de um pacote de dados isócrono no barramento USB é 1.023 bytes. Supondo que um dispositivo pode enviar só um pacote de dados por quadro, qual é a máxima largura de banda para um único dispositivo isócrono? 45. Que efeito causaria o acréscimo de uma terceira linha de entrada sobre uma porta nand selecionando a PO da Figura 3.61(b) se essa nova linha fosse conectada a a13? 46. Escreva um programa para simular o comporta- mento de uma matriz m × n de portas nand com duas entradas. Esse circuito, contido em um chip, tem j pinos de entrada e k pinos de saída. Os valores de j, k, m e n são parâmetros da simulação em tempo de compilação. O programa deve iniciar lendo em uma “lista de fiação” onde cada fio especifica uma entrada e uma saída. Uma entrada é um dos j pinos de entrada ou a saída de alguma porta nand. Uma saída ou é um dos k pinos de saída ou uma entrada para alguma porta nand. Entradas não usadas são 1 lógico. Após ler a lista de fiação, o programa deve imprimir a saída para cada uma das 2j entradas pos- síveis. Chips de porta vetorial como esse são muito usados para colocar circuitos sob encomenda em um chip porque a maior parte do trabalho (deposi- tar o arranjo vetorial no chip) é independente do circuito a ser executado. Somente a fiação é especí- fica para cada projeto. 47. Escreva um programa, na sua linguagem de programação favorita, para ler duas expressões booleanas quaisquer e verificar se elas represen- tam a mesma função. A linguagem de entrada deve incluir letras únicas, como variáveis booleanas, ope- randos and, or e not, e parênteses. Cada expressão deve caber em uma linha de entrada. O programa deve calcular tabelas verdade para ambas as funções e compará-las.
  • 209. O nível acima do lógico digital é o nível de microarquitetura. Sua função é executar o nível SA (nstruction Set Architecture – arquitetura do conjunto de instruções) acima dele, como ilustrado na Figura 1.2. O projeto do nível de microarquitetura depende da SA que está sendo implementada, bem como das metas de custo e desempenho do computador. Muitas SAs modernas, em particular projetos RSC, têm instruções simples que normalmente podem ser executadas em um único ciclo de clock. SAs mais complexas, como a Core i7, podem exigir muitos ciclos para executar uma única instrução. Executar uma instrução pode requerer localizar os operan- dos na memória, ler esses operandos e armazenar resultados de volta na memória. A sequência de operações dentro de uma única instrução muitas vezes leva a uma abordagem de controle diferente da adotada para SAs simples. 4.1 Um exemplo de microarquitetura O ideal seria que nós apresentássemos este tópico explicando os princípios gerais do projeto de microar- quitetura. nfelizmente, não há princípios gerais; cada microarquitetura é um caso especial. Por conseguinte, resolvemos discutir um exemplo detalhado. Para nossa SA que servirá de exemplo, escolhemos um subconjunto da Java irtual Machine, como prometemos no Capítulo 1. Esse subconjunto contém somente instruções com inteiros, portanto, nós o denominamos IJVM para enfatizar que ele trata somente de inteiros. Começaremos pela descrição da microarquitetura sobre a qual realizaremos a JM, arquitetura que tem algumas instruções complexas. Muitas dessas arquiteturas costumam ser executadas ao se recorrer à microprogra- mação, como discutimos no Capítulo 1. Embora a JM seja pequena, é um bom ponto de partida para descrever o controle e a sequência de instruções. O n vel de microarquitetura 4 Cap tulo
  • 210. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 191 Nossa microarquitetura conterá um microprograma (em ROM) cuja tarefa é buscar, decodificar e executar instruções JM. Não podemos usar o interpretador Oracle JM para o microprograma porque precisamos de um microprograma diminuto, que comande com eficiência portas individuais no hardware propriamente dito. Por comparação, o interpreta- dor Oracle JM foi escrito em C por questão de portabilidade, e não pode controlar o hardware de forma alguma. Como o hardware utilizado consiste apenas nos componentes básicos descritos no Capítulo 3, em teoria, se o leitor entender completamente esse capítulo, deverá estar habilitado a sair e comprar uma sacola de transistores e montar esse subconjunto da máquina JM. Os estudantes que conseguirem executar essa tarefa com sucesso ganharão créditos extras (e um exame psiquiátrico completo). Um modelo conveniente para o projeto de microarquitetura é pensar no projeto como um problema de programação no qual cada instrução no nível SA é uma função a ser chamada por um programa mestre. Nesse modelo, o programa mestre é um laço simples, sem fim, que determina uma função a ser invocada, chama a fun- ção e então começa de novo, algo muito parecido com a Figura 2.3. O microprograma tem um conjunto de variáveis denominado estado do computador, que pode ser acessado por todas as funções. Cada função altera ao menos algumas das variáveis que compõem o estado. Por exemplo, o contador de programa (Program Counter – PC) é parte do estado. Ele indica a localização da memória que contém a próxima função (isto é, instrução SA) a ser executada. Durante a execução de cada instrução, o PC é incrementado para indicar a próxima instrução a ser executada. nstruções JM são curtas e fáceis. Cada instrução tem alguns campos, em geral um ou dois, e cada um deles tem alguma finalidade específica. O primeiro campo de toda instrução é o opcode (abreviatura de operation code – código de operação), que identifica a instrução, informando se ela é um ADD ou um BRANCH, ou qualquer outra coisa. Muitas instruções têm um campo adicional que especifica o operando. Por exemplo, instruções que acessam uma variável local precisam de um campo que identifique qual variável. Esse modelo de execução, às vezes denominado ciclo buscar-decodificar-executar, é útil em termos abstratos e também pode ser a base para execução de SAs como a JM, isto é, que tenham instruções complexas. Logo adiante, descreveremos como ela funciona, qual é o aspecto da microarquitetura e como ela é controlada pelas microinstruções; cada uma delas controla o caminho de dados durante um ciclo. A lista de microinstruções forma o microprograma, que apresentaremos e discutiremos detalhadamente. 4.1.1 O caminho de dados O caminho de dados é a parte da CPU que contém a ULA, suas entradas e suas saídas. O caminho de dados de nossa microarquitetura de exemplo é mostrado na Figura 4.1. Embora tenha sido cuidadosamente otimizado para interpretar programas JM, ele guarda uma razoável semelhança com o caminho de dados usado na maioria das máquinas. Contém vários registradores de 32 bits, aos quais atribuímos nomes simbólicos como PC, SP e MDR. Embora alguns desses nomes sejam familiares, é importante entender que esses registradores são acessíveis apenas no nível de microarquitetura (pelo microprograma). Eles recebem esses nomes porque em geral contêm um valor correspondente à variável do mesmo nome na arquitetura do nível de SA. A maior parte dos regis- tradores pode dirigir seu conteúdo para o barramento B. A saída da ULA comanda o deslocador e em seguida o barramento C, cujo valor pode ser escrito em um ou mais registradores ao mesmo tempo. Por enquanto, não há nenhum barramento A; incluiremos um mais adiante. A ULA é idêntica à mostrada nas figuras 3.18 e 3.19. Sua função é determinada por seis linhas de controle. O segmento de reta diagonal com rótulo “6” na Figura 4.1 indica que há seis linhas de controle de ULA, a saber: F0 e F1 para determinar a operação da ULA; ENA e ENB para habilitar as entradas individualmente; INVA para inverter a entrada esquerda e INC para forçar um vai-um para o bit de ordem baixa, somando 1 ao resultado. Contudo, nem todas as 64 combinações de linhas de controle de ULA fazem algo de útil. Algumas das combinações mais interessantes são mostradas na Figura 4.2. Nem todas essas funções são necessárias para a JM, mas, para a JM completa, muitas delas viriam a calhar. Em muitos casos, há várias possibilidades de conseguir o mesmo resultado. Nessa tabela, + significa “mais” aritmético e – significa “menos” aritmético; assim, por exemplo, –A significa o complemento de dois de A.
  • 211. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 192 Figura 4.1 Caminho de dados da microarquitetura de exemplo usada neste cap tulo. H Controle do deslocador Deslocador ULA 2 N A B Barramento B Barramento C 6 Controle da ULA Sinais de controle Registradores de controle da memória Habilitar para barramento B Escrever barramento C para registrador De e para a memória principal Z SP LV CPP TOS OPC PC MDR MAR MBR A ULA da Figura 4.1 precisa de duas entradas de dados: uma entrada esquerda (A) e uma entrada direita (B). Ligado à entrada esquerda está um registrador de retenção, H. Ligado à entrada direita está o barramento B, que pode ser carre- gado por cada uma de nove fontes, indicadas pelas nove setas cinza que chegam até ele. Um projeto alternativo, com dois barramentos completos, tem um conjunto diferente de opções de projeto e será discutido mais adiante neste capítulo. H pode ser carregado com a escolha de uma função da ULA que passe diretamente da entrada direita (vinda do barramento B) para a saída da ULA. Uma função desse tipo seria somar as entradas da ULA, porém, com ENA nega- do, de modo que a entrada esquerda é forçada a zero. Adicionar zero ao valor no barramento B resulta somente no valor no barramento B. Então, esse resultado pode ser passado pelo deslocador sem modificação e armazenado em H. Além das funções citadas, duas outras linhas de controle podem ser usadas independentemente para con- trolar a saída da ULA. SLL8 (Shift Left Logical) desloca o conteúdo para a esquerda por 1 byte, preenchendo os 8 bits menos significativos com zeros. SRA1 (Shift Right Arithmetic) desloca o conteúdo para a direita por 1 bit, deixando inalterado o bit mais significativo.
  • 212. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 193 Figura 4.2 Combinac o es u teis de sinais de ULA e a func a o executada. F0 F1 ENA ENB INVA INC Função 0 1 1 0 0 0 A 0 1 0 1 0 0 B 0 1 1 0 1 0 A 1 0 1 1 0 0 B 1 1 1 1 0 0 A + B 1 1 1 1 0 1 A + B + 1 1 1 1 0 0 1 A + 1 1 1 0 1 0 1 B + 1 1 1 1 1 1 1 B – A 1 1 0 1 1 0 B – 1 1 1 1 0 1 1 –A 0 0 1 1 0 0 A AND B 0 1 1 1 0 0 A OR B 0 1 0 0 0 0 0 1 1 0 0 0 1 1 1 1 0 0 1 0 –1 É explicitamente possível ler e escrever o mesmo registrador em um único ciclo. Por exemplo, é permitido colocar SP no barramento B, desativar a entrada esquerda da ULA, habilitar o sinal INC e armazenar o resultado em SP, desse modo incrementando SP em 1 (veja a oitava linha na Figura 4.2). Como um registrador pode ser lido e escrito no mesmo ciclo sem produzir lixo? A solução é que leitura e escrita na verdade são executadas em instantes diferentes dentro do ciclo. Quando um registrador é selecionado como a entrada direita da ULA, seu valor é colocado no barramento B no início do ciclo e ali é mantido durante todo o ciclo. Depois, a ULA realiza seu trabalho, produzindo um resultado que passa pelo deslocador e entra no barramento C. Próximo ao final do ciclo, quando se sabe que as saídas da ULA e deslocador são estáveis, um sinal de clock ativa o armazenamento do conteúdo do barramento C e o passa para um ou mais dos registradores. Um deles pode perfeitamente ser aquele que forneceu sua saída ao barramento B. A temporização exata do caminho de dados possibilita ler e escrever o mesmo registrador em um único ciclo, como descreveremos a seguir. Temporizac a o do caminho de dados A temporização desses eventos é mostrada na Figura 4.3. Um pulso curto é produzido no início de cada ciclo de clock. Ele pode ser derivado do clock principal, como ilustra a Figura 3.20(c). Na borda descendente do pulso, os bits que comandarão todas as portas são ajustados, o que leva um tempo finito e conhecido, ∆w. Depois, o registrador necessário no barramento B é selecionado e conduzido até este. Demora ∆x para o valor ficar está- vel. Então, a ULA e o deslocador começam a operar com dados válidos. Após outro ∆y, as saídas da ULA e do deslocador estão estáveis. Após um ∆z adicional, os resultados se propagaram ao longo do barramento C até os registradores, onde podem ser carregados na borda ascendente do próximo pulso. A carga deve ser acionada pela borda ascendente do próximo pulso e de forma rápida, de modo que, se alguns dos registradores de entrada forem alterados, o efeito não será sentido no barramento C até muito tempo após os registradores terem sido carregados.
  • 213. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 194 Também na borda ascendente do pulso, o registrador que comanda o barramento B para de fazê-lo preparando- -se para o próximo ciclo. MPC, MIR e a memória são mencionados na figura; em breve, discutiremos seus papéis. É importante perceber que, ainda que não haja nenhum elemento de armazenamento no caminho de dados, há um tempo de propagação finito por ele. Uma alteração de valor no barramento B só provocará uma alteração no barramento C após um tempo finito (por causa dos atrasos finitos de cada etapa). Por conseguinte, mesmo que um armazenamento altere um dos registradores de entrada, o valor estará guardado em segurança no registrador muito antes que o valor (agora incorreto) que está sendo colocado no barramento B (ou H) possa alcançar a ULA. Fazer esse esquema funcionar requer rígida temporização, um ciclo de clock longo, um tempo mínimo de propagação pela ULA conhecido e uma carga rápida dos registradores pelo barramento C. Contudo, com cuida- dosa engenharia, o caminho de dados pode ser projetado de modo que funcione corretamente o tempo todo. Na verdade, as máquinas reais funcionam desse modo. Um modo um pouco diferente de ver o ciclo de caminho de dados é imaginá-lo fragmentado em subciclos implícitos. O início do subciclo 1 é acionado pela borda descendente do clock. As atividades que ocorrem durante os subciclos são mostradas a seguir, junto com as extensões dos subciclos (entre parênteses). 1. Os sinais de controle são ajustados (∆w). 2. Os registradores são carregados no barramento B (∆x). 3. Operação da ULA e deslocador (∆y). 4. Os resultados se propagam ao longo do barramento C de volta aos registradores (∆z). O intervalo de tempo após ∆z oferece alguma tolerância, pois os tempos não são exatos. Na borda ascendente do próximo ciclo de clock, os resultados são armazenados nos registradores. Dissemos que é melhor imaginar os subciclos como implícitos. Com isso, queremos dizer que não há nenhum pulso de clock ou outros sinais explícitos que indiquem à ULA quando operar ou que digam aos resultados que entrem no barramento C. Na verdade, a ULA e o deslocador funcionam o tempo todo. Contudo, suas entradas são lixo até um tempo ∆w + ∆x após a borda descendente do clock. Do mesmo modo, suas saídas são lixo até que ∆w + ∆x + ∆y tenha transcorrido após a borda descendente do clock. Os únicos sinais explícitos que comandam Figura 4.3 Diagrama de temporizac a o de um ciclo de caminho de dados. Ciclo 1 começa aqui Saída do deslocador estável Registradores carregados instantaneamente do barramento C e da memória na borda ascendente do clock Prepara sinais para comandar o caminho de dados ULA e deslocador Drive H e barramento B Propagação do deslocador aos registradores ∆w ∆x ∆y ∆z Ciclo de clock 1 Ciclo de clock 2 MPC disponível aqui Novo MPC usado para carregar MIR com a próxima microinstrução aqui
  • 214. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 195 o caminho de dados são a borda descendente do clock, que inicia o ciclo do caminho de dados, e a borda ascen- dente, que carrega os registradores a partir do barramento C. As outras fronteiras de subciclos são determinadas implicitamente pelos tempos de propagação inerentes dos circuitos envolvidos. Cabe aos engenheiros de projeto garantir que o tempo ∆w + ∆x + ∆y + ∆z venha suficientemente antes da borda ascendente do clock para fazer as cargas de registrador funcionarem de modo confiável o tempo todo. Operac a o de memo ria Nossa máquina tem dois modos diferentes de se comunicar com a memória: uma porta de memória de 32 bits, endereçável por palavra, e outra de 8 bits, endereçável por byte. A porta de 32 bits é controlada por dois registradores, MAR (Memory ddress Register  registrador de endereço de memória) e MDR (Memory ata Register  registrador de dados de memória), como mostra a Figura 4.1. A porta de 8 bits é controlada por um registrador, PC, que lê 1 byte para os 8 bits de ordem baixa do MBR. Essa porta só pode ler dados da memória; ela não pode escrever dados na memória. Cada um desses registradores (e todos os outros na Figura 4.1) é comandado por um ou dois sinais de con- trole. Uma seta clara sob um registrador indica um sinal de controle que habilita a saída do registrador para o barramento B. isto que MAR não tem conexão com o barramento B, não tem sinal de habilitação. H também não tem esse sinal porque está sempre habilitado, por ser a única entrada esquerda possível da ULA. Uma seta negra sob um registrador indica um sinal de controle que escreve (isto é, carrega) o registrador a partir do barramento C. Uma vez que MBR não pode ser carregado a partir do barramento C, não tem um sinal de escrita (embora tenha dois outros sinais de habilitação, descritos mais adiante). Para iniciar uma leitura ou escrita da memória, os registradores de memória adequados devem ser carregados e em seguida deve ser emitido um sinal de leitura ou escrita para a memória (não mostrado na Figura 4.1). MAR contém endereços de palavras, de modo que os valores 0, 1, 2 etc. se referem a palavras consecutivas. PC contém endereços de bytes, portanto, os valores 0, 1, 2 etc. se referem a bytes consecutivos. Assim, colocar um 2 em PC e iniciar uma leitura de memória lerá o byte 2 da memória e o colocará nos 8 bits de ordem baixa do MBR. Colocar 2 em MAR e iniciar uma leitura de memória lerá os bytes 8–11 (isto é, palavra 2) da memória e os colocará em MDR. Essa diferença de funcionalidade é necessária porque MAR e PC serão usados para referenciar duas partes diferentes da memória. A necessidade dessa distinção ficará mais clara adiante. Por enquanto, basta dizer que a combinação MAR/MDR é usada para ler e escrever palavras de dados de nível SA e a combinação PC/MBR é empregada para ler o programa executável de nível SA, que consiste em uma sequência de bytes. Todos os outros registradores que contêm endereços usam endereço de palavras, como o MAR. Na implementação física propriamente dita, há apenas uma memória real que funciona com bytes. Permitir que MAR conte palavras (isso é necessário por causa do modo como a JM é definida) enquanto a memória física conta bytes depende de um truque simples. Quando o MAR é colocado no barramento de endereço, seus 32 bits não são mapeados diretamente para as 32 linhas de endereço, 0–31. Em vez disso, o bit 0 do MAR é ligado à linha 2 do barramento de endereço, o bit 1 do MAR é ligado à linha 3 do barramento de endereço e assim por diante. Os 2 bits superiores do MAR são descartados, visto que só são necessários para endereços de palavra acima de 232 , nenhum dos quais é válido para nossa máquina de 4 GB. Usando esse mapeamento, quando MAR é 1, o endereço 4 é colocado no barramento; quando MAR é 2, o endereço 8 é colocado no barramento e assim por diante. Esse estratagema está ilustrado na Figura 4.4. Como já mencionamos, dados lidos da memória por uma porta de memória de 8 bits são devolvidos em MBR, um registrador de 8 bits. MBR pode ser copiado (gated) para o barramento B por um entre dois modos: com ou sem sinal. Quando é preciso o valor sem sinal, a palavra de 32 bits colocada no barramento B contém o valor MBR nos 8 bits de ordem baixa e zeros nos 24 bits superiores. alores sem sinal são úteis para indexar em uma tabela ou quando um inteiro de 16 bits tem de ser montado a partir de 2 bytes consecutivos (sem sinal) na sequência de instrução. A outra opção para converter o MBR de 8 bits em uma palavra de 32 bits é tratá-lo como um valor com sinal entre –128 e +127 e usar esse valor para gerar uma palavra de 32 bits com o mesmo valor numérico. Essa conversão é feita duplicando o bit de sinal do MBR (o bit mais à esquerda) nas 24 posições superiores de bits do barramento B, um processo denominado extensão de sinal. Quando essa opção é escolhida, os 24 bits superiores serão todos 0s ou todos 1s, dependendo do bit mais à esquerda do MBR de 8 bits ser um 0 ou um 1.
  • 215. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 196 Figura 4.4 Mapeamento dos bits em MAR para o barramento de enderec o. Descartados MAR de 32 bits (contagem em palavras) Barramento de endereço de 32 bits (contagem em bytes) 0 0 A opção de converter o MBR de 8 bits em um valor de 32 bits com sinal ou sem sinal no barramento B é determinada por qual dos dois sinais de controle (setas claras sob MBR na Figura 4.1) for ativado. A necessidade dessas duas opções é a razão de haver duas setas presentes. A capacidade de fazer o MBR de 8 bits agir como uma fonte de 32 bits para o barramento B é indicada pelo retângulo tracejado na figura. 4.1.2 Microinstruc o es Para controlar o caminho de dados da Figura 4.1 precisamos de 29 sinais, que podem ser divididos em cinco grupos funcionais, como descreveremos a seguir: 9 sinais para controlar escrita de dados do barramento C para registradores. 9 sinais para controlar habilitação de registradores dirigidos ao barramento B para a entrada da ULA. 8 sinais para controlar as funções da ULA e do deslocador. 2 sinais (não mostrados) para indicar leitura/escrita na memória via MAR/MDR. 1 sinal (não mostrado) para indicar busca na memória via PC/MBR. Os valores desses 29 sinais de controle especificam as operações para um ciclo do caminho de dados. Um ciclo consiste em copiar valores dos registradores para o barramento B, propagar os sinais pela ULA e pelo deslocador, dirigi-los ao barramento C e, por fim, escrever os resultados no registrador ou registradores adequados. Além disso, se um sinal de leitura de dados da memória for ativado, a operação de memória é iniciada no final do ciclo de cami- nho de dados, após o MAR ter sido carregado. Os dados da memória estão disponíveis no final do ciclo seguinte em MBR ou MDR e podem ser usados no ciclo que vem depois daquele. Em outras palavras, uma leitura de memória em qualquer porta iniciada no final do ciclo k entrega dados que não podem ser usados no ciclo k + 1, porém, somente no ciclo k + 2 ou mais tarde. Esse comportamento que parece anti-intuitivo é explicado pela Figura 4.3. Os sinais de controle da memória não são gerados no ciclo de clock 1 até que MAR e PC sejam carregados na borda ascendente do clock, próximo ao final do ciclo de clock 1. Consideraremos que a memória coloca seus resultados nos barramentos de memória dentro de um ciclo, portanto, que MBR e/ou MDR podem ser carregados na próxima borda ascendente do clock, junto com os outros registradores. Em outras palavras, carregamos MAR no final de um ciclo de caminho de dados e iniciamos a memória logo após. Por conseguinte, na realidade não podemos esperar que os resultados de uma operação de leitura estejam em MDR no início do próximo ciclo, em especial se a largura do pulso de clock for curta. Não há tempo suficiente se a memória demora um ciclo de clock. Um ciclo de caminho de dados deve ser interposto entre o início de uma leitura de memória e a utilização do resultado. É claro que outras operações podem ser executadas durante aquele ciclo, mas não as que necessitam da palavra de memória.
  • 216. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 197 Supor que a memória leva um ciclo para operar equivale a supor que a taxa de presença na cache de nível 1 é 100%. Essa suposição nunca é verdadeira, mas a complexidade introduzida por um tempo de ciclo de memória de duração variável é mais do que o que queremos discutir aqui. Uma vez que MBR e MDR são carregados na borda ascendente do clock, com todos os outros registradores, eles podem ser lidos durante ciclos em que está sendo realizada uma nova leitura de memória. Eles retornam aos valores antigos, já que a leitura ainda não teve tempo de sobrescrevê-los. Aqui não há ambiguidade alguma; até que novos valores sejam carregados em MBR e MDR na borda ascendente do clock, os precedentes ainda estão ali e podem ser usados. Note que é possível fazer leituras seguidas em dois ciclos consecutivos, uma vez que uma leitura leva apenas um. Além disso, ambas as memórias podem funcionar ao mesmo tempo. Contudo, tentar ler e escrever o mesmo byte em simultâneo gera resultados indefinidos. Embora talvez seja desejável escrever a saída no barramento C em mais de um registrador, nunca é aconselhável habilitar mais de um por vez no barramento B. Na verdade, algumas implementações reais sofrerão dano físico se isso for feito. Com um pequeno aumento no conjunto de circuitos podemos reduzir o número de bits necessários para selecionar entre as possíveis fontes para comandar o barramento B. Há somente nove registradores de entrada possí- veis que podem comandar o barramento B (onde cada versão do MBR com sinal e sem sinal é contada como uma ver- são individual). Portanto, podemos codificar as informações do barramento B em 4 bits e usar um decodificador para gerar os 16 sinais de controle, sete dos quais não são necessários. Em um projeto comercial, os arquitetos seriam ata- cados por um desejo desesperado de se livrar de um dos registradores de modo que 3 bits fizessem o trabalho. Como acadêmicos, podemos nos dar ao enorme luxo de desperdiçar 1 bit para obter um projeto mais limpo e mais simples. Nesse ponto, podemos controlar o caminho de dados com 9 + 4 + 8 + 2 + 1 = 24 sinais, daí 24 bits. Contudo, esses 24 bits só controlam o caminho de dados por um ciclo. A segunda parte do controle é determinar o que fazer no ciclo seguinte. Para incluir isso no projeto do controlador, criaremos um formato para descrever as operações a serem realizadas usando os 24 bits de controle mais dois campos adicionais: NEXT_ADDRESS e JAM. O conteúdo de cada um desses campos será discutido em breve. A Figura 4.5 mostra um formato possível, dividido em seis grupos (listados abaixo da instrução) e contendo os seguintes 36 sinais: Addr – Contém o endereço de uma microinstrução potencial seguinte. JAM – Determina como a próxima microinstrução é selecionada. ULA – Funções da ULA e do deslocador. C – Seleciona quais registradores são escritos a partir do barramento C. Mem – Funções de memória. B – Seleciona a fonte do barramento B; é codificado como mostrado. A ordem dos grupos é, em princípio, arbitrária, embora na verdade a tenhamos escolhido com muito cuidado para minimizar cruzamentos de linhas na Figura 4.6. Cruzamentos de linhas em diagramas esquemáticos como essa figura costumam corresponder a cruzamento de fios em chips, o que causa problemas em projetos bidimen- sionais, portanto, é melhor minimizá-los. Figura 4.5 Formato da microinstruc a o para a Mic-1 (descrita em breve adiante). Bits 9 3 8 9 3 4 NEXT_ADDRESS Addr JAM ULA C Mem B R E A D F E T C H J A M N J M P C J A M Z S L L 8 S R A 1 F0 F1 E N A E N B I N V A I N C H O P C T O S C P P L V S P P C M D R M A R W R I T E Barra- mento B Registradores do barramento B 0 = MDR 1 = PC 2 = MBR 3 = MBRU 4 = SP 5 = LV 6 = CPP 7 = TOS 8 = OPC 9-15 nenhum
  • 217. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 198 Figura 4.6 Diagrama de blocos completo de nossa microarquitetura de exemplo, a Mic-1. H Deslocador ULA 2 N Barramento B 6 Controle da ULA Sinais de controle Sinais de controle de memória (rd, wr, fetch) Habilita para barramento B Escreve barramento C no registrador Z Barramento C SP LV CPP TOS OPC PC MDR MAR MBR 9 O Armazenamento de controle de 512 × 36 bits para conter o microprograma 3 8 Decodicador 4 para 16 2 9 4 MPC MIR Addr J ULA C M B Flip-op de 1 bit Bit alto JMPC JAMN/JAMZ 4.1.3 Controle de microinstruc a o: a Mic-1 Até aqui, descrevemos como o caminho de dados é controlado, mas ainda não explicamos como é decidido qual dos sinais de controle deve ser habilitado em cada ciclo. sso é determinado por um sequenciador, que é responsável por escalonar a sequência de operações necessárias para a execução de uma única instrução SA. O sequenciador deve produzir dois tipos de informação a cada ciclo: 1. O estado de cada sinal de controle no sistema. 2. O endereço da microinstrução que deve ser executada em seguida.
  • 218. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 199 A Figura 4.6 é um diagrama de blocos detalhado da microarquitetura completa de nossa máquina de exem- plo, que denominaremos Mic-1. Ela pode parecer imponente de início, mas vale a pena estudá-la com cuidado. Quando você entender totalmente cada retângulo e cada linha dessa figura, terá avançado bastante no entendi- mento do nível de microarquitetura. O diagrama de blocos tem duas partes: o caminho de dados, à esquerda, que já discutimos em detalhes, e a seção de controle, à direita, que estudaremos agora. O maior item e também o mais importante na parte do controle da máquina é uma memória denominada armazenamento de controle. É conveniente imaginá-la como uma memória que contém o microprograma com- pleto, embora às vezes ele seja executado como um conjunto de portas lógicas. Em geral, vamos nos referir a ele como o armazenamento de controle para evitar confusão com a memória principal, acessada por meio de MBR e MDR. Contudo, em termos funcionais, o armazenamento de controle é uma memória que apenas contém microins- truções em vez de instruções SA. No caso da nossa máquina de exemplo, ele contém 512 palavras, cada uma con- sistindo em uma microinstrução de 36 bits do tipo ilustrado na Figura 4.5. Na verdade, nem todas essas palavras são necessárias, mas (por razões que explicaremos em breve) precisamos de endereços para 512 palavras distintas. Em um aspecto importante, o armazenamento de controle é bem diferente da memória principal: instruções na memória principal são sempre executadas em ordem de endereço (exceto para os desvios); microinstruções não são. O ato de incrementar o contador de programa na Figura 2.3 expressa o fato de que a instrução padrão (default) a executar após a instrução corrente é a instrução seguinte àquela corrente na memória. Microprogramas precisam de mais flexibilidade (porque as sequências de microinstruções tendem a ser curtas), e, portanto, não costumam ter essa propriedade. Em vez disso, cada microinstrução especifica explicitamente sua sucessora. Uma vez que, em termos funcionais, o armazenamento de controle é uma memória (só de leitura), ele pre- cisa de seu próprio registrador de endereço de memória e de seu próprio registrador de dados de memória. Não precisa ler nem escrever sinais porque está sendo lido continuamente. Denominaremos o registrador de endereço de memória do armazenamento de controle MPC (MicroProgram Counter  contador de microprograma). Esse nome é irônico, já que as localizações nele são explicitamente não ordenadas, portanto, o conceito de contagem não é útil (mas quem somos nós para discutir uma tradição?). O registrador de dados de memória é denominado MIR (MicroInstruction Register  registrador de microinstrução). Sua função é conter a microinstrução corren- te, cujos bits comandam os sinais de controle que operam o caminho de dados. O registrador MIR na Figura 4.6 contém os mesmos seis grupos da Figura 4.5. Os grupos Addr e J (de JAM) controlam a seleção da microinstrução seguinte e serão discutidos em breve. O grupo ULA contém os 8 bits que selecionam a função ULA e comandam o deslocador. Os bits C fazem os registradores individuais carregarem a saída da ULA vinda do barramento C. Os bits M controlam operações de memória. Por fim, os últimos 4 bits comandam o decodificador que determina o que entra no barramento B. Nesse caso, preferimos usar um decodificador padrão 4 para 16, mesmo que sejam requeridas apenas nove possibilidades. Em um projeto mais afinado, poderia ser usado um decodificador 4 para 9. Nesse caso, o compromisso é usar um circuito padrão que possa ser encontrado em uma biblioteca de circuitos em vez de projetar um circuito fabricado sob espe- cificação. Usar o circuito padrão é mais simples e a probabilidade de introduzir bugs é menor. Construir seu próprio circuito usa menos área de chip, mas leva mais tempo para projetar e há sempre a possibilidade de você errar. A operação da Figura 4.6 é a seguinte. No início de cada ciclo de clock (a borda descendente na Figura 4.3), MIR é carregado a partir da palavra no armazenamento de controle apontada pelo MPC. O tempo de carga do MIR é indicado na figura por ∆w. Se pensarmos em termos de subciclos, MIR é carregado durante o primeiro. Assim que a microinstrução é estabelecida em MIR, os vários sinais se propagam para dentro do caminho de dados. Um registrador é copiado para o barramento B, a ULA sabe qual operação realizar e a atividade é frenética. Esse é o segundo subciclo. Após um intervalo ∆w + ∆x a partir do início do ciclo, as entradas da ULA estão estáveis. Após mais um ∆y, tudo se acomoda e as saídas da ULA, N, Z e do deslocador estão estáveis. Então, os valores N e Z são salvos em um par de flip-flops de 1 bit. Esses bits, como os registradores que são carregados a partir do barramento C e na memória, são salvos na borda ascendente do clock, próximo ao final do ciclo do caminho de dados. A saída da ULA não é serializada, mas apenas alimentada no deslocador. A atividade da ULA e do deslo- cador ocorre durante o subciclo 3. Após um intervalo adicional, ∆z, a saída do deslocador alcançou os registradores via barramento C. Então, estes podem ser carregados perto do final do ciclo (borda ascendente do pulso de clock na Figura 4.3). O subciclo 4 consiste em carregar os registradores e flip-flops N e Z e termina um pouco após a borda ascendente do clock,
  • 219. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 200 quando todos os resultados foram salvos e os produtos das operações de memória anteriores estão disponíveis e o MPC foi carregado. O processo continua até alguém se entediar e desligar a máquina. Em paralelo com o comando do caminho de dados, o microprograma tem de determinar qual microinstru- ção executar em seguida, porque elas precisam ser executadas na ordem em que aparecem no armazenamento de controle. O cálculo do endereço da próxima microinstrução começa após MIR ter sido carregado e estar estável. Primeiro, o campo NEXT_ADDRESS de 9 bits é copiado para MPC. Enquanto essa cópia está ocorrendo, o campo JAM é inspecionado. Se tiver valor 000, nada mais é feito; quando a cópia de NEXT_ADDRESS estiver concluída, o MPC apontará a próxima microinstrução. Se um ou mais dos bits JAM for 1, é preciso mais trabalho. Se JAMN estiver ativado, o flip-flop N de 1 bit sofre uma operação OR com o bit de ordem alta do MPC. De modo semelhante, se JAMZ estiver ativado, é o flip-flop Z de 1 bit que passa pela operação OR. Se ambos estiverem ajustados, ambos passam por OR. A razão de os flip- -flops N e Z serem necessários é que, após a borda ascendente do clock (enquanto o clock está alto), o barramento B não está mais sendo comandado, portanto, as saídas da ULA não podem mais ser tomadas como corretas. Salvar os flags de estado da ULA em N e Z torna os valores corretos disponíveis e estáveis para o cálculo do MPC, não importa o que esteja ocorrendo na ULA. Na Figura 4.6, a lógica que faz tal cálculo é denominada “bit alto”. A função booleana que ela calcula é F = (JAMZ AND Z) OR (JAMN AND N) OR NEXT_ADDRESS[8] Note que, em todos os casos, MPC só pode assumir um de dois valores possíveis: 1. O valor de NEXT_ADDRESS. 2. O valor de NEXT_ADDRESS com o bit de ordem alta que passa por uma operação OR com 1. Não existe nenhuma outra possibilidade. Se o bit de ordem alta de NEXT_ADDRESS já for 1, usar JAMN ou JAMZ não tem sentido. Note que, quando os bits JAM são todos zeros, o endereço da próxima microinstrução a ser executada é simplesmente o número de 9 bits em seu campo NEXT_ADDRESS. Quando ou JAMN ou JAMZ é 1, há dois sucessores potenciais: NEXT_ADDRESS e NEXT_ADDRESS com operação OR com 0x100 (considerando que NEXT_ADDRESS ≤ 0xFF). (Note que 0x indica que o número que vem em seguida está em hexadecimal.) Esse ponto é ilustrado na Figura 4.7. A microinstrução corrente, na localização 0x75, tem NEXT_ADDRESS = 0x92 e JAMZ ajustado para 1. Por conseguinte, o próximo endereço da microinstrução depende do bit Z armazenado durante a operação de ULA anterior. Se o bit Z for 0, a próxima microinstrução vem de 0x92. Se o bit Z for 1, a próxima microinstrução vem de 0x192. O terceiro bit no campo JAM é JMPC. Se ele estiver ativado, os 8 bits MBR passam por uma operação OR bit a bit com os 8 bits de ordem baixa do campo NEXT_ADDRESS que vem da microinstrução corrente. O resultado é enviado a MPC. O retângulo com o rótulo “O” na Figura 4.6 faz uma OR de MBR com NEXT_ADDRESS se JMPC for 1, mas apenas passa NEXT_ADDRESS diretamente para MPC se JMPC for 0. Quando JMPC é 1, os 8 bits de ordem baixa de NEXT_ADDRESS em geral são zero. O bit de ordem alta pode ser 0 ou 1, portanto, o valor de NEXT_ADDRESS usado com JMPC normalmente é 0x000 ou 0x100. A razão para usar às vezes 0x000 e às vezes 0x100 será discutida mais adiante. A capacidade de efetuar OR entre MBR e NEXT_ADDRESS e armazenar o resultado em MPC permite uma execução eficiente de um desvio (jump) multivias. Note que qualquer um dos 256 endereços pode ser especifica- do, determinado exclusivamente pelos bits presentes em MBR. Em uma utilização típica, MBR contém um código de operação, que chamaremos de opcode, portanto, a utilização de JMPC resultará em uma seleção única para a próxima microinstrução a ser executada para todo opcode possível. Esse método é útil para fazer desvios rápidos diretamente para a função correspondente ao opcode que acabou de ser buscado. Entender a temporização da máquina é crítico para o que vem a seguir, portanto, talvez valha a pena repeti- -la. Faremos isso em termos de subciclos, uma vez que é fácil de visualizar, mas os únicos eventos de clock reais são a borda descendente, que inicia o ciclo, e a borda ascendente, que carrega os registradores e os flip-flops N e Z. Favor consultar a Figura 4.3 mais uma vez.
  • 220. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 201 Figura 4.7 Microinstruc a o com JAMZ ajustado para 1 tem duas sucessoras potenciais. … … Endereço Addr Bits de controle do caminho de dados Um desses virá após 0x75 dependendo de Z JAM Bit JAMZ ajustado 0x75 0x92 0x92 0x192 001 Durante o subciclo 1, iniciado pela borda descendente do clock, MIR é carregado a partir do endereço con- tido em MPC no instante em questão. Durante o subciclo 2, os sinais de MIR se propagam e o barramento B é carregado a partir do registrador selecionado. Durante o subciclo 3, a ULA e o deslocador funcionam e produzem um resultado estável. Durante o subciclo 4, os valores do barramento C, dos barramentos de memória e da ULA tornam-se estáveis. Na borda ascendente do clock, os registradores são carregados a partir do barramento C, flip- -flops N e Z são carregados e MBR e MDR obtêm seus resultados da operação de memória iniciada no final do ciclo de caminho de dados anterior (se houver algum). Assim que o valor de MBR estiver disponível, MPC é carregado em preparação para a próxima microinstrução. Assim, MPC obtém seu valor em algum instante durante o meio do intervalo quando o clock está alto, mas após MBR/MDR estarem prontos. Ele poderia ser ativado no nível (em vez de ativado pela borda) ou ativado pela borda com um atraso fixo após a borda ascendente do clock. O que real- mente importa é que MPC não seja carregado até que os registradores dos quais ele depende (MBR, N e Z) estejam prontos. Tão logo o clock caia, MPC pode endereçar o armazenamento de controle e um novo ciclo pode começar. Note que cada ciclo é autossuficiente. Ele especifica o que ocorre no barramento B, o que a ULA e o deslo- cador têm de fazer, onde o barramento C deve ser armazenado e, por fim, qual deve ser o próximo valor de MPC. ale a pena fazer uma observação final sobre a Figura 4.6. Estamos tratando o MPC como um registrador propriamente dito, com 9 bits de capacidade de armazenamento, que é carregado enquanto o clock está alto. Na realidade, não há necessidade alguma de um registrador ali. Todas as suas entradas podem ser alimentadas diretamente para o armazenamento de controle. Basta que elas estejam presentes no armazenamento de contro- le na borda descendente do clock quando MIR é selecionado e lido. Na verdade, não há necessidade alguma de armazená-las em MPC. Por essa razão, o MPC pode perfeitamente ser executado como um registrador virtual, que é apenas um lugar de reunião para sinais, mais como se fosse um painel de conexão eletrônico do que um regis- trador real. Transformar o MPC em um registrador virtual simplifica a temporização: agora, os eventos acontecem somente nas bordas descendentes e ascendentes do clock e em nenhum outro lugar. Porém, se for mais fácil para você imaginar um MPC como um registrador real, esse ponto de vista também é válido. 4.2 Exemplo de ISA: IJVM amos continuar nosso exemplo introduzindo o nível SA da máquina a ser interpretado pelo microprogra- ma que é executado na microarquitetura da Figura 4.6 (JM). Por conveniência, às vezes vamos nos referir a nstruction Set Architecture (SA) como a macroarquitetura, para contrastá-la com a microarquitetura. Contudo, antes de descrever a JM, vamos fazer uma ligeira digressão com o intuito de motivação. 4.2.1 Pilhas Praticamente todas as linguagens de programação trabalham com o conceito de procedimentos (métodos), que têm variáveis locais. Essas variáveis podem ser acessadas de dentro dos procedimentos, mas deixam de ser
  • 221. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 202 acessíveis assim que o procedimento é devolvido. Portanto, surge a pergunta: “Em que lugar da memória essas variáveis devem ser mantidas?”. A solução mais simples, dar a cada variável um endereço de memória absoluto, não funciona. O problema é que um procedimento pode chamar a si mesmo. Estudaremos esses procedimentos recursivos no Capítulo 5. Por enquanto, basta dizer que, se um procedimento for ativado – isto é, chamado – duas vezes, é impossível armaze- nar suas variáveis em localizações absolutas de memória porque a segunda chamada irá interferir com a primeira. Em vez disso, é usada uma estratégia diferente. Uma área da memória, denominada pilha, é reservada para variáveis, mas variáveis individuais não obtêm endereços absolutos nela. Em vez disso, um registrador, por exem- plo, LV, é preparado para apontar para a base das variáveis locais para o procedimento em questão. Na Figura 4.8(a), um procedimento A, que tem variáveis locais a1, a2 e a3, foi chamado, portanto, foi reservado armazena- mento para suas variáveis locais, começando na localização de memória apontada por LV. Outro registrador, SP, aponta para a palavra mais alta das variáveis locais de A. Se LV for 100 e as palavras tiverem 4 bytes, então SP será 108. ariáveis são referenciadas dando seu deslocamento (distância) em relação a LV. A estrutura de dados entre LV e SP (e incluindo ambas as palavras apontadas) é denominada quadro de variáveis locais de A. Figura 4.8 Utilizac a o de uma pilha para armazenar varia veis locais. (a) Enquanto A esta  ativo. (b) Apo s A chamar B. (c) Apo s B chamar C. (d) Apo s C e B retornarem e A chamar D. SP LV a3 a1 (a) 108 100 a2 104 SP LV a3 a1 (b) a2 b3 b4 b1 b2 a3 a1 (c) a2 b3 b4 LV c1 SP c2 b1 b2 LV a3 a1 (d) a2 d3 d4 SP d5 d1 d2 Agora, vamos considerar o que acontece se A chamar outro procedimento, B. Onde deveriam ser armaze- nadas as quatro variáveis locais de B (b1, b2, b3, b4)? Resposta: na pilha, em cima das variáveis de A, conforme mostra a Figura 4.8(b). Observe que LV foi ajustado pela chamada de procedimento para que aponte para as variáveis locais de B em vez das de A. As variáveis locais de B podem ser referenciadas dando seu deslocamento em relação a LV. De modo semelhante, se B chamar C, LV e SP são ajustados novamente para alocar espaço para as duas variáveis de C, como mostra a Figura 4.8(c). Quando C retorna, B torna-se ativo de novo e a pilha volta a ser ajustada para a Figura 4.8(b), de modo que LV agora aponta outra vez para as variáveis locais de B. Da mesma forma, quando B retorna, voltamos à situação da Figura 4.8(a). Sob todas as condições, LV aponta para a base do quadro da pilha para o procedimento ativo no momento em questão e SP aponta para o topo do quadro da pilha. Agora, suponha que A chama D, que tem cinco variáveis locais. Essa é a situação da Figura 4.8(d), na qual as variáveis locais de D usam a mesma memória que as de B usaram, bem como parte das de C. Com essa orga- nização, a memória só é alocada para procedimentos que estão ativos no momento em questão. Quando um procedimento retorna, a memória usada por suas variáveis locais é liberada. Pilhas têm outra utilização além de conter variáveis locais. Elas podem ser usadas para reter operandos durante o cálculo de uma expressão aritmética. Quando usada dessa maneira, a pilha é denominada pilha de operandos. Suponha, por exemplo, que, antes de chamar B, A tenha de calcular a1 = a2 + a3;
  • 222. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 203 Um modo de efetuar essa soma é passar a2 para a pilha, como ilustra a Figura 4.9(a). Nesse caso, SP foi incre- mentado pelo número de bytes em uma palavra, por exemplo, 4, e o primeiro operando foi armazenado no endereço agora apontado por SP. Em seguida, a3 é passada para a pilha, conforme mostra a Figura 4.9(b). (Como parte da notação, usaremos uma fonte Helvetica para todos os fragmentos de programa, como fizemos anteriormente. Também usaremos essa fonte para opcodes em linguagem de montagem e registradores de máquina, mas, em texto corrente, variáveis de programa e procedimentos serão dados em itálico. A diferença é que nomes de variáveis de programas e nomes de procedimento são escolhidos pelo usuário; nomes de opcodes e registradores vêm com a máquina.) Figura 4.9 Utilizac a o de uma pilha de operandos para efetuar um ca lculo aritme tico. LV a3 SP a2 a1 (a) a2 LV a3 a2 SP a3 a1 (b) a2 LV a3 SP a2 + a3 a1 (c) a2 LV SP a3 a2 + a3 (d) a2 Agora, o cálculo propriamente dito pode ser feito executando uma instrução que retira duas palavras da pilha, soma as duas e devolve o resultado para a pilha, conforme a Figura 4.9(c). Por fim, a palavra que está no topo pode ser retirada da pilha e armazenada de novo na variável local a1, como ilustrado na Figura 4.9(d). Os quadros de variáveis locais e as pilhas de operandos podem ser misturados. Por exemplo, ao calcular uma expressão como x2 + f(x), parte dela (por exemplo, x2 ) pode estar em uma pilha de operandos quando a função f é chamada. O resultado da função é deixado na pilha, em cima de x2 , de modo que a próxima instrução pode somá-la. ale a pena observar que, enquanto todas as máquinas usam uma pilha para armazenar variáveis locais, nem todas usam uma pilha de operandos como essa para efetuar aritmética. Na verdade, a maioria delas não usa, mas a JM e a JM trabalham assim, e é por isso que apresentamos aqui as operações com a pilha. amos estudá-las com mais detalhes no Capítulo 5. 4.2.2 Modelo de memo ria IJVM Agora, estamos prontos para estudar a arquitetura da JM. Em essência, ela consiste em uma memória que pode ser vista de dois modos: um arranjo de 4.294.967.296 bytes (4 GB) ou um arranjo de 1.073.741.824 pala- vras, cada uma consistindo em 4 bytes. Diferente da maioria das SAs, a Java irtual Machine (máquina virtual Java) não deixa nenhum endereço absoluto de memória diretamente visível no nível SA, mas há vários endereços implícitos que fornecem a base para um ponteiro. nstruções JM só podem acessar a memória indexando a partir desses ponteiros. Em qualquer instante, as seguintes áreas de memória são definidas: 1. O conjunto de constantes. Essa área não pode ser escrita por um programa JM e consiste em constan- tes, cadeias e ponteiros para outras áreas da memória que podem ser referenciadas. Ele é carregado quando o programa é trazido para a memória e não é alterado depois. Há um registrador implícito, CPP, que contém o endereço da primeira palavra do conjunto de constantes. 2. O quadro de variáveis locais. Para cada invocação de um método é alocada uma área para armazenar variáveis durante o tempo de vida da invocação, denominada quadro de variáveis locais. No início desse quadro estão os parâmetros (também denominados argumentos) com os quais o método foi invocado. O quadro de variáveis locais não inclui a pilha de operandos, que é separada. Contudo, por questões de eficiência, nossa implementação prefere executar a pilha de operandos logo acima do quadro de variáveis locais. Há um registrador implícito que contém o endereço da primeira localização
  • 223. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 204 do quadro de variáveis locais. Nós o denominaremos LV. Os parâmetros passados na chamada do método são armazenados no início do quadro de variáveis locais. 3. A pilha de operandos. É garantido que o quadro não exceda certo tamanho, calculado com antecedên- cia pelo compilador Java. O espaço da pilha de operandos é alocado diretamente acima do quadro de variáveis locais, como ilustrado na Figura 4.10. Em nossa implementação, é conveniente imaginar a pilha de operandos como parte do quadro de variáveis locais. De qualquer modo, há um registrador implícito que contém o endereço da palavra do topo da pilha. Note que, diferente do CPP e do LV, esse ponteiro, SP, muda durante a execução do método à medida que operandos são passados para a pilha ou retirados dela. 4. A área de método. Por fim, há uma região da memória que contém o programa, à qual nos referimos como a área de “texto” em um processo UN. Há um registrador implícito que contém o endereço da instrução a ser buscada em seguida. Esse ponteiro é denominado contador de programa (Program Counter) ou PC. Diferente das outras regiões da memória, a área de método é tratada como um vetor de bytes. Figura 4.10 As va rias partes da memo ria IJVM. SP LV PC CPP Conjunto de constantes Pilha 3 de operandos correntes Quadro 3 de variáveis locais correntes Quadro 2 de variáveis locais Quadro 1 de variáveis locais Área de método É preciso esclarecer uma questão em relação aos ponteiros. Os registradores CPP, LV e SP são todos pon- teiros para palavras, não para bytes, e são deslocados pelo número de palavras. Para o subconjunto de inteiros que escolhemos, todas as referências a itens no conjunto de constantes, o quadro de variáveis locais e as pilhas são palavras, e todos os deslocamentos usados para indexar esses quadros são deslocamentos de palavras. Por exemplo, LV, LV + 1 e LV + 2 se referem às primeiras três palavras do quadro de variáveis locais. Em comparação, LV, LV + 4 e LV + 8 se referem a palavras em intervalos de quatro palavras (16 bytes). Ao contrário, PC contém um endereço de byte, e uma adição ou subtração ao PC altera o endereço por um número de bytes, e não por um número de palavras. O endereçamento para PC é diferente dos outros e esse fato é aparente na porta de memória especial fornecida para PC na Mic-1. Lembre-se de que a largura dessa porta é de apenas 1 byte. ncrementar o PC por um fator de um e iniciar uma leitura resulta em uma busca pelo próximo byte. ncrementar o SP por um fator de um e iniciar uma leitura resulta em uma busca pela próxima palavra. 4.2.3 Conjunto de instruc o es da IJVM O conjunto de instruções da JM é mostrado na Figura 4.11. Cada instrução consiste em um opcode e às vezes um operando, tal como um deslocamento de memória ou uma constante. A primeira coluna dá a codificação hexadecimal da instrução. A segunda dá seu mnemônico em linguagem de montagem. A terceira dá uma breve descrição de seu efeito.
  • 224. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 205 Figura 4.11 Conjunto de instruc o es da IJVM. Os operandos byte, const e varnum sa o de 1 byte. Os operandos disp, index e offset sa o de 2 bytes. Hexa Mnemônico Significado 0x10 BIPUSH byte Carregue o byte para a pilha 0x59 DUP Copie a palavra do topo da pilha e passe-a para a pilha 0xA7 GOTO offset Desvio incondicional 0x60 IADD Retire duas palavras da pilha; carregue sua soma 0x7E IAND Retire duas palavras da pilha; carregue AND booleano 0x99 IFEQ offset Retire palavra da pilha e desvie se for zero 0x9B IFLT offset Retire palavra da pilha e desvie se for menor do que zero 0x9F IF_ICMPEQ offset Retire duas palavras da pilha; desvie se iguais 0x84 IINC varnum const Some uma constante a uma variável local 0x15 ILOAD varnum Carregue variável local para pilha 0xB6 INVOKEVIRTUAL disp Invoque um método 0x80 IOR Retire duas palavras da pilha; carregue OR booleano 0xAC IRETURN Retorne do método com valor inteiro 0x36 ISTORE varnum Retire palavra da pilha e armazene em variável local 0x64 ISUB Retire duas palavras da pilha; carregue sua diferença 0x13 LDC_W index Carregue constante do conjunto de constantes para pilha 0x00 NOP Não faça nada 0x57 POP Apague palavra no topo da pilha 0x5F SWAP Troque as duas palavras do topo da pilha uma pela outra 0xC4 WIDE Instrução prefixada; instrução seguinte tem um índice de 16 bits São fornecidas instruções para passar para a pilha uma palavra que pode vir de diversas fontes. Entre essas fontes estão o conjunto de constantes (LDC_W), o quadro de variáveis locais (ILOAD) e a própria instrução (BIPUSH). Uma variável também pode ser retirada da pilha e armazenada no quadro de variáveis locais (ISTORE). Duas operações aritméticas (IADD e ISUB), bem como duas operações lógicas booleanas (IAND e IOR), podem ser efetuadas usando as duas palavras de cima da pilha como operandos. Em todas as operações aritméticas e lógicas, duas palavras são retiradas da pilha e o resultado é devolvido a ela. São fornecidas quatro instruções de desvio, uma incondicional (GOTO) e três condicionais (IFEQ, IFLT e IF_ICMPEQ). Todas as instruções de ramificação, se tomadas, ajustam o valor de PC conforme o tamanho de seus deslocamentos (16 bits com sinal), que vem após o opcode na instrução. Esse deslocamento é adicionado ao endereço do opcode. Há também instruções JM para trocar as duas palavras do topo da pilha uma pela outra (SWAP), duplicando a palavra do topo (DUP) e retirando-a (POP). Algumas instruções têm vários formatos, o que permite uma forma abreviada para versões comumente usa- das. Na JM, incluímos dois dos vários mecanismos que a JM usa para fazer isso. Em um caso, ignoramos a forma abreviada em favor da mais geral. Em outro caso, mostramos como a instrução prefixada WIDE pode ser usada para modificar a instrução resultante. Por fim, há uma instrução (INVOKEVIRTUAL) para invocar (chamar) outro método e outra instrução (IRETURN) para sair dele e devolver o controle ao método que o invocou. Pela complexidade do mecanismo,
  • 225. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 206 simplificamos de leve a definição, possibilitando produzir um mecanismo direto para invocar uma chamada e um retorno. A restrição é que, diferente da Java, só permitimos que um método invoque outro existente dentro de seu próprio objeto. Essa restrição prejudica seriamente a orientação de objetos, mas nos permite apresentar um mecanismo muito mais simples, evitando o requisito de localizar o método dinamicamente. (Se você não estiver familiarizado com programação orientada a objeto, pode ignorar essa observação sem susto. O que fizemos foi levar Java de volta a uma linguagem não orientada a objeto, como C ou Pascal.) Em todos os computadores, exceto JM, o endereço do procedimento para chamar é determinado diretamente pela instrução CALL, portanto, nossa abordagem é, na verdade, o caso normal, e não a exceção. O mecanismo para invocar um método é o seguinte. Primeiro, o chamador passa para a pilha uma referência (ponteiro) ao objeto a ser chamado. (Essa referência não é necessária na JM, visto que nenhum outro objeto pode ser especificado, mas é mantida para preservar a consistência com a JM.) Na Figura 4.12(a), essa referência é indicada por OBJREF. Em seguida, o chamador passa os parâmetros do método para a pilha, nesse exemplo, Parâmetro 1, Parâmetro 2 e Parâmetro 3. Finalmente, INVOKEVIRTUAL é executada. A instrução INVOKEVIRTUAL inclui um deslocamento que indica a posição no conjunto de constantes que contêm o endereço de início dentro da área de método para o método que está sendo invocado. Contudo, embora o código do método resida na localização apontada por esse ponteiro, os primeiros 4 bytes na área de método contêm dados especiais. Os primeiros 2 bytes são interpretados como um inteiro de 16 bits que indica o número de parâmetros para o método (os parâmetros em si já foram passados para a pilha). Nessa contagem, OBJREF é contado como um parâmetro: parâmetro 0. Esse inteiro de 16 bits, junto com o valor de SP, fornece a localização de OBJREF. Note que LV aponta para OBJREF, e não para o primeiro parâmetro real. Para onde o LV aponta é uma escolha um tanto arbitrária. Os 2 bytes seguintes na área de método são interpretados como outro inteiro de 16 bits, que indica o tama- nho da área de variáveis locais para o método que está sendo chamado. sso é necessário porque uma nova pilha será estabelecida para o método, começando imediatamente acima do quadro de variáveis locais. Por fim, o quinto byte na área de método contém o primeiro opcode a ser executado. A sequência real que ocorre para INVOKEVIRTUAL é a seguinte, e está retratada na Figura 4.12. Os dois bytes de índice sem sinal que seguem o opcode são usados para construir um índice na tabela do conjunto de constantes (o primeiro byte é o byte de ordem alta). A instrução calcula o endereço da base do novo quadro de variáveis locais subtraindo o número de parâmetros do ponteiro da pilha e ajustando LV para apontar para OBJREF. Nesse local, sobrescrevendo OBJREF, a implementação guarda o endereço do local onde o antigo PC deve ser armazenado. Esse endereço é calculado adicionando o tamanho do quadro de variáveis locais (parâmetros + variáveis locais) ao endere- ço contido em LV. mediatamente acima do endereço onde o antigo PC deve ser armazenado está o endereço onde o antigo LV deve ser armazenado. Logo acima daquele endereço está o início da pilha para o procedimento que acabou de ser chamado. O SP é ajustado para apontar para o antigo LV, que é o endereço logo abaixo do primeiro local vazio na pilha. Lembre-se de que o SP sempre aponta para a palavra no topo da pilha. Se esta estiver vazia, ele aponta para o primeiro local abaixo do final, porque nossas pilhas crescem para cima, na direção de endereços mais altos. Em nossas figuras, as pilhas sempre crescem para cima, na direção dos endereços mais altos, no topo da página. A última operação necessária para efetuar INVOKEVIRTUAL é ajustar PC para apontar para o quinto byte no espaço de código do método. A instrução IRETURN inverte as operações da instrução INVOKEVIRTUAL, conforme mostra Figura 4.13. Ela libera o espaço usado pelo método que retorna. Também restaura a pilha a seu estado anterior, exceto que (1) a palavra OBJREF (agora sobrescrita) e todos os parâmetros foram retirados da pilha e (2) o valor retornado foi colocado no topo da pilha, no local antes ocupado por OBJREF. Para restaurar o antigo estado, a instrução IRETURN deve ser capaz de restaurar os ponteiros PC e LV para seus antigos valores. Ela faz isso acessando o ponteiro de ligação (que é a palavra identificada pelo ponteiro LV corrente). Lembre-se de que, nesse local, onde a OBJREF estava armazenada originalmente, a instrução INVOKEVIRTUAL armazenou o endereço contendo o PC antigo. Essa palavra e a palavra acima dela são recuperadas para restaurar PC e LV para seus valores antigos. O valor de retorno, que estava armazenado no topo da pilha do método que está encerrando, é copiado para o local onde a OBJREF estava armazenada, e SP é restaurado para apontar para esse local. Portanto, o controle é devolvido à instrução imediatamente após a instrução INVOKEVIRTUAL.
  • 226. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 207 Figura 4.12 (a) Memo ria antes de executar INVOKEVIRTUAL. (b) Apo s executa -la. Parâmetros passados Quadro de variáveis locais do chamador Pilha antes de INVOKEVIRTUAL Pilha após INVOKEVIRTUAL SP SP LV LV (a) (b) Base da pilha após INVOKEVIRTUAL Base da pilha antes de INVOKEVIRTUAL Parâmetro 3 Parâmetro 2 Parâmetro 1 OBJREF LV anterior PC anterior PC anterior Variáveis locais do chamador Parâmetro 2 Parâmetro 1 Ponteiro de ligação Variáveis locais do chamador Espaço para variáveis locais do chamador Parâmetro 2 Parâmetro 1 Ponteiro de ligação LV do chamador PC do chamador LV anterior Parâmetro 3 Parâmetro 2 Parâmetro 1 Ponteiro de ligação Figura 4.13 Memo ria antes de executar IRETURN. (b) Apo s executa -la. Frame da variável local do chamador Pilha antes de IRETURN Pilha após IRETURN SP SP LV LV (a) (b) Base da pilha antes de IRETURN Base da pilha após IRETURN Parâmetro 3 Parâmetro 2 Parâmetro 1 Ponteiro de ligação PV anterior PC anterior PC anterior Variáveis locais do chamador Variáveis locais do chamador Parâmetro 2 Parâmetro 1 LV anterior Valor de retorno PC anterior Ponteiro de ligação Variáveis locais do chamador Parâmetro 2 Parâmetro 1 Ponteiro de ligação LV anterior Valor de retorno
  • 227. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 208 Até aqui, nossa máquina não tem nenhuma instrução de entrada/saída. Tampouco vamos adicionar alguma. Ela não precisa dessas instruções, nem a Java irtual Machine, e a especificação oficial para a JM sequer men- ciona E/S. A teoria é que uma máquina que não efetua entrada nem saída é “segura”. (Na JM, leitura e escrita são realizadas por meio de uma chamada a métodos especiais de E/S.) 4.2.4 Compilando Java para a IJVM Agora, vamos ver como Java e JM estão relacionadas uma com a outra. Na Figura 4.14(a), mostramos um fragmento simples de código Java. Quando alimentado em um compilador Java, este provavelmente produziria a linguagem de montagem JM mostrada na Figura 4.14(b). Os números de linhas de 1 a 15 à esquerda do pro- grama de linguagem de montagem não fazem parte da saída do compilador; o mesmo vale para os comentários (que começam com //). Eles estão ali para ajudar a explicar a figura seguinte. Então, o assembler Java traduziria o programa de montagem para o programa binário mostrado na Figura 4.14(c). (Na verdade, o compilador Java faz sua própria montagem e produz o programa binário diretamente.) Para este exemplo, consideremos que i é a variável local 1, j é a variável local 2 e k é a variável local 3. Figura 4.14 (a) Fragmento em Java. (b) Linguagem de montagem Java correspondente. (c) Programa IJVM em hexadecimal. i = j + k; ILOAD j // i = j + k 0x15 0x02 if (i == 3) 2 ILOAD 0 k x15 0x03 k = 0; IADD 0x60 else 4 ISTORE i x36 0x01 j = j − 1; 5 ILOAD i // if (i == 3) 0x15 0x01 6 BIPUSH 3 x10 0x03 7 IF ICMPEQ L1 0x9F 0x00 0x0D 8 ILOAD j // j = j − 1 0x15 0x02 9 BIPUSH 1 x10 0x01 10 ISUB 0x64 11 ISTORE 0 j x36 0x02 12 GOTO L2 0xA7 0x00 0x07 13 L1: BIPUSH 0 // k = 0 0x10 0x00 14 ISTORE k x36 0x03 15 L2: (a) (b) (c) 1 3 0 0 0 0 O código compilado é direto. Primeiro, j e k são passadas para a pilha, somadas e o resultado é armazenado em i. Então, i e a constante 3 são passadas para a pilha e comparadas. Se forem iguais, é tomado um desvio para L1, onde k é ajustada para 0. Se forem diferentes, a comparação falha e o código logo após IF_ICMPEQ é execu- tado. Feito isso, ele desvia para L2, onde as partes then e else se fundem. A pilha de operandos para o programa JM da Figura 4.14(b) é mostrada na Figura 4.15. Antes de o código começar a executar, ela está vazia, o que é indicado pela linha horizontal acima do 0. Após a primeira ILOAD, j está na pilha, como indicado por j no retângulo acima de 1 (o que significa que a instrução 1 foi executada). Depois da segunda ILOAD, duas palavras estão na pilha, como mostrado acima de 2. Após a IADD, há somente uma palavra na pilha, que contém a soma j + k. Quando a palavra do topo é retirada e armazenada em i, a pilha está vazia, como mostrado acima do 4. A instrução 5 (ILOAD) inicia a declaração if passando i para a pilha (em 5). Em seguida, vem a constante 3 (em 6). Após a comparação, a pilha está novamente vazia (7). A instrução 8 é o início da parte else do fragmento de programa Java. A parte else continua até a instrução 12, quando então desvia para a parte then e vai para o rótulo L2.
  • 228. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 209 Figura 4.15 Pilha apo s cada instruc a o da Figura 4.14(b). j 2 j + k 3 j 1 0 k i 6 7 3 4 i 5 j – 1 10 11 j 1 j 9 8 14 15 12 0 13 4.3 Exemplo de implementac a o Agora que já especificamos em detalhes a micro e a macroarquitetura, resta a questão da implementação. Em outras palavras, como é um programa que está rodando na primeira e interpretando a última, e como ele funcio- na? Antes de podermos responder a essas perguntas, devemos considerar com cuidado a notação que usaremos para descrever a implementação. 4.3.1 Microinstruc o es e notac a o Em princípio, poderíamos descrever o armazenamento de controle em linguagem binária, 36 bits por pala- vra. Mas, em linguagens de programação convencionais, é um grande benefício introduzir uma notação que transmita a essência das questões que precisamos tratar e, ao mesmo tempo, oculte os detalhes que podem ser ignorados ou que podem ser mais bem tratados automaticamente. Nesse caso, é importante perceber que a lingua- gem que escolhemos pretende ilustrar os conceitos, e não facilitar projetos eficientes. Se esse fosse nosso objetivo, usaríamos uma notação diferente para maximizar a flexibilidade disponível para o projetista. Um aspecto em que essa questão é importante é a escolha de endereços. Uma vez que a memória não é ordenada logicamente, não há nenhuma “próxima instrução” natural a ser subentendida quando especificamos uma sequência de operações. Grande parte do poder dessa organização de controle deriva da capacidade do projetista [ou do montador (assem- bler)] de selecionar endereços com eficiência. Portanto, começamos introduzindo uma linguagem simbólica simples que dá uma descrição completa de cada operação sem explicar completamente como todos os endereços poderiam ter sido determinados. Nossa notação especifica todas as atividades que ocorrem num único ciclo de clock em uma única linha. Em teoria, poderíamos usar uma linguagem de alto nível para descrever as operações. Contudo, o controle ciclo por ciclo é muito importante porque dá oportunidade de realizar várias operações ao mesmo tempo e é necessário que possamos analisar cada um para entender e verificar as operações. Se a meta for uma execução rápida e eficiente (se os outros aspectos forem iguais, rápido e eficiente é sempre melhor que lento e ineficiente), então, cada ciclo conta. Em uma implementação real, há muitos truques sutis ocultos no programa, que usam sequências ou ope- rações obscuras para economizar um único ciclo que seja. Há uma grande compensação por economizar ciclos: uma instrução de quatro ciclos que pode ser reduzida em dois agora será executada com uma velocidade duas vezes maior – e essa aceleração é obtida toda vez que executamos a instrução. Uma abordagem possível é simplesmente fazer uma lista dos sinais que deveriam ser ativados a cada ciclo de clock. Suponha que, em determinado ciclo, queremos incrementar o valor de SP. Também queremos iniciar uma operação de leitura e queremos que a próxima instrução seja a que reside no local 122 do armazenamento de controle. Poderíamos escrever ReadRegister = SP, ULA = INC, WSP, Read, NEXT_ADDRESS = 122 onde WSP significa “escreva no registrador SP”. Essa notação é completa, mas difícil de entender. Em vez disso, combinaremos as operações de modo natural e intuitivo para captar o efeito daquilo que está acontecendo:
  • 229. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 210 SP = SP + 1; rd amos dar à nossa Microlinguagem Assembly de alto nível o nome “MAL” (palavra de raiz latina que significa “doente”, o que com certeza você ficará se tiver de escrever muito código utilizando essa linguagem). A MAL é projetada para refletir as características da microarquitetura. Durante cada ciclo, qualquer um dos registradores pode ser escrito, mas o normal é que somente um o seja. Apenas um registrador pode ser copiado para o lado B da ULA. No lado A, as opções são +1, 0, –1 e o registrador H. Assim, podemos usar uma declaração de atribuição simples, como em Java, para indicar a operação a ser executada. Por exemplo, para copiar algo de SP para MDR, podemos dizer MDR = SP Para indicar a utilização das funções ULA, exceto passar pelo barramento B, podemos escrever, por exemplo, MDR = H + SP que adiciona o conteúdo do registrador H a SP e escreve o resultado no MDR. O operador + é comutativo – o que significa que a ordem dos operandos não importa –, portanto, a declaração anterior também pode ser escrita como MDR = SP + H e gerar a mesma microinstrução de 36 bits, ainda que, em termos estritos, H deve ser o operando esquerdo da ULA. Temos de tomar o cuidado de usar somente operações válidas. As operações válidas mais importantes são mostradas na Figura 4.16, na qual SOURCE pode ser qualquer um dentre MDR, PC, MBR, MBRU, SP, LV, CPP, TOS ou OPC (MBRU implica a versão sem sinal de MBR). Todos esses registradores podem agir como fontes para a ULA no barramento B. De modo semelhante, DEST pode ser qualquer um dentre MAR, MDR, PC, SP, LV, CPP, TOS, OPC ou H; todos eles são destinos possíveis para a saída da ULA no barramento C. Esse formato pode ser enganoso, pois muitas declarações aparentemente razoáveis são ilegais. Por exemplo, MDR = SP + MDR parece perfeitamente razoável, mas não há nenhum modo de executá-la em um ciclo no caminho de dados da Figura 4.6. Essa restrição existe porque, para uma adição (exceto um incremento ou decremento), um dos operandos tem de ser o registrador H. Da mesma forma, H = H – MDR poderia ser útil, mas também ela é impossível porque a única fonte possível de um subtraendo – valor que está sendo subtraído – é o registrador H. Cabe ao montador rejeitar declarações que pareçam válidas, mas que, na verdade, são ilegais. Ampliamos a notação para permitir múltiplas atribuições pela utilização de múltiplos sinais de igual. Por exem- plo, adicionar 1 a SP e armazená-lo de volta em SP, bem como escrevê-lo em MDR, pode ser conseguido por SP = MDR = SP + 1 Para indicar leituras e escritas de memória de palavras de dados de 4 bytes, basta acrescentar rd e wr à microinstrução. Buscar um byte pela porta de 1 byte é indicado por fetch. Atribuições e operações de memória podem ocorrer no mesmo ciclo, o que é indicado escrevendo-as na mesma linha. Para evitar qualquer confusão, vamos repetir que a Mic-1 tem dois modos de acessar a memória. Leituras e escritas de palavras de dados de 4 bytes usam MAR/MDR e são indicadas nas microinstruções por rd e wr, respec- tivamente. Leituras de opcodes de 1 byte a partir da sequência de instruções usam PC/MBR e são indicadas por fetch nas microinstruções. Ambos os tipos de operações de memória podem ocorrer simultaneamente. Contudo, o mesmo registrador não pode receber um valor da memória e o caminho de dados no mesmo ciclo. Considere o código MAR = SP; rd MDR = H O efeito da primeira microinstrução é atribuir um valor da memória a MDR no final da segunda microinstru- ção. Contudo, esta também atribui um valor a MDR ao mesmo tempo. Essas duas atribuições estão em conflito e não são permitidas porque os resultados são indefinidos.
  • 230. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 211 Figura 4.16 Todas as operac o es permitidas. Qualquer uma das operac o es anteriores pode ser estendida somando << 8” a elas para des- locar o resultado para a esquerda por 1 byte. Por exemplo, uma operac a o comum e  H = MBR << 8. DEST = H DEST = SOURCE DEST = H DEST = SOURCE DEST = H + SOURCE DEST = H + SOURCE + 1 DEST = H + 1 DEST = SOURCE + 1 DEST = SOURCE – H DEST = SOURCE – 1 DEST = –H DEST = H AND SOURCE DEST = H OR SOURCE DEST = 0 DEST = 1 DEST = –1 Lembre-se de que cada microinstrução deve fornecer explicitamente o endereço da próxima a ser executada. Todavia, é comum ocorrer que uma microinstrução seja chamada somente por uma outra, a saber, por aquela que está na linha imediatamente acima dela. Para facilitar o trabalho do microprogramador, o microassembler atribui um endereço a cada microinstrução, não necessariamente consecutivas no armazenamento de controle, e preenche o próximo campo NEXT_ADDRESS de modo que microinstruções escritas em linhas consecutivas são executadas consecutivamente. Todavia, às vezes o microprogramador quer desviar, condicional ou incondicionalmente. A notação para desvios incondicionais é fácil: goto label e pode ser incluída em qualquer microinstrução para nomear explicitamente sua sucessora. Por exemplo, a maio- ria das sequências de microinstrução termina com um retorno à primeira instrução do laço principal, portanto, a última instrução em cada uma dessas sequências normalmente inclui goto Main1 Note que o caminho de dados está disponível para operações normais mesmo durante a microinstrução que contém um goto. Afinal, toda microinstrução individual contém um campo NEXT_ADDRESS. A tarefa de goto é instruir o microassembler a colocar um valor específico nesse campo em vez de no endereço onde ele decidiu colocar a microinstrução na linha seguinte. Em princípio, toda linha deveria ter uma declaração goto; apenas como uma conveniência para o microprogramador, quando o endereço visado for a próxima linha, ele pode ser omitido. Para desvios condicionais, precisamos de uma notação diferente. Lembre-se de que JAMN e JAMZ usam os bits N e Z, que são ajustados com base na saída da ULA. Às vezes, é preciso testar um registrador para ver se ele é zero, por exemplo. Um modo de fazer isso seria passá-lo pela ULA e armazená-lo em si mesmo. Escrever
  • 231. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 212 TOS = TOS parece peculiar, embora exerça sua função (ajustar o flip-flop Z com base no TOS). Contudo, para que os micro- programas pareçam melhores, agora estendemos MAL adicionando dois registradores imaginários, N e Z, aos quais se podem designar atribuições. Por exemplo, Z = TOS passa TOS pela ULA, ajustando assim os flip-flops Z (e N), mas não faz um armazenamento em qualquer registra- dor. Usar Z ou N como um destino equivale a dizer ao microassembler que ajuste todos os bits no campo C da Figura 4.5 para 0. O caminho de dados executa um ciclo normal, com todas as operações normais permitidas, mas nenhum registrador é escrito. Note que não importa se o destino é N ou Z; a microinstrução gerada pelo micro- assembler é idêntica. Programadores que escolhem intencionalmente a forma “errada” deveriam, como castigo, ser obrigados a trabalhar em um BM PC original de 4,77 MHz durante uma semana. A sintaxe para dizer ao microassembler que ajuste o bit JAMZ é if (Z) goto L1; else goto L2 Uma vez que o hardware requer que os 8 bits de ordem baixa desses dois endereços sejam idênticos, cabe ao microassembler designá-los a endereços com essa propriedade. Por outro lado, visto que L2 pode estar em qualquer lugar nas 256 palavras que estão mais embaixo no armazenamento de controle, o microassembler tem bastante liberdade para achar um par disponível. Normalmente, essas duas declarações serão combinadas; por exemplo: Z = TOS; if (Z) goto L1; else goto L2 O efeito dessa declaração é que MAL gera uma microinstrução na qual TOS é passada pela ULA (mas não é armazenada em lugar algum) de modo que seu valor ajusta o bit Z. Logo após Z ser carregado a partir do bit de condição da ULA, ele passa por uma operação OR com o bit de ordem alta do MPC, forçando o endereço da próxima microinstrução a ser buscado em L2 ou L1 (que deve ser exatamente 256 mais do que L2). O MPC estará estável e pronto a ser utilizado para buscar a próxima microinstrução. Por fim, precisamos de uma notação para usar o bit JMPC. A notação que usaremos será goto (MBR OR value) Essa sintaxe diz ao microassembler para usar value para NEXT_ADDRESS e ajustar o bit JMPC de modo que MBR e NEXT_ADDRESS sejam combinados por uma operação OR, e o resultado, armazenado em MPC. Se value for 0, que é o caso normal, basta escrever goto (MBR) Note que somente os 8 bits de ordem baixa de MBR são ligados ao MPC (veja a Figura 4.6), portanto, a questão da extensão de sinal (isto é, MBR versus MBRU) não surge aqui. Além disso, note que o MBR disponível no final do ciclo em questão é o que é utilizado. Uma busca iniciada nessa microinstrução está muito atrasada para afetar a escolha da próxima microinstrução. 4.3.2 Implementac a o de IJVM que usa a Mic-1 Chegamos enfim ao ponto em que podemos juntar todas as partes. A Figura 4.17 é o microprograma que executa em Mic-1 e interpreta a JM. É um programa surpreendentemente curto – somente 112 microinstruções no total. São dadas três colunas para cada microinstrução: o rótulo simbólico, o microcódigo propriamente dito e um comentário. Note que microinstruções consecutivas não precisam ser localizadas em endereços consecutivos no armazenamento de controle, como já havíamos comentado.
  • 232. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 213 Figura 4.17 Microprograma para a Mic-1. Rótulo Operações Comentários Main1 PC = PC + 1; fetch;1 goto (MBR) MBR contém opcode; obtenha o próximo byte; despache nop1 goto Main1 Não faça nada iadd1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha iadd2 H = TOS H = topo da pilha iadd3 MDR = TOS = MDR + H; wr; goto Main1 Some as duas palavras do topo; escreva para o topo da pilha isub1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha isub2 H = TOS H = topo da pilha isub3 MDR = TOS = MDR – H; wr; goto Main1 Efetue subtração; escreva para topo da pilha iand1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha iand2 H = TOS H = topo da pilha iand3 MDR = TOS = MDR AND H; wr; goto Main1 Faça AND; escreva para novo topo da pilha ior1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha ior2 H = TOS H = topo da pilha ior3 MDR = TOS = MDR OR H; wr; goto Main1 Faça OR; escreva para novo topo da pilha dup1 MAR = SP = SP + 1 Incremente SP e copie para MAR dup2 MDR = TOS; wr; goto Main1 Escreva nova palavra da pilha pop1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha pop2 Espere nova TOS ser lida da memória pop3 TOS = MDR; goto Main1 Copie nova palavra para TOS swap1 MAR = SP – 1; rd Ajuste MAR para SP – 1; leia 2a palavra da pilha swap2 MAR = SP Ajuste MAR para palavra do topo swap3 H = MDR; wr Salve TOS em H; escreva 2a palavra para topo da pilha swap4 MDR = TOS Copie TOS antigo para MDR swap5 MAR = SP – 1; wr Ajuste MAR para SP – 1; escreva como 2a palavra na pilha swap6 TOS = H; goto Main1 Atualize TOS bipush1 SP = MAR = SP + 1 MBR = o byte para passar para a pilha bipush2 PC = PC + 1; fetch Incremente PC, busque próximo opcode bipush3 MDR = TOS = MBR; wr; goto Main1 Estenda sinal da constante e passe para a pilha iload1 H = LV MBR contém índice; copie LV para H iload2 MAR = MBRU + H; rd MAR = endereço de variável local para passar para pilha iload3 MAR = SP = SP + 1 SP aponta para novo topo da pilha; prepare escrita iload4 PC = PC + 1; fetch; wr Incremente PC; obtenha próximo opcode; escreva topo da pilha iload5 TOS = MDR; goto Main1 Atualize TOS 1 N.R.: O termo fetch” indica a leitura de um byte da área de programa.
  • 233. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 214 Rótulo Operações Comentários istore1 H = LV MBR contém índice; copie LV para H istore2 MAR = MBRU + H MAR = endereço de variável local onde armazenar istore3 MDR = TOS; wr Copie TOS para MDR; escreva palavra istore4 SP = MAR = SP – 1; rd Leia a palavra seguinte à do topo da pilha istore5 PC = PC + 1; fetch Incremente PC; busque próximo opcode istore6 TOS = MDR; goto Main1 Atualize TOS wide1 PC = PC + 1; fetch Busque byte de operando ou próximo opcode wide2 goto (MBR OR 0x100) Ramificação multivias com bit alto ajustado wide_iload1 PC = PC + 1; fetch MBR contém 1o byte de índice; busque 2o wide_iload2 H = MBRU << 8 H = 1o byte de índice deslocado 8 bits para esquerda wide_iload3 H = MBRU OR H H = índice de 16 bits de variável local wide_iload4 MAR = LV + H; rd; goto iload3 MAR = endereço de variável local a carregar wide_istore1 PC = PC + 1; fetch MBR contém 1o byte de índice; busque 2o wide_istore2 H = MBRU << 8 H = 1o byte de índice deslocado 8 bits para esquerda wide_istore3 H = MBRU OR H H = índice de 16 bits de variável local wide_istore4 MAR = LV + H; goto istore3 MAR = endereço de variável local no qual armazenar ldc_w1 PC = PC + 1; fetch MBR contém 1o byte de índice; busque 2o ldc_w2 H = MBRU << 8 H = 1o byte de índice << 8 ldc_w3 H = MBRU OR H H = índice de 16 bits dentro do conjunto de constantes ldc_w4 MAR = H + CPP; rd; goto iload3 MAR = endereço de constante no conjunto de constantes iinc1 H = LV MBR contém índice; copie LV para H iinc2 MAR = MBRU + H; rd Copie LV + índice para MAR; leia variável iinc3 PC = PC + 1; fetch Busque constante iinc4 H = MDR Copie variável para H iinc5 PC = PC + 1; fetch Busque próximo opcode iinc6 MDR = MBR + H; wr; goto Main1 Ponha soma em MDR; atualize variável goto1 OPC = PC – 1 Salve endereço de opcode goto2 PC = PC + 1; fetch MBR = 1o byte de deslocamento; busque 2o byte goto3 H = MBR << 8 Desloque e salve primeiro byte com sinal em H goto4 H = MBRU OR H H = deslocamento de desvio de 16 bits goto5 PC = OPC + H; fetch Adicione deslocamento a OPC goto6 goto Main1 Espere para buscar o próximo opcode iflt1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha iflt2 OPC = TOS Salve TOS em OPC temporariamente iflt3 TOS = MDR Ponha novo topo da pilha em TOS iflt4 N = OPC; if (N) goto T; else goto F Desvio de bit N
  • 234. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 215 Rótulo Operações Comentários ifeq1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha ifeq2 OPC = TOS Salve TOS em OPC temporariamente ifeq3 TOS = MDR Ponha novo topo da pilha em TOS ifeq4 Z = OPC; if (Z) goto T; else goto F Desvio de bit Z if_icmpeq1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha if_icmpeq2 MAR = SP = SP – 1 Ajuste MAR para ler novo topo da pilha if_icmpeq3 H = MDR; rd Copie segunda palavra da pilha para H if_icmpeq4 OPC = TOS Salve TOS em OPC temporariamente if_icmpeq5 TOS = MDR Ponha novo topo da pilha em TOS if_icmpeq6 Z = OPC – H; if (Z) goto T; else goto F Se 2 palavras do topo da pilha forem iguais, vá para T, senão vá para F T OPC = PC – 1; goto goto2 O mesmo que goto1; necessário para endereço de destino F PC = PC + 1 Salte primeiro byte de deslocamento F2 PC = PC + 1; fetch PC agora aponta para próximo opcode F3 goto Main1 Espere por busca de opcode invokevirtual1 PC = PC + 1; fetch MBR = byte de índice 1; incremente PC, obtenha 2o byte invokevirtual2 H = MBRU << 8 Desloque e salve primeiro byte em H invokevirtual3 H = MBRU OR H H = deslocamento de ponteiro de método em relação a CPP invokevirtual4 MAR = CPP + H; rd Obtenha ponteiro para método da área CPP invokevirtual5 OPC = PC + 1 Salve PC de retorno em OPC temporariamente invokevirtual6 PC = MDR; fetch PC aponta para novo método; obtenha contagem de parâ- metros invokevirtual7 PC = PC + 1; fetch Busque 2o byte da contagem de parâmetro invokevirtual8 H = MBRU << 8 Desloque e salve primeiro byte em H invokevirtual9 H = MBRU OR H H = número de parâmetros invokevirtual10 PC = PC + 1; fetch Busque 1o byte de # locais invokevirtual11 TOS = SP – H TOS = endereço de OBJREF – 1 invokevirtual12 TOS = MAR = TOS + 1 TOS = endereço de OBJREF (novo LV) invokevirtual13 PC = PC + 1; fetch Busque 2o byte de # locais invokevirtual14 H = MBRU << 8 Desloque e salve primeiro byte em H invokevirtual15 H = MBRU OR H H = # locais invokevirtual16 MDR = SP + H + 1; wr Sobrescreva OBJREF com ponteiro de enlace invokevirtual17 MAR = SP = MDR Ajuste SP, MAR para localização para conter PC antigo invokevirtual18 MDR = OPC; wr Salve PC antigo acima das variáveis locais invokevirtual19 MAR = SP = SP + 1 SP aponta para localização para conter LV antigo invokevirtual20 MDR = LV; wr Salve LV antigo acima do PC salvo invokevirtual21 PC = PC + 1; fetch Busque primeiro opcode do novo método
  • 235. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 216 Rótulo Operações Comentários invokevirtual22 LV = TOS; goto Main1 Ajuste LV para apontar para quadro LV ireturn1 MAR = SP = LV; rd Reajuste SP, MAR para obter ponteiro de ligação ireturn2 Espere por leitura ireturn3 LV = MAR = MDR; rd Ajuste LV para ponteiro de ligação; obtenha PC antigo ireturn4 MAR = LV + 1 Ajuste MAR para ler LV antigo ireturn5 PC = MDR; rd; fetch Restaure PC; busque próximo opcode ireturn6 MAR = SP Ajuste MAR para escrever TOS ireturn7 LV = MDR Restaure LV ireturn8 MDR = TOS; wr; goto Main1 Salve valor de retorno no topo de pilha original A essa altura a escolha de nomes para a maioria dos registradores na Figura 4.1 já deve ser óbvia: CPP, LV e SP são usados para conter os ponteiros para o conjunto de constantes, variáveis locais e o topo da pilha, enquanto PC contém o endereço do próximo byte a ser buscado no fluxo de instruções. MBR é um registrador de 1 byte que contém os bytes da sequência de instrução, à medida que eles chegam da memória para ser interpretados. TOS e OPC são registradores extras. Sua utilização é descrita a seguir. Em certas ocasiões, é garantido que cada um desses registradores contenha certo valor, mas cada um pode ser usado como um registrador transitório, se necessário. No início e no final de cada instrução, TOS contém o valor do endereço de memória apontado por SP, a palavra que está no topo da pilha. Esse valor é redundante, uma vez que sempre pode ser lido da memória, mas tê-lo em um registrador muitas vezes economiza uma referência à memória. Para algumas poucas instruções, manter TOS significa mais operações de memória. Por exemplo, a instrução POP joga fora a palavra do topo e, portanto, deve buscar a nova palavra do topo da pilha na memória e passá-la para TOS. O registrador OPC é um registrador temporário . Ele não tem nenhuma utilização predeterminada. É usado, por exemplo, para salvar o endereço do opcode para uma instrução de desvio enquanto o PC é incrementado para acessar parâmetros. Também é usado como um registrador temporário nas instruções de desvio condicional da JM. Como todos os interpretadores, o microprograma da Figura 4.17 tem um laço principal que busca, decodi- fica e executa instruções do programa que está sendo interpretado, nesse caso, instruções JM. Seu laço prin- cipal começa na linha de rótulo Main1. nicia com a invariante de que o PC tenha sido previamente carregado com um endereço de um local da memória que contém um opcode. Além do mais, esse opcode já foi trazido para dentro do MBR. Contudo, observe que isso implica que, quando voltarmos a esse local, devemos assegurar que o PC foi atualizado para apontar o próximo opcode a ser interpretado e o próprio byte do opcode já foi trazido para dentro do MBR. Essa sequência inicial de instruções é executada no início de cada instrução, então, é importante que ela seja a mais curta possível. Por meio de um projeto muito cuidadoso do hardware e do software da Mic-1, conseguimos reduzir o laço principal a uma única microinstrução. Uma vez iniciada a máquina, toda vez que essa microins- trução for executada, o opcode JM a executar já está presente no MBR. A tarefa dessa microinstrução é desviar para o microcódigo para executar a instrução JM e também iniciar a busca do byte após o opcode, que pode ser um byte de operando ou o próximo opcode. Agora podemos revelar a razão real por que cada microinstrução nomeia sua sucessora em vez de executá-las em sequência. Todos os endereços do armazenamento de controle correspondentes a opcodes devem ser reserva- dos para a primeira palavra do interpretador de instrução correspondente. Assim, pela Figura 4.11, vemos que o código que interpreta POP começa em 0x57 e o código que interpreta DUP começa em 0x59. (Como o MAL consegue colocar POP em 0x57? Possivelmente, há um arquivo em algum lugar que o informa.)
  • 236. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 217 nfelizmente, o código para POP tem três microinstruções de comprimento, portanto, se colocado em palavras consecutivas, interferiria com o início de DUP. Uma vez que todos os endereços do armazenamento de controle correspondentes a opcodes são de fato reservados, as microinstruções, exceto a inicial em cada sequência, devem ser colocadas nos espaços entre os endereços reservados. Por essa razão, há muitos saltos para lá e para cá; dessa maneira, ter um microdesvio explícito – microinstrução que desvia – a cada poucas microinstruções para saltar de buraco em buraco seria muito desperdício. Para ver como o interpretador trabalha, vamos considerar, por exemplo, que MBR contém o valor 0x60, isto é, o opcode para IADD (veja a Figura 4.11). No laço principal de uma só microinstrução realizamos três coisas: 1. ncrementamos o PC, que fica contendo o endereço do primeiro byte após o opcode. 2. niciamos uma busca do próximo byte para MBR. Mais cedo ou mais tarde, esse byte sempre será necessário, seja como um operando para a instrução JM corrente, seja como o próximo opcode (como no caso da instrução IADD, que não tem bytes de operando). 3. Executamos um desvio multivias até o endereço contido em MBR no início de Main1. Esse endereço é igual ao valor numérico do opcode que está sendo executado no momento em questão. Ele foi colocado ali pela microinstrução anterior. Não se esqueça de observar que o valor que está sendo buscado nessa microinstrução não desempenha nenhum papel no desvio multivias. A busca do próximo byte é iniciada aqui, portanto, ele estará disponível no início da terceira microinstrução. Ele pode ser ou não necessário nesse momento, porém, mais cedo ou mais tarde, será necessário. Portanto, em todo caso, iniciar a busca agora não poderá fazer mal algum. Se acaso os bytes em MBR forem todos zeros, o opcode para uma instrução NOP, a microinstrução seguinte, é a que tem rótulo nop1, buscada da localização 0. Como essa instrução nada faz, ela apenas desvia de volta ao início do laço principal, onde a sequência é repetida, mas com um novo opcode buscado em MBR. Mais uma vez destacamos que as microinstruções na Figura 4.17 não são consecutivas na memória e que Main1 não está no endereço 0 do armazenamento de controle (porque nop1 tem de estar no endereço 0). Cabe ao microassembler colocar cada microinstrução em um endereço adequado e ligá-las em sequências curtas usando o campo NEXT_ADDRESS. Cada sequência começa no endereço correspondente ao valor numérico do opcode JM que interpreta (por exemplo, POP começa em 0x57), mas o resto da sequência pode estar em qualquer lugar do armazenamento de controle, e não necessariamente no endereço consecutivo. Agora, considere a instrução JM IADD. A microinstrução para a qual o laço principal desviou é a que tem o rótulo iadd1. Essa instrução inicia o trabalho específico de IADD: 1. O TOS já está presente, mas a palavra anterior à que está no topo da pilha deve ser buscada na memória. 2. O TOS deve ser adicionado à palavra anterior à do topo da pilha que foi buscada na memória. 3. O resultado, que deve ser passado para a pilha, deve ser armazenado de volta na memória, bem como armazenado no registrador TOS. Para buscar o operando na memória, é necessário decrementar o ponteiro da pilha e escrevê-lo em MAR. Note que, por conveniência, esse endereço também é o endereço que será usado para a escrita subsequente. Além do mais, visto que tal localização será o novo topo da pilha, esse valor deve ser atribuído a SP. Portanto, uma única operação pode determinar o novo valor de SP e MAR, decrementar SP e escrevê-lo em ambos os registradores. Essas coisas são realizadas no primeiro ciclo, iadd1, e a operação de leitura é iniciada. Além disso, MPC obtém o valor do campo NEXT_ADDRESS de iadd1, que é o endereço de iadd2, onde quer que ele possa estar. Então, iadd2 é lida do armazenamento de controle. Durante o segundo ciclo, enquanto espera o operando ser lido da memória, copiamos a palavra do topo da pilha do TOS para H, onde ela ficará disponível para a adição quando a leitura for concluída.
  • 237. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 218 No início do terceiro ciclo, iadd3, MDR contém o somando buscado na memória. Neste ciclo, ele é adicionado ao conteúdo de H, e o resultado é armazenado de volta em MDR, bem como em TOS. Também é iniciada uma operação de escrita, armazenando a nova palavra de topo de pilha de volta à memória. Neste ciclo, o goto tem o efeito de atri- buir o endereço de Main1 ao MPC, o que nos leva de volta ao ponto de partida para a execução da próxima instrução. Se o opcode JM subsequente, agora contido em MBR, for 0x64 (ISUB), quase exatamente a mesma sequên- cia de eventos ocorre de novo. Após a execução de Main1, o controle é transferido para a microinstrução em 0x64 (isub1). Essa microinstrução é seguida por isub2 e isub3, e então novamente Main1. A única diferença entre essa sequência e a anterior é que em isub3, o conteúdo de H é subtraído de MDR em vez de somado a ele. A interpretação de IAND é quase idêntica à de IADD e ISUB, exceto que as duas palavras do topo da pilha pas- sam por uma operação AND bit a bit em vez de serem somadas ou subtraídas. Algo semelhante acontece para IOR. Se o opcode JC for DUP, POP ou SWAP, a pilha deve ser ajustada. A instrução DUP apenas duplica a pala- vra do topo da pilha. Uma vez que o valor dessa palavra já está armazenado em TOS, a operação é tão simples quanto incrementar SP para apontar para a nova localização e armazenar TOS naquela localização. A instrução POP é quase tão simples, apenas decrementa SP para descartar a palavra que está no topo da pilha. Contudo, para manter a palavra do topo em TOS, agora é necessário ler a nova palavra do topo na memória e escrevê-la em TOS. Por fim, a instrução SWAP envolve permutar entre si os valores em duas localizações de memória: as duas palavras do topo da pilha. A operação é facilitada de certa forma pelo fato de o TOS já conter um desses valores, portanto, ele não precisa ser lido da memória. Essa instrução será discutida com mais detalhes mais adiante. A instrução BIPUSH é um pouco mais complicada porque o opcode é seguido por um único byte, conforme mostra a Figura 4.18. O byte deve ser interpretado como um inteiro com sinal. Esse byte, que já foi buscado para MBR em Main1, deve ser estendido em sinal para 32 bits e passado para o topo da pilha. Portanto, essa sequência deve estender em sinal o byte em MBR para 32 bits e copiá-lo para MDR. Por fim, SP é incrementado e copiado para MAR, permitindo que o operando seja escrito para o topo da pilha. No caminho, esse operando também deve ser copiado para o TOS. Além disso, antes de retornar para o programa principal, note que o PC deve ser incrementado de modo que o próximo opcode estará disponível em Main1. Figura 4.18 Formato da instruc a o BIPUSH. BYTE BIPUSH (0x10) Em seguida, considere a instrução ILOAD. Ela também tem um byte após o opcode, como ilustra a Figura 4.19(a), mas esse byte é um índice (sem sinal) para identificar a palavra no espaço de variáveis locais que será passada para a pilha. Uma vez que há somente 1 byte, apenas 28 = 256 palavras podem ser distinguidas, a saber, as primeiras 256 palavras no espaço de variáveis locais. A instrução ILOAD requer uma leitura (para obter a palavra), bem como uma escrita (para passá-la para o topo da pilha). Para determinar o endereço para leitura, entretanto, o deslocamento, contido em MBR, deve ser adicionado ao conteúdo de LV. Uma vez que ambos, MBR e LV, só podem ser acessados pelo barramento B, LV primeiro é copiado para H (em iload1), então MBR é adicionado. O resultado dessa adição é copiado para MAR e uma leitura é iniciada (em iload2). Figura 4.19 (a) ILOAD com um  ndice de 1 byte. (b) WIDE ILOAD com um  ndice de 2 bytes. INDEX BYTE 1 INDEX BYTE 2 WIDE (0xC4) ILOAD (0x15) ILOAD (0x15) INDEX (a) (b)
  • 238. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 219 Contudo, a utilização de MBR como um índice é um pouco diferente do que em BIPUSH, onde ele era estendido em sinal. No caso de um índice, o deslocamento é sempre positivo, portanto, o deslocamento do byte deve ser interpretado como um inteiro sem sinal, diferente de BIPUSH, onde era interpretado como um inteiro de 8 bits com sinal. A interface de MBR ao barramento B é projetada para possibilitar ambas as operações. No caso de BIPUSH (inteiro de 8 bits com sinal), a operação adequada é a extensão de sinal, isto é, o bit da extrema esquerda no MBR de 1 byte é copiado para os 24 bits superiores no barramento B. No caso de ILOAD (inteiro de 8 bits sem sinal), a operação adequada é preencher com zeros. Nesse caso, os 24 bits superiores do barramento B são simplesmente fornecidos com zeros. Essas duas operações são distinguidas por sinais separados que indicam qual operação deve ser executada (veja a Figura 4.6). No microcódigo, isso é indicado por MBR (estendido em sinal, como em BIPUSH 3) ou MBRU (sem sinal, como em iload2). Enquanto está esperando que a memória forneça o operando (em iload3), SP é incrementado para conter o valor para armazenar o resultado, o novo topo da pilha. Esse valor também é copiado para MAR em preparação para escrever o operando para o topo. Mais uma vez, o PC deve ser incrementado para buscar o próximo opcode (em iload4). Por fim, MDR é copiado para TOS para refletir o novo topo da pilha (em iload5). ISTORE é a operação inversa de ILOAD, isto é, uma palavra é retirada do topo da pilha e armazenada na loca- lização especificada pela soma de LV e do índice contido na instrução. Ela usa o mesmo formato de ILOAD, mos- trado na Figura 4.19(a), exceto que o opcode é 0x36 em vez de 0x15. Essa instrução é um pouco diferente do que poderíamos esperar porque a palavra do topo da pilha já é conhecida (em TOS), portanto, ela pode ser armazenada de imediato. Contudo, a nova palavra do topo da pilha deve ser buscada. Assim, são necessárias uma escrita, bem como uma leitura, mas elas podem ser realizadas em qualquer ordem (ou até em paralelo, se isso fosse possível). Ambas, ILOAD e ISTORE, são restritas, já que só podem acessar as primeiras 256 variáveis locais. Ao passo que para grande parte dos programas esse espaço de variáveis locais seja mais do que suficiente, claro que é necessário poder acessar uma variável onde quer que ela esteja localizada no espaço de variáveis locais. Para fazer isso, a JM usa o mesmo mecanismo empregado na JM: um opcode especial WIDE (largo), conhecido como byte de prefixo, seguido pelo opcode ILOAD ou ISTORE. Quando essa sequência ocorre, as definições de ILOAD e ISTORE são modificadas, com um índice de 16 bits após o opcode, em vez de um índice de 8 bits, como mostra a Figura 4.19(b). WIDE é decodificada do modo usual, levando um desvio para wide1 que manipula o opcode WIDE. Embora o opcode para alargar (ou ampliar – widen) já esteja disponível em MBR, wide1 busca o primeiro byte após o opcode, porque a lógica do microprograma sempre espera que ele esteja ali. Então, é feito um segundo desvio multivias em wide2, agora usando o byte após a WIDE para despachar. Contudo, já que WIDE ILOAD requer microcódigo diferente do de ILOAD, e WIDE ISTORE requer microcódigo diferente do de ISTORE etc., o segundo desvio mul- tivias não pode só usar o opcode como endereço de destino, do mesmo modo que faz Main1. Em vez disso, wide2 efetua uma operação OR de 0x100 com o opcode enquanto o coloca em MPC. O resulta- do é que a interpretação de WIDE ILOAD começa em 0x115 (em vez de 0x15), a interpretação de WIDE ISTORE começa em 0x136 (e não 0x36) e assim por diante. Desse modo, todo opcode WIDE começa em um endereço 256 palavras mais alto, isto é, 0x100, no armazenamento de controle que o opcode regular correspondente. A sequên- cia inicial de microinstruções para ambas, ILOAD e WIDE ILOAD, é mostrada na Figura 4.20. Uma vez alcançado o código para implementar WIDE ILOAD (0x115), a diferença entre ele e o ILOAD normal é apenas que o índice deve ser construído concatenando 2 bytes de índice em vez de simplesmente estender em sinal um byte único. A concatenação e subsequente adição devem ser efetuadas em etapas, primeiro copiando INDEX BYTE 1 em H deslocado 8 bits para a esquerda. isto que o índice é um inteiro sem sinal, o MBR é esten- dido em zeros usando MBRU. Agora, o segundo byte do índice é adicionado (a operação de adição é idêntica à concatenação, já que o byte de ordem baixa de H agora é zero, garantindo que não haverá vai-um entre os bytes) e, de novo, o resultado é armazenado em H. Daí em diante, a operação pode seguir exatamente como se fosse uma ILOAD padrão. Em vez de duplicar as instruções finais de ILOAD (iload3 a iload5), apenas desviamos de wide_iload4 para iload3. Todavia, note que PC deve ser incrementado duas vezes durante a execução da instru- ção de modo que passe a apontar para o próximo opcode. A instrução ILOAD o incrementa uma vez; a sequência WIDE_ILOAD também o incrementa uma vez.
  • 239. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 220 Figura 4.20 Seque ncia inicial de microinstruc o es para ILOAD e WIDE ILOAD. Os enderec os sa o exemplos. Endereço Armazenamento de controle Ordem de execução de microinstrução ILOAD WIDE ILOAD wide_iload1 Main1 1 wide1 iload1 3 1 2 2 0x1FF 0x115 0x100 0xC4 0x15 0x00 A mesma situação ocorre para WIDE_ISTORE: após a execução das primeiras quatro microinstruções (wide_istore1 até wide_istore4), a sequência é a mesma de ISTORE após as duas primeiras instruções, portanto, wide_istore4 desvia para istore3. Nosso próximo exemplo é uma instrução LDC_W. Esse opcode tem duas diferenças em relação a ILOAD. A primeira é que ele tem um deslocamento sem sinal de 16 bits (como a versão larga, ou ampliada, de ILOAD). A segunda, ele é indexado a partir de CPP em vez de LV, pois sua função é ler do conjunto de constantes em vez do quadro de variáveis locais. (Na verdade, há uma forma curta de LDC_W (LDC), mas não incluímos em JM, já que a forma longa incorpora todas as possíveis variações da forma curta, mas toma 3 bytes em vez de 2.) A instrução IINC é a única da JM, exceto a instrução ISTORE, que pode modificar uma variável local. Ela o faz incluindo dois operandos, cada um de 1 byte de comprimento, como apresenta a Figura 4.21. Figura 4.21 A instruc a o IINC tem dois campos de operando diferentes. INDEX CONST IINC (0x84) A instrução IINC usa INDEX para especificar o deslocamento em relação ao início do quadro de variáveis locais. Ela lê aquela variável, incrementando-a por CONST, um valor contido na instrução, e volta a armazená-la no mesmo local. Note que essa instrução pode incrementar por uma quantidade negativa, isto é, CONST é uma constante de 8 bits com sinal, na faixa –128 a +127. A JM completa inclui uma versão ampliada da IINC, onde cada operando tem 2 bytes de comprimento. Agora, chegamos à primeira instrução de desvio da JM: GOTO. A função exclusiva dessa instrução é alterar o valor de PC, de modo que a próxima instrução JM executada seja a que está no endereço calculado adicio-
  • 240. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 221 nando o deslocamento de 16 bits (com sinal) ao endereço opcode do desvio. Uma complicação que surge nesse caso é que o deslocamento é relativo ao valor que o PC tinha no início da decodificação da instrução, e não ao valor que ele tem depois que os 2 bytes de deslocamento foram buscados. Para esclarecer esse ponto, na Figura 4.22(a) vemos a situação no início de Main1. O opcode já está em MBR, mas o PC ainda não foi incrementado. Na Figura 4.22(b), vemos a situação no início de goto1. A essa altura, o PC já foi incrementado, mas o primeiro byte do deslocamento ainda não foi buscado para MBR. Uma microinstrução depois, temos a Figura 4.22(c), na qual o antigo PC, que aponta para o opcode, foi salvo em OPC e o primeiro byte do deslocamento está em MBR. Esse valor é necessário porque o deslocamento da instrução GOTO da JM é rela- tiva a ele e não ao valor corrente de PC. Na verdade, essa é a razão primordial por que precisamos do registrador. Figura 4.22 Situac a o no in cio de va rias microinstruc o es. (a) Main1. (b) goto1. (c) goto2. (d) goto3 (e) goto4. Memória 1 byte n + 3 n + 2 n + 1 n OFFSET BYTE 2 OFFSET BYTE 1 GOTO (0xA7) OFFSET BYTE 2 OFFSET BYTE 1 GOTO (0xA7) OFFSET BYTE 2 OFFSET BYTE 1 GOTO (0xA7) OFFSET BYTE 2 OFFSET BYTE 1 GOTO (0xA7) OFFSET BYTE 2 OFFSET BYTE 1 GOTO (0xA7) Registradores PC OPC MBR H n n n n n + 1 n + 1 n + 2 n + 2 OFFSET BYTE 1 OFFSET BYTE 2 0xA7 OFFSET BYTE 1 0xA7 OFFSET 1 << 8 (a) (b) (c) (d) (e) A microinstrução em goto2 inicia a busca do segundo byte de deslocamento, o que leva à Figura 4.22(d) no início de goto3. Depois que o primeiro byte do deslocamento foi deslocado 8 bits para a esquerda e copiado para H, chegamos em goto4 e à Figura 4.22(e). Agora, temos o primeiro byte de deslocamento desviado para a esquerda em H, o segundo byte de deslocamento em MBR e a base em OPC. Construindo o deslocamento de 16 bits completo em H e então o adicionando à base, obtemos o novo endereço para colocar em PC, em goto5. Não se esqueça de observar que usamos MBRU em goto4 em vez de MBR porque não queremos extensão de sinal do segundo byte. Na verdade, o deslocamento de 16 bits é construído efetuando uma operação OR com as duas metades. Por fim, temos de buscar o próximo opcode antes de voltar a Main1 porque o código que ali está espera o próximo opcode em MBR. O último ciclo, goto6, é necessário porque os dados da memória podem ser buscados a tempo de aparecer em MBR durante Main1. Os deslocamentos usados na instrução goto da JM são valores de 16 bits com sinal, com um mínimo de –32768 e um máximo de +32767. sso significa que desvios para qualquer lado para rótulos mais distantes do que esses valores não são possíveis. Essa propriedade pode ser considerada um bug ou uma característica na JM (e também na JM). A turma do bug diria que a definição da JM não deveria restringir seu estilo de programação. A turma da qualidade diria que o trabalho de muitos programadores sofreria uma melhoria radical se eles tivessem pesadelos com a temida mensagem do compilador: Program is too big and hairy. You must rewrite it. Compilation aborted. (Programa muito grande e confuso. ocê precisa reescrevê-lo. Compilação abortada.)
  • 241. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 222 nfelizmente (de nosso ponto de vista), essa mensagem só aparece quando uma cláusula then ou else passa de 32 KB, o que normalmente representa 50 páginas de Java. Agora, considere as três instruções JM de desvio condicional: IFLT, IFEQ e IF_ICMPEQ. As duas primeiras retiram a palavra que está no topo da pilha, desviando se a palavra for menor do que zero ou igual a zero, respec- tivamente. IF_ICMPEQ retira as duas palavras do topo da pilha e desvia se, e somente se, elas forem iguais. Em todos os três casos, é necessário ler uma nova palavra do topo da pilha para armazenar no TOS. O controle para essas três instruções é semelhante: o operando ou operandos são primeiro colocados em registradores, depois o novo valor do topo de pilha é lido para o TOS e, por fim, são realizados o teste e o desvio. Considere IFLT em primeiro lugar. A palavra a testar já está em TOS, porém, como IFLT retira uma palavra da pilha, o novo topo tem de ser lido para armazenar em TOS. Essa leitura é iniciada em iflt1. Em iflt2, a palavra a ser testada é salva em OPC por enquanto, portanto, o novo valor pode ser colocado em TOS dentro em pouco sem perder o valor corrente. Em iflt3, a nova palavra do topo da pilha está disponível em MDR, portanto, é copiada para TOS. Por fim, em iflt4, a palavra a ser testada, agora salva em OPC, é passada pela ULA sem ser armazenada e o bit N é amostrado e testado. Essa microinstrução também contém um desvio, que escolhe T se o teste foi bem-sucedido e F, caso contrário. Se bem-sucedido, o restante da operação é, em essência, a mesma que no início da instrução GOTO, e a sequên- cia simplesmente continua no meio da sequência GOTO, com goto2. Se malsucedida, é necessária uma sequência curta (F, F2 e F3) para pular o resto da instrução (o deslocamento) antes de voltar a Main1 para continuar com a instrução seguinte. O código em ifeq2 e ifeq3 segue a mesma lógica, só que usando o bit Z em vez do bit N. Em ambos os casos, cabe ao assembler de MAL reconhecer que os endereços T e F são especiais e garantir que seus endereços sejam colocados em endereços de armazenamento de controle cuja diferença seja apenas o bit da extrema esquerda. A lógica para IF_ICMPEQ é bastante semelhante à IFEQ, exceto que nesse caso precisamos ler também o segundo operando. Esse operando é armazenado em H em if_icmpeq3, onde a leitura da nova palavra do topo da pilha é iniciada. Mais uma vez, a palavra do topo da pilha corrente é salva em OPC e a nova é instalada em TOS. Por fim, o teste em if_icmpeq6 é semelhante a ifeq4. Agora, consideramos a execução de INVOKEVIRTUAL e IRETURN, as instruções para invocar um procedimento de chamada e retorno, como descrito na Seção 4.2.3. INVOKEVIRTUAL é uma sequência de 22 microinstruções e é a mais complexa instrução realizada em JM. Sua operação foi mostrada na Figura 4.12. A instrução usa seu desloca- mento de 16 bits para determinar o endereço do método a ser invocado. Em nossa implementação, esse deslocamento é simplesmente um deslocamento no conjunto de constantes. Sua localização nesse conjunto aponta o método a ser invocado. Contudo, lembre-se de que os primeiros 4 bytes de cada método não são instruções, e sim dois ponteiros de 16 bits. O primeiro dá o número de palavras de parâmetro – incluindo OBJREF (veja a Figura 4.12). O segundo dá o tamanho da área de variáveis locais em palavras. Esses campos são buscados por meio da porta de 8 bits e montados exatamente como se fossem deslocamentos de 16 bits dentro de uma instrução. Então, a informação de enlace necessária para restaurar a máquina a seu estado anterior – o endereço do início da área de variáveis antiga e o PC antigo – é armazenada imediatamente acima da área de variáveis locais recém-criada e abaixo da nova pilha. Por fim, o opcode da próxima instrução é buscado e o PC é incrementado antes de retornar a Main1 para iniciar a próxima instrução. IRETURN é uma instrução simples que não contém operandos. Ela apenas usa o endereço armazenado na primeira palavra da área de variáveis locais para recuperar a informação de ligação, então, restaura SP, LV e PC a seus valores anteriores e copia o valor de retorno do topo da pilha corrente para o topo da pilha original, con- forme ilustra a Figura 4.13. 4.4 Projeto do n vel de microarquitetura Como quase tudo na ciência da computação, o projeto da microarquitetura está repleto de compromissos. Computadores têm muitas características desejáveis, entre elas velocidade, custo, confiabilidade, facilidade de
  • 242. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 223 utilização, requisitos de energia e tamanho físico. Contudo, um compromisso comanda as decisões mais impor- tantes que os projetistas de CPU devem tomar: velocidade versus custo. Nesta seção, estudaremos esse assunto detalhadamente, para ver o que pode ser permutado pelo que, que grau de desempenho pode ser alcançado e a que preço em hardware e complexidade. 4.4.1 Velocidade versus custo Embora a tecnologia mais rápida tenha resultado no maior dos aumentos de velocidade em qualquer perío- do de tempo considerado, esse assunto não se enquadra no escopo deste livro. Melhorias de velocidade graças à organização, embora menos espetaculares do que as propiciadas por circuitos mais rápidos, ainda assim são impressionantes. elocidade pode ser medida de várias maneiras, mas dadas uma tecnologia de circuitos e uma SA, há três abordagens básicas para aumentar a velocidade de execução: 1. Reduzir o número de ciclos de clock necessários para executar uma instrução. 2. Simplificar a organização de modo que o ciclo de clock possa ser mais curto. 3. Sobrepor a execução de instruções. As duas primeiras são óbvias, mas há uma surpreendente variedade de oportunidades de projeto que pode afe- tar drasticamente o número de ciclos de clock, o período de clock, ou – em grande parte das vezes – ambos. Nesta seção, daremos um exemplo de como a codificação e a decodificação de uma operação podem afetar o ciclo de clock. O número de ciclos de clock necessários para executar um conjunto de operações é conhecido como compri- mento do caminho. Às vezes, o comprimento do caminho pode ser encurtado adicionando-se hardware especiali- zado. Por exemplo, adicionando um incrementador – conceitualmente, um somador com um lado ligado de modo permanente a “some 1” (add 1) – ao PC, não precisamos mais usar a ULA para fazer avançar o PC, eliminando ciclos. O preço a pagar é mais hardware. Todavia, essa capacidade não ajuda tanto como seria de esperar. Na maioria das instruções, os ciclos consumidos para incrementar o PC também são ciclos em que uma operação de leitura está sendo executada. Em todo caso, a instrução seguinte não pode ser executada mais cedo porque ela depende dos dados que vêm da memória. Reduzir o número de ciclos de instrução necessários para buscar instruções requer mais do que apenas um circuito adicional para incrementar o PC. Para acelerar a busca de instrução em qualquer grau significativo, a terceira técnica – sobreposição de execução – deve ser explorada. Separar o circuito de busca de instruções – a porta de memória de 8 bits e os registradores MBR e PC – é mais efetivo se, em termos funcionais, a unidade for montada independentemente do caminho de dados principal. Desse modo, ela pode buscar o próximo opcode ou operando por conta própria, talvez até mesmo executando fora de sincronia em relação ao restante da CPU e buscando uma ou mais instruções com antecedência. Uma das fases que mais consome o tempo da execução de muitas das instruções é buscar um deslocamento de 2 bytes, estendê-lo adequadamente e acumular no registrador H em preparação para uma adição, por exemplo, em um desvio para PC ± n bytes. Uma solução potencial – construir uma porta de memória de 16 bits de largu- ra – complica muito a operação porque, na verdade, a memória tem 32 bits de largura. Os 16 bits necessários podem se espalhar por fronteiras de palavras, de modo que até mesmo uma única leitura de 32 bits não buscará necessariamente ambos os bytes necessários. Sobrepor a execução de instruções é, de longe, o mais interessante e oferece a melhor oportunidade para drásticos aumentos de velocidade. A simples sobreposição da busca e execução de instruções dá um resultado surpreendentemente efetivo. Entretanto, técnicas mais sofisticadas avançam muito mais, sobrepondo a execução de muitas instruções. Na verdade, essa ideia está no coração do projeto de computadores modernos. Mais adiante, discutiremos algumas das técnicas básicas para sobrepor a execução de instruções e apresentaremos o motivo para as mais sofisticadas.
  • 243. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 224 elocidade é apenas uma metade do quadro; custo é a outra. O custo pode ser medido de vários modos, mas uma definição precisa é problemática. Algumas medidas são muito simples, tal como uma contagem do número de componentes, o que era válido em particular na época em que os processadores eram compostos de componentes discretos, que eram comprados e montados. Hoje, o processador inteiro está contido em um único chip, mas chips maiores e mais complexos são muito mais caros do que os menores, mais simples. Componentes individuais – por exemplo, transistores, portas ou unidades funcionais – podem ser contados, mas quase sempre o número resultante não é tão importante quanto a quantidade de área requerida no circuito integrado. Quanto mais área for requerida para as funções incluídas, maior será o chip, e o custo de fabricação deste cresce com rapidez muito maior do que sua área. Por essa razão, projetistas costumam falar de custo em termos utilizados na área imobiliária, isto é, a área exigida por um circuito (imagino que seja medida em pico-hectares). Um dos circuitos mais exaustivamente estudados na história é o somador binário. Há milhares de projetos e os mais rápidos são muito mais velozes do que os mais lentos – e também muito mais complexos. O projetista de sistemas tem de decidir se a maior velocidade vale o preço do espaço. Somadores não são os únicos componentes que têm muitas opções. Praticamente qualquer componente do sistema pode ser projetado para executar de modo mais rápido ou mais lento, com um diferencial de custo. O desafio para o projetista é identificar os componentes que mais podem melhorar o sistema e então aumentar a velocidade deles. O interessante é que muitos componentes individuais podem ser substituídos por um muito mais veloz e causar pouco ou nenhum efeito sobre a velocidade. Nas seções seguintes, examinaremos algumas das questões de projeto e os compromissos correspondentes. Um dos fatores fundamentais para determinar a velocidade em que um clock pode executar é a quantidade de trabalho que deve ser realizada em cada ciclo de clock. É óbvio que, quanto mais trabalho a ser realizado, mais longo será o ciclo. Claro que não é assim tão simples, porque o hardware é muito bom para fazer coisas em paralelo. Portanto, na verdade, o que determina o comprimento do ciclo de clock é a sequência de operações que devem ser executadas em série em um único ciclo. Um aspecto que pode ser controlado é a quantidade de decodificação que deve ser realizada. Lembre-se, por exemplo, de que na Figura 4.6 vimos que, embora qualquer um de nove registradores pudesse ser lido para a ULA a partir do barramento B, precisávamos de apenas 4 bits na palavra de microinstrução para especificar qual registrador devia ser selecionado. nfelizmente, essas economias têm um preço. O circuito de decodificação agrega atraso ao caminho crítico, e isso significa que qualquer registrador que habilite seus dados para o barramento B receberá o comando um pouquinho mais tarde e obterá seus dados no barramento um pouquinho mais tarde. sso provoca um efeito em cascata, com a ULA recebendo suas entradas um pouco mais tarde e produzindo seus resultados um pouco mais tarde. Por fim, o resultado estará disponível no barramento C para ser escrito nos regis- tradores também um pouco mais tarde. Como esse atraso muitas vezes é o fator que determina o comprimento do ciclo de clock, isso pode significar que o clock não pode funcionar com tanta rapidez e todo o computador deve funcionar um pouco mais lentamente. Assim, há uma permuta entre velocidade e custo. A redução do armaze- namento de controle em 5 bits por palavra é obtida ao custo da redução da velocidade do clock. O engenheiro deve levar em conta os objetivos do projeto ao decidir qual é a opção correta. Para uma implementação de alto desempenho, usar um decodificador talvez não seja uma boa ideia; para uma de baixo custo, pode ser. 4.4.2 Reduc a o do comprimento do caminho de execuc a o A Mic-1 foi projetada para ser moderadamente simples e moderadamente rápida, embora admitamos que há uma enorme tensão entre esses dois objetivos. Em poucas palavras, máquinas simples não são rápidas e máquinas rápidas não são simples. A CPU da Mic-1 também usa uma quantidade mínima de hardware: 10 registradores, a ULA simples da Figura 3.19 repetida 32 vezes, um deslocador, um decodificador, um armazenamento de controle e um pouquinho de cola aqui e ali. O sistema inteiro poderia ser montado com menos de 5.000 transistores mais o tanto que o armazenamento de controle (ROM) e a memória principal (RAM) precisarem. Agora que já vimos como JM pode ser executada de modo direto em microcódigo com pouco hardware, é hora de examinar implementações alternativas, mais rápidas. A seguir, vamos estudar modos de reduzir o número
  • 244. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 225 de microinstruções por instrução SA (isto é, reduzir o comprimento do caminho de execução). Depois disso, vamos considerar outras técnicas. Incorporac a o do lac o do interpretador ao microco digo Na Mic-1, o laço principal consiste em uma microinstrução que deve ser executada no início de cada ins- trução JM. Em alguns casos, é possível sobrepô-la à instrução anterior. Na verdade, isso já foi conseguido, ao menos em parte. Note que, quando Main1 é executada, o opcode a ser interpretado já está em MBR. O opcode está ali porque foi buscado pelo laço principal anterior (se a instrução anterior não tinha operandos) ou durante a execução da instrução anterior. Esse conceito de sobrepor o início da instrução pode ser levado mais adiante e, na realidade, em alguns casos o laço principal pode ser reduzido a nada. sso pode ocorrer da seguinte maneira. Considere cada sequência de microinstruções que termina desviando para Main1. Em cada lugar, a microinstrução do laço principal pode ser agregada ao final da sequência, em vez de ao início da próxima, e o desvio multivias agora é repetido em muitos lugares, mas sempre com o mesmo conjunto de alvos. Em alguns casos, a microinstrução Main1 pode ser incor- porada a microinstruções anteriores, já que elas nem sempre são totalmente utilizadas. Na Figura 4.23, é mostrada a sequência dinâmica de instruções para uma instrução POP. O laço principal ocorre antes e depois de cada instrução; na figura, mostramos apenas a ocorrência após a instrução POP. Note que a execução dessa instrução leva quatro ciclos de clock: três para as microinstruções específicas para POP e um para o laço principal. Figura 4.23 Seque ncia original de microprograma para executar POP. Rótulo Operações Comentários pop1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha pop2 Espere novo TOS ser lido da memória pop3 TOS = MDR; goto Main1 Copie nova palavra para TOS Main1 PC = PC + 1; fetch; goto (MBR) MBR contém o opcode; obtenha próximo byte; despache Na Figura 4.24, a sequência foi reduzida a três instruções que incorporam as instruções do laço principal, aproveitando um ciclo de clock no qual a ULA não é usada em pop2 para economizar um ciclo e novamente em Main1. Não se esqueça de observar que o final dessa sequência desvia diretamente para o código específico para a instrução seguinte, portanto, são requeridos apenas três ciclos no total. Esse pequeno estratagema reduz em um ciclo o tempo de execução da próxima microinstrução; portanto, por exemplo, uma IADD subsequente passa de quatro ciclos para três. Assim, isso equivale a aumentar a velocidade do clock de 250 MHz (microinstruções de 4 ns) para 333 MHz (microinstruções de 3 ns) sem pagar nada. Figura 4.24 Seque ncia de microprograma melhorada para executar POP. Rótulo Operações Comentários pop1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha Main1.pop PC = PC + 1; fetch MBR contém opcode; busque próximo byte pop3 TOS = MDR; goto (MBR) Copie nova palavra para TOS; despache em opcode
  • 245. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 226 A instrução POP se encaixa particularmente nesse tratamento porque ela tem um ciclo ocioso no meio que não usa a ULA. Contudo, o laço principal usa a ULA. Por isso, reduzir o comprimento da instrução por um fator dentro dela requer achar um ciclo na instrução no qual a ULA não está em uso. Esses ciclos ociosos não são comuns, mas ocorrem; portanto, vale a pena incorporar Main1 ao final de cada sequência de microinstrução. Tudo isso custa um pouco de armazenamento de controle. Assim, temos nossa primeira técnica para reduzir o comprimento do caminho: Incorpore o laço do interpretador ao final de cada sequência de microcódigo. Arquitetura de tre s barramentos O que mais podemos fazer para reduzir o comprimento do caminho de execução? Outra solução fácil é ter dois barramentos completos de entrada para ULA, um barramento A e um B, o que dá três barramentos no total. Todos os registradores (ou ao menos a maioria deles) devem ter acesso a ambos os barramentos de entrada. A vantagem de ter dois barramentos de entrada é que então é possível adicionar qualquer registrador a qualquer outro registrador em um só ciclo. Para ver o valor dessa característica, considere a execução de ILOAD na Mic-1, apresentada novamente na Figura 4.25. Figura 4.25 Co digo Mic-1 para executar ILOAD. Rótulo Operações Comentários iload1 H = LV MBR contém índice; copie LV para H iload2 MAR = MBRU + H; rd MAR = endereço de variáveis locais a buscar iload3 MAR = SP = SP + 1 SP aponta para novo topo da pilha; prepare escrita iload4 PC = PC + 1; fetch; wr Incremente PC; obtenha novo opcode; escreva topo da pilha iload5 TOS = MDR; goto Main1 Atualize TOS Main1 PC = PC + 1; fetch; goto (MBR) MBR contém opcode; obtenha próximo byte; despache emos aqui que, em iload1, LV é copiado para H. A única razão para LV ser copiado para H é que, assim, ele poder ser adicionado a MBRU em iload2. Em nosso projeto original de dois barramentos, não há nenhum modo de adicionar registradores arbitrários, portanto, primeiro um deles tem de ser copiado para H. Com nosso novo projeto de três barramentos, podemos economizar um ciclo, conforme mostra a Figura 4.26. Nesse caso, adi- cionamos o laço do interpretador a ILOAD, mas isso nem aumenta nem diminui o comprimento do caminho de execução. Ainda assim, o barramento adicional reduziu o tempo total de execução de ILOAD de seis para cinco ciclos. Agora, temos nossa segunda técnica para reduzir o comprimento de caminho: Passe de um projeto de dois barramentos para um projeto de três barramentos. Figura 4.26 Co digo de tre s barramentos para executar ILOAD. Rótulo Operações Comentários iload1 MAR = MBRU + LV; rd MAR = endereço de variável local a buscar iload2 MAR = SP = SP + 1 SP aponta para novo topo da pilha; prepare escrita iload3 PC = PC + 1; fetch; wr Incremente PC; obtenha novo opcode; escreva topo da pilha iload4 TOS = MDR Atualize TOS iload5 PC = PC + 1; fetch; goto (MBR) MBR já contém opcode; busque byte de índice
  • 246. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 227 Unidade de busca de instruc a o ale a pena usar essas duas técnicas, mas, para conseguir uma melhoria drástica, precisamos de algo muito mais radical. amos voltar atrás um pouco e examinar as partes comuns de toda instrução: a busca e a decodifi- cação dos campos da instrução. Observe que, para cada instrução, podem ocorrer as seguintes operações: 1. O PC é passado pela ULA e incrementado. 2. O PC é usado para buscar o próximo byte na sequência de instruções. 3. Operandos são lidos da memória. 4. Operandos são escritos para a memória. 5. A ULA efetua um cálculo e os resultados são armazenados de volta. Se uma instrução tiver campos adicionais (para operandos), cada campo deve ser buscado explicitamente, um byte por vez, e montado antes de poder ser usado. Buscar e montar um campo ocupa a ULA por no mínimo um ciclo por byte para incrementar o PC, e então de novo para montar o índice ou deslocamento resultante. A ULA é usada em praticamente todos os ciclos para uma série de operações que têm a ver com buscar a instrução e montar os campos dentro da instrução, além do “trabalho” real da instrução. Para sobrepor o laço principal, é necessário liberar a ULA de algumas dessas tarefas. sso poderia ser feito com a introdução de uma segunda ULA, embora não seja necessária uma completa para grande parte da atividade. Observe que, em muitos casos, ela é apenas usada como um caminho para copiar um valor de um registrador para outro. Esses ciclos poderiam ser eliminados introduzindo-se caminhos de dados adicionais que não passem pela ULA. Como exemplo, pode-se conseguir algum benefício criando um caminho de TOS a MDR, ou de MDR a TOS, uma vez que a palavra do topo da pilha é muitas vezes copiada entre esses dois registradores. Na Mic-1, grande parte da carga pode ser retirada da ULA criando uma unidade independente para buscar e processar as instruções. Essa unidade, denomina IFU (Instruction Fetch Unit  unidade de busca de instrução), pode incrementar o PC independentemente e buscar bytes antes de eles serem necessários. Essa unidade requer apenas um incrementador, um circuito muito mais simples do que um somador completo. Levando essa ideia mais adiante, a FU também pode montar operandos de 8 e 16 bits de modo que eles estejam prontos para uso imediato sempre que necessário. Há no mínimo dois modos de fazer isso: 1. A FU pode interpretar cada opcode, determinando quantos campos adicionais devem ser buscados, e montá-los em um registrador pronto para a utilização pela unidade de execução principal. 2. A FU pode aproveitar a natureza sequencial das instruções e disponibilizar os próximos fragmentos de 8 e 16 bits todas as vezes, quer isso tenha ou não algum sentido. Então, a unidade de execução principal pode requisitar o que precisar. Mostramos os rudimentos do segundo esquema na Figura 4.27. Em vez de um único MBR de 8 bits, agora há dois MBRs: o MBR1 de 8 bits e o MBR2 de 16 bits. A FU monitora o(s) byte(s) mais recentemente consumido(s) pela unidade de execução principal. Também disponibiliza o próximo byte em MBR1 como na Mic-1, exceto que percebe automaticamente quando MBR1 é lido, busca o próximo byte por antecipação e o carrega em MBR1 de imediato. Como na Mic-1, ela tem duas interfaces com o barramento B: MBR1 e MBR1U. A primeira é estendida em sinal para 32 bits; a outra é estendida para zero. De modo semelhante, o MBR2 oferece a mesma funcionalidade, mas contém os próximos 2 bytes. Também tem duas interfaces com o barramento B: MBR2 e MBR2U, que copiam os valores de 32 bits estendidos em sinal e estendidos em zeros, respectivamente. A FU é responsável por buscar uma sequência de bytes, e faz isso usando uma porta de memória con- vencional de 4 bytes, buscando palavras inteiras de 4 bytes antes da hora e carregando os bytes consecutivos em um registrador de deslocamento que os fornece um ou dois por vez, na ordem em que foram buscados. A função do registrador de deslocamento é manter uma fila de bytes da memória, para alimentar MBR1 e MBR2.
  • 247. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 228 Figura 4.27 Unidade de busca para a Mic-1. MBR2 Registrador de deslocamento Da memória MBR1 +1 Escreva PC 2 bits de ordem baixa Barramento B Barramento C IMAR PC +1, 2 Em todas as vezes, MBR1 contém o byte mais antigo no registrador de deslocamento e MBR2 contém os 2 bytes mais antigos (byte mais antigo na esquerda), para formar um inteiro de 16 bits (veja a Figura 4.19(b)). Os 2 bytes em MBR2 podem ser de palavras de memória diferentes, porque instruções JM não se alinham em fronteiras de palavras na memória. Sempre que MBR1 é lido, o registrador de deslocamento desloca 1 byte para a direita. Sempre que MBR2 é lido, ele desloca 2 bytes para a direita. Então, MBR1 e MBR2 são recarregados a partir do byte mais antigo e do par de bytes mais antigo, respectivamente. Se agora restar espaço suficiente no registrador de deslocamento para mais outra palavra inteira, a FU inicia um ciclo de memória para lê-la. Admitimos que, quando qualquer um dos registradores MBR é lido, ele é preenchido outra vez no início do ciclo seguinte, de modo que pode ser lido em ciclos consecutivos. O projeto da FU pode ser modelado por uma FSM (Finite State Machine  máquina de estado finito), como ilustra a Figura 4.28. Todas as FSMs consistem em duas partes: estados, representados por círculos, e transições, representadas por arcos que vão de um estado a outro. Cada estado representa uma situação possível na qual a FSM pode estar. Essa FSM particular tem sete estados, correspondentes aos estados do registrador de deslocamento da Figura 4.27. Os sete estados correspondem à quantidade de bytes que estão naquele registrador no momento em questão, um número entre 0 e 6, inclusive. Cada arco representa um evento que pode ocorrer. Três eventos diferentes podem ocorrer nesse caso. O pri- meiro deles é a leitura de 1 byte do MBR1. Esse evento faz o registrador de deslocamento ser ativado e 1 byte ser deslocado para fora da extremidade direita, que reduz o estado por um fator de 1. O segundo evento é a leitura de 2 bytes do MBR2, o que reduz o estado por um fator de dois. Essas duas transições fazem MBR1 e MBR2 serem recarregados. Quando a FSM passa para os estados 0, 1 ou 2, é iniciada uma referência à memória para buscar uma nova palavra (considerando que a memória já não esteja ocupada lendo uma). A chegada da palavra adianta o estado por um fator de 4. Para trabalhar corretamente, a FU deve bloquear quando requisitada a fazer algo que não pode, tal como for- necer o valor de MBR2 quando há somente 1 byte no registrador de deslocamento e a memória ainda está ocupada buscando uma nova palavra. Além disso, ela só pode fazer uma coisa por vez, portanto, eventos que estão chegan- do devem ser serializados. Por fim, sempre que o PC é alterado, a FU deve ser atualizada. Esses detalhes a tornam mais complicada do que mostramos. Ainda assim, muitos dispositivos de hardware são construídos como FSMs.
  • 248. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 229 Figura 4.28 Ma quina de estado finito para implementar a IFU. Palavra buscada Palavra buscada Palavra buscada 0 MBR1 MBR2 MBR2 MBR2 MBR2 MBR2 Transições MBR1: ocorre quando MBR1 é lido MBR2: ocorre quando MBR2 é lido Palavra buscada: ocorre quando uma palavra da memória é lida e 4 bytes são colocados no registrador de deslocamento 1 MBR1 2 MBR1 3 MBR1 4 MBR1 5 MBR1 6 A FU tem seu próprio registrador de endereço de memória, denominado IMAR, que é usado para endereçar a memória quando uma nova palavra tem de ser buscada. Esse registrador tem seu próprio incrementador dedi- cado, de modo que a ULA principal não é necessária para incrementá-lo nem para buscar a próxima palavra. A FU deve monitorar o barramento C de modo que, sempre que PC for carregado, o novo valor de PC é copiado para IMAR. Uma vez que o novo valor em PC pode não estar sobre uma fronteira de palavra, a FU tem de buscar a palavra necessária e fazer o ajuste adequado do registrador de deslocamento. Com a FU, a unidade de execução principal escreve para o PC somente quando for necessário alterar a natu- reza sequencial do fluxo de bytes da instrução. Ela escreve por causa de uma instrução de desvio bem-sucedida e em virtude da INVOKEVIRTUAL e IRETURN. Já que o microprograma não mais incrementa o PC explicitamente, porque opcodes são buscados, a FU deve manter o PC atualizado. Ela o faz percebendo quando um byte da instrução foi consumido, isto é, quando MBR1 ou MBR2, ou as versões sem sinal, foram lidos. Associado com o PC há um incrementador separado, capaz de incrementar por fatores de 1 ou 2, dependendo de quantos bytes foram consumidos. Assim, o PC sempre contém o endereço do primeiro byte que não foi consumido. No início de cada instrução, MBR contém o endereço do opcode para aquela instrução. Note que há dois incrementadores separados e eles executam funções diferentes. O PC conta bytes e incre- menta por um fator de 1 ou 2. O IMAR conta palavras, e incrementa somente por um fator de 1 (para 4 bytes novos). Como o MAR, o IMAR está ligado “obliquamente” ao barramento de endereço, sendo que o bit 0 do IMAR está conectado à linha de endereço 2, e assim por diante, para efetuar uma conversão implícita de endereços de palavras para endereços de bytes. Como detalharemos em breve, não ter de incrementar o PC no laço principal representa um grande ganho, porque a microinstrução na qual ele é incrementado costuma fazer pouco mais do que isso. Se tal microinstrução puder ser eliminada, o caminho de execução pode ser reduzido. Nesse caso, a permuta é mais hardware por uma máquina mais rápida, portanto, nossa terceira técnica para reduzir o comprimento do caminho é: Busque instruções na memória com uma unidade funcional especializada. 4.4.3 O projeto com busca antecipada: a Mic-2 A FU pode reduzir muito o comprimento do caminho da instrução média. Primeiro, ela elimina todo o laço principal, visto que o final de cada instrução apenas desvia diretamente para a próxima. Segundo, evita ocupar
  • 249. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 230 a ULA com a tarefa de incrementar o PC. Terceiro, reduz o comprimento do caminho sempre que um índice de 16 bits ou um deslocamento é calculado, porque ela monta o valor de 16 bits e o passa diretamente para a ULA como um valor de 32 bits, evitando a necessidade de montagem em H. A Figura 4.29 mostra a Mic-2, uma versão melhorada da Mic-1 à qual foi acrescentada a FU da Figura 4.27. O microcódigo para a máquina melhorada é ilustrado na Figura 4.30. Figura 4.29 O caminho de dados para a Mic-2. H Deslocador ULA N Barramento B Barramento C 6 Controle da ULA Sinais de controle Registradores de controle de memória Habilite para barramento B Escreva barramento C para registrador De e para a memória principal Z MBR2 SP LV CPP TOS PC MDR MAR MBR OPC Unidade de busca de instrução (IFU) Barramento A
  • 250. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 231 Figura 4.30 Microprograma para a Mic-2. Rótulo Operações Comentários nop1 goto (MBR) Desvie para a próxima instrução iadd1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha iadd2 H = TOS H = topo da pilha iadd3 MDR = TOS = MDR + H; wr; goto (MBR1) Some duas palavras do topo; escreva para novo topo da pilha isub1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha isub2 H = TOS H = topo da pilha isub3 MDR = TOS = MDR – H; wr; goto (MBR1) Subtraia TOS da palavra anterior na pilha iand1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha iand2 H = TOS H = topo da pilha iand3 MDR = TOS = MDR AND H; wr; goto (MBR1) AND palavra anterior da pilha com TOS ior1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha ior2 H = TOS H = topo da pilha ior3 MDR = TOS = MDR OR H; wr; goto (MBR1) OR palavra anterior da pilha com TOS dup1 MAR = SP = SP + 1 Incremente SP; copie para MAR dup2 MDR = TOS; wr; goto (MBR1) Escreva nova palavra da pilha pop1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha pop2 Espere pela leitura pop3 TOS = MDR; goto (MBR1) Copie nova palavra para TOS swap1 MAR = SP – 1; rd Leia a segunda palavra da pilha; ajuste MAR para SP swap2 MAR = SP Prepare para escrever nova 2a palavra swap3 H = MDR; wr Salve novo TOS; escreva 2a palavra para pilha swap4 MDR = TOS Copie antigo TOS para MDR swap5 MAR = SP – 1; wr Escreva antigo TOS para 2o lugar na pilha swap6 TOS = H; goto (MBR1) Atualize TOS bipush1 SP = MAR = SP + 1 Ajuste MAR para escrever para novo topo da pilha bipush2 MDR = TOS = MBR1; wr; goto (MBR1) Atualize pilha em TOS e memória iload1 MAR = LV + MBR1U; rd Passe LV + índice para MAR; leia operando iload2 MAR = SP = SP + 1 Incremente SP; passe novo SP para MAR iload3 TOS = MDR; wr; goto (MBR1) Atualize pilha em TOS e memória istore1 MAR = LV + MBR1U Ajuste MAR para LV + índice istore2 MDR = TOS; wr Copie TOS para armazenamento istore3 MAR = SP = SP – 1; rd Decremente SP; leia novo TOS istore4 Espere por leitura istore5 TOS = MDR; goto (MBR1) Atualize TOS
  • 251. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 232 Rótulo Operações Comentários wide1 goto (MBR1 OR 0x100) Próximo endereço é 0x100 com operação OR efetuada com opcode wide_iload1 MAR = LV + MBR2U; rd; goto iload2 Idêntica a iload1 mas usando índice de 2 bytes wide_istore1 MAR = LV + MBR2U; goto istore2 Idêntica a istore1 mas usando índice de 2 bytes ldc_w1 MAR = CPP + MBR2U; rd; goto iload2 O mesmo que wide_iload1 mas indexando a partir de CPP iinc1 MAR = LV + MBR1U; rd Ajuste MAR para LV + índice para leitura iinc2 H = MBR1 Ajuste H para constante iinc3 MDR = MDR + H; wr; goto (MBR1) Incremente por constante e atualize goto1 H = PC – 1 Copie PC para H goto2 PC = H + MBR2 Some deslocamento e atualize PC goto3 Tem de esperar que IFU busque novo opcode goto4 goto (MBR1) Despache para a próxima instrução iflt1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha iflt2 OPC = TOS Salve TOS em OPC temporariamente iflt3 TOS = MDR Ponha novo topo da pilha em TOS iflt4 N = OPC; if (N) goto T; else goto F Desvie no bit N ifeq1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha ifeq2 OPC = TOS Salve TOS em OPC temporariamente ifeq3 TOS = MDR Ponha novo topo da pilha em TOS ifeq4 Z = OPC; if (Z) goto T; else goto F Desvie no bit Z if_icmpeq1 MAR = SP = SP – 1; rd Leia a palavra seguinte à do topo da pilha if_icmpeq2 MAR = SP = SP – 1 Ajuste MAR para ler novo topo da pilha if_icmpeq3 H = MDR; rd Copie segunda palavra da pilha para H if_icmpeq4 OPC = TOS Salve TOS em OPC temporariamente if_icmpeq5 TOS = MDR Ponha novo topo da pilha em TOS if_icmpeq6 Z = H – OPC; if (Z) goto T; else goto F Se 2 palavras do topo forem iguais, vá para T, senão vá para F T H = PC – 1; goto goto2 O mesmo que goto1 F H = MBR2 Toque bytes em MBR2 para descartar F2 goto (MBR1) invokevirtual1 MAR = CPP + MBR2U; rd Ponha endereço de ponteiro de método em MAR invokevirtual2 OPC = PC Salve Return PC em OPC invokevirtual3 PC = MDR Ajuste PC para 1o byte do código de método invokevirtual4 TOS = SP – MBR2U TOS = endereço de OBJREF – 1 invokevirtual5 TOS = MAR = H = TOS + 1 TOS = endereço de OBJREF invokevirtual6 MDR = SP + MBR2U + 1; wr Sobrescreva OBJREF com ponteiro de ligação invokevirtual7 MAR = SP = MDR Ajuste SP, MAR à localização para conter PC antigo
  • 252. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 233 Rótulo Operações Comentários invokevirtual8 MDR = OPC; wr Prepare para salvar PC antigo invokevirtual9 MAR = SP = SP + 1 Incremente SP para apontar para a localização para conter LV antigo invokevirtual10 MDR = LV; wr Salve LV antigo invokevirtual11 LV = TOS; goto (MBR1) Ajuste LV para apontar para o parâmetro de ordem zero ireturn1 MAR = SP = LV; rd Reajuste SP, MAR para ler ponteiro de ligação ireturn2 Espere por ponteiro de ligação ireturn3 LV = MAR = MDR; rd Ajuste LV, MAR para ponteiro de ligação; leia PC antigo ireturn4 MAR = LV + 1 Ajuste MAR para apontar para LV antigo; leia LV antigo ireturn5 PC = MDR; rd Restaure PC ireturn6 MAR = SP ireturn7 LV = MDR Restaure LV ireturn8 MDR = TOS; wr; goto (MBR1) Salve valor de retorno no topo da pilha original Como exemplo do modo de funcionamento da Mic-2, examine a IADD. Ela pega a segunda palavra em uma pilha e efetua a adição como antes, só que agora, quando termina, ela não tem de ir até Main1 para incremen- tar PC e despachar para a próxima microinstrução. Quando a FU vê que MBR1 foi referenciado em iadd3, seu registrador de deslocamento interno empurra tudo para a direita e recarrega MBR1 e MBR2. Ela também faz a transição para um estado um grau mais baixo do que o corrente. Se o novo estado for 2, a FU começa a buscar uma palavra da memória. Tudo isso é feito em hardware – o microprograma não tem de fazer nada. É por isso que a IADD pode ser reduzida de quatro para três microinstruções. A Mic-2 melhora algumas instruções mais do que outras. LDC_W passa de nove microinstruções para ape- nas três, reduzindo seu tempo de execução por um fator de três. Por outro lado, SWAP só passa de oito para seis microinstruções. O que de fato conta para o desempenho geral é o ganho para as instruções mais comuns. Podemos citar ILOAD (eram 6, agora são 3), IADD (eram 4, agora são 3) e IF_ICMPEQ (eram 13, agora são 10 para o caso do desvio tomado; eram 10, agora são 8 para o caso do desvio não tomado). Para medir a melhoria, teríamos de escolher e executar alguns padrões de comparação, mas é claro que tudo isso representa um grande ganho. 4.4.4 Projeto com pipeline: a Mic-3 A Mic-2 é uma melhoria clara em relação à Mic-1. É mais rápida e usa menos armazenamento de controle, em- bora o custo da FU sem dúvida seja maior do que o ganho obtido por ter um armazenamento de controle menor. Portanto, ela é uma máquina bem mais rápida por um preço pouca coisa mais alto. amos ver se podemos fazê-la ficar ainda mais rápida. Que tal tentar reduzir o tempo de ciclo? Ele é determinado, em considerável proporção, pela tecnologia sub- jacente. Quanto menores os transistores e mais curtas as distâncias físicas entre eles, mais rapidamente o clock pode ser executado. Para uma determinada tecnologia, o tempo requerido para executar uma operação completa de caminho de dados é fixo (ao menos de nosso ponto de vista). Ainda assim, temos certa liberdade e em breve a exploraremos ao máximo. Nossa outra opção é introduzir mais paralelismo na máquina. No momento, a Mic-2 é altamente sequencial. Ela coloca registradores em seus barramentos, espera que a ULA e o deslocador os processem para depois escrever os resultados de volta nos registradores. Exceto pela FU, há pouco paralelismo presente. Adicionar paralelismo é uma oportunidade real.
  • 253. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 234 Como já dissemos, o ciclo de clock é limitado pelo tempo necessário para que os sinais se propaguem pelo caminho de dados. A Figura 4.3 mostra um desdobramento do atraso em vários componentes durante cada ciclo. Há três componentes importantes no ciclo do caminho de dados propriamente dito: 1. O tempo para levar os registradores selecionados até os barramentos A e B. 2. O tempo para que a ULA e o deslocador realizem seu trabalho. 3. O tempo para os resultados voltarem aos registradores e serem armazenados. Na Figura 4.31, mostramos uma nova arquitetura e três barramentos, incluindo a FU, mas com três regis- tradores adicionais, cada um inserido no meio de cada barramento. Os registradores são escritos em todo o ciclo. Na realidade, eles repartem o caminho de dados em partes distintas que agora podem funcionar de modo inde- pendente. Denominaremos isso Mic-3, ou modelo pipeline. Figura 4.31 Caminho de dados de tre s barramentos usados em Mic-3. H Latch A Latch C Latch B Deslocador ULA N Barramento B Barramento C 6 Controle da ULA Sinais de controle Registradores de controle da memória Habilite para barramento B Escreva barramento C no registrador De e para memória principal Z MBR2 SP LV CPP TOS PC MDR MAR MBR1 OPC Unidade de busca de instrução Barramento A
  • 254. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 235 Como esses registradores extras podem ajudar? Agora, leva três ciclos de clock para usar o caminho de dados: um para carregar os latches A e B, um para executar a ULA e deslocador e carregar o latch C, e um para armazenar o latch C de volta nos registradores. Certamente, isso é pior do que tínhamos antes. Estamos loucos? (Dica: Não!) nserir os registradores tem dupla finalidade: 1. Podemos aumentar a velocidade do clock porque o atraso máximo agora é mais curto. 2. Podemos usar todas as partes do caminho de dados durante cada ciclo. Desmembrando o caminho de dados em três partes, o atraso máximo é reduzido e o resultado é que a frequência do clock pode ser mais alta. amos supor que, desmembrando o ciclo do caminho de dados em três intervalos de tempo, o comprimento de cada um seja cerca de 1/3 do original, de modo que podemos triplicar a velocidade do clock. (sso não é de todo realidade, já que também adicionamos dois registradores ao caminho de dados, mas serve como uma primeira aproximação.) Como estamos considerando que todas as leituras e escritas da memória podem ser satisfeitas na cache de nível 1, e que esta é feita do mesmo material que os registradores, continuaremos a supor que uma operação de memória leva um ciclo. Porém, na prática, isso pode não ser fácil de conseguir. O segundo ponto trata do rendimento, e não da velocidade, de uma instrução individual. Na Mic-2, durante a primeira e a terceira partes de cada ciclo de clock, a ULA fica ociosa. Desmembrando o caminho de dados em três pedaços, poderemos usar a ULA em cada ciclo, obtendo três vezes mais trabalho da máquina. Agora, vamos ver como o caminho de dados da Mic-3 funciona. Antes de começar, precisamos de uma notação para lidar com os registradores. A óbvia é denominar os registradores A, B e C e tratá-los como os outros registradores, tendo em mente as restrições do caminho de dados. A Figura 4.32 mostra um exemplo de sequência de código, a execução de SWAP para a Mic-2. Figura 4.32 Co digo Mic-2 para SWAP. Rótulo Operações Comentários swap1 MAR = SP – 1; rd Leia a segunda palavra da pilha; ajuste MAR a SP swap2 MAR = SP Prepare para escrever nova segunda palavra swap3 H = MDR; wr Salve novo TOS; escreva segunda palavra para pilha swap4 MDR = TOS Copie TOS antigo para MDR swap5 MAR = SP – 1; wr Escreva TOS antigo para o segundo lugar na pilha swap6 TOS = H; goto (MBR1) Atualize TOS Agora, vamos reimplementar essa sequência na Mic-3. Lembre-se de que o caminho de dados agora requer três ciclos para operar: um para carregar A e B, um para efetuar a operação e carregar C e um para escrever o resultado de volta para os registradores. Denominaremos cada um desses pedaços microetapa. A implementação de SWAP para Mic-3 é mostrada na Figura 4.33. No ciclo 1, começamos em swap1 copian- do SP para B. Não importa o que acontece em A porque, para subtrair 1 de B, ENA é negado (veja a Figura 4.2). Para simplificar, não mostramos atribuições que não são usadas. No ciclo 2, efetuamos a subtração. No ciclo 3, o resultado é armazenado em MAR e a operação de leitura é iniciada no final do ciclo 3, após MAR ter sido armaze- nado. Já que leituras de memória agora levam um ciclo, essa não estará concluída até o final do ciclo 4, o que é indicado mostrando a atribuição MDR no ciclo 4. O valor em MDR não pode ser lido antes do ciclo 5.
  • 255. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 236 Figura 4.33 A implementac a o de SWAP na Mic-3. Swap1 Swap2 Swap3 Swap4 Swap5 Swap6 Ciclo MAR = SP – 1; rd MAR = SP H = MDR; wr MDR = TOS MAR = SP – 1; wr TOS = H; goto (MBR1) 1 B = SP 2 C = B – 1 B = SP 3 MAR = C; rd C = B 4 MDR = Mem MAR = C 5 B = MDR 6 C = B B = TOS 7 H = C; wr C = B B = SP 8 Mem = MDR MDR = C C = B – 1 B = H 9 MAR = C; wr C = B 10 Mem = MDR TOS = C 11 goto (MBR1) amos voltar ao ciclo 2. Agora, podemos começar a desmembrar swap2 em microetapas e iniciá-las também. No ciclo 2, podemos copiar SP para B, então passá-lo pela ULA no ciclo 3 e por fim armazená-lo em MAR no ciclo 4. Até aqui, tudo bem. Deve estar claro que, se pudermos continuar nesse ritmo, iniciando uma nova microinstrução a cada ciclo, triplicaremos a velocidade da máquina. Esse ganho vem do fato de que podemos emitir uma nova microinstrução a cada ciclo de clock, que a Mic-3 tem três vezes mais ciclos de clock por segundo do que a Mic-2. Na verdade, construímos uma CPU com pipeline. nfelizmente, encontramos um empecilho no ciclo 3. Gostaríamos de começar a trabalhar em swap3, mas a primeira coisa que ela faz é passar MDR pela ULA, e MDR não estará disponível na memória até o início do ciclo 5. A situação em que uma microetapa não pode iniciar porque está esperando um resultado que uma microetapa anterior ainda não produziu é denominada dependência verdadeira ou dependência RW. Dependências cos- tumam ser denominadas ocorrências (hazards). RAW quer dizer Read After Write (leitura após escrita) e indica que uma microetapa quer ler um registrador que ainda não foi escrito. A única coisa sensata a fazer nesse caso é atrasar o início de swap3 até MDR estar disponível no ciclo 5. Esperar por um valor necessário é denominado protelação (stalling). Depois disso, podemos continuar iniciando microinstruções a cada ciclo, pois não há mais dependências, embora swap6 escape por um triz, uma vez que lê H no ciclo após swap3 escrevê-lo. Se swap5 tivesse tentado ler H, ela (swap6) teria sido protelada por um ciclo. Embora o programa Mic-3 leve mais ciclos do que o programa Mic-2, ainda assim é mais rápido. Se denomi- narmos o tempo de ciclo da Mic-3 ∆T ns, então, ela vai requerer 11 ∆T ns para executar SWAP. Por comparação, a Mic-2 leva 6 ciclos a 3 ∆T cada, para um total de 18 ∆T. O pipeline deixou a máquina mais rápida, ainda que tivéssemos de protelar uma vez para evitar uma dependência. Pipeline é uma técnica fundamental em todas as CPUs modernas, portanto, é importante entendê-lo bem. Na Figura 4.34, vemos o caminho de dados da Figura 4.31 ilustrado graficamente como um pipeline. A primeira coluna representa o que está acontecendo no ciclo 1, a segunda representa o ciclo 2 e assim por diante (consi- derando que não haja protelação). A região sombreada no ciclo 1 para a instrução 1 indica que a FU está ocupada buscando a instrução 1. Uma batida de clock mais tarde, durante o ciclo 2, os registradores requisitados pela instru- ção 1 estão sendo carregados nos registradores A e B enquanto, ao mesmo tempo, a FU está ocupada buscando a instrução 2, de novo mostrada pelos dois retângulos sombreados no ciclo 2.
  • 256. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 237 Figura 4.34 Ilustrac a o gra fica do funcionamento do pipeline. 1 Instrução Ciclo 1 Ciclo 2 Tempo Ciclo 3 Ciclo 4 IFU ULA Reg A C B IFU ULA Reg A C B IFU ULA Reg A C B IFU ULA Reg A C B IFU ULA Reg A C B IFU ULA Reg A C B IFU ULA Reg A C B IFU ULA Reg A C B IFU ULA Reg A C B IFU ULA Reg A C B 2 IFU ULA Reg A C B IFU ULA Reg A C B IFU ULA Reg A C B 3 IFU ULA Reg A C B IFU ULA Reg A C B 4 IFU ULA Reg A C B Deslocador Deslocador Deslocador Deslocador Deslocador Deslocador Deslocador Deslocador Deslocador Deslocador Deslocador Deslocador Deslocador Deslocador Deslocador Deslocador Durante o ciclo 3, a instrução 1 está usando a ULA e o deslocador para executar sua operação e os regis- tradores A e B estão sendo carregados para a instrução 2, e a instrução 3 está sendo buscada. Por fim, durante o ciclo 4, quatro instruções estão sendo processadas ao mesmo tempo. Os resultados da instrução 1 estão sendo armazenados, o trabalho da ULA para a instrução 2 está sendo realizado, os registradores A e B para a instrução 3 estão sendo carregados e a instrução 4 está sendo buscada. Se tivéssemos mostrado o ciclo 5 e os subsequentes, o padrão teria sido o mesmo do ciclo 4: todas as qua- tro partes do caminho de dados que podem executar independentemente estariam fazendo isso. Esse projeto representa um pipeline de quatro estágios: para busca de instrução, acesso a operando, operações de ULA e escrita de volta para os registradores. sso é semelhante ao pipeline da Figura 2.4(a), exceto pela ausência do estágio de deco- dificação. A questão importante a entender aqui é que, embora uma única instrução leve quatro ciclos de clock para executar, a cada ciclo uma nova instrução é iniciada e uma velha instrução é concluída.
  • 257. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 238 Outro modo de ver a Figura 4.34 é seguir cada instrução na página em sentido horizontal. Para a instrução 1, no ciclo 1 a FU está trabalhando nela. No ciclo 2, seus registradores estão sendo colocados nos barramentos A e B. No ciclo 3, a ULA e o deslocador estão trabalhando para ela. Por fim, no ciclo 4, seus resultados estão sendo armazenados de volta nos registradores. O que se deve notar nesse caso é que há quatro seções do hardware disponíveis, e durante cada ciclo, uma determinada instrução usa só um deles, liberando as outras seções para instruções diferentes. Uma analogia útil para nosso projeto com pipeline é uma linha de montagem de uma fábrica de automó- veis. Para abstrair os aspectos essenciais desse modelo, imagine que um gongo é tocado a cada minuto, quando então todos os automóveis passam para uma estação seguinte na linha. Em cada estação, os trabalhadores que ali estão executam alguma operação no carro que está à sua frente no momento em questão, como adicionar o volante ou instalar os freios. A cada batida do gongo (1 ciclo), um novo carro é introduzido no início da linha de montagem e um carro é concluído. Assim, ainda que leve centenas de ciclos para terminar um carro, a cada ciclo um carro inteiro é concluído. A fábrica pode produzir um carro por minuto, independente do tempo que realmente leva para montar um carro. Essa é a força do pipelining, e ela se aplica igualmente bem a CPUs e fábricas de automóveis. 4.4.5 Pipeline de sete esta gios: a Mic-4 Uma questão a que não demos o devido destaque é o fato de que toda microinstrução seleciona sua própria sucessora. A maioria delas apenas seleciona a instrução seguinte na sequência corrente, mas a última, tal como swap6, muitas vezes faz um desvio multivias que atrapalha o pipeline, já que é impossível continuar fazendo busca antecipada após o desvio. Precisamos de um modo melhor de lidar com essa questão. Nossa última microarquitetura é a Mic-4. Suas partes principais estão ilustradas na Figura 4.35, embora mui- tos detalhes tenham sido suprimidos em benefício da clareza. Como a Mic-3, ela tem uma FU que busca palavras da memória antecipadamente e mantém os vários MBRs. A FU também alimenta o fluxo de bytes que está entrando para um novo componente, a unidade de decodi- ficação. Essa unidade tem uma ROM interna indexada por opcode JM. Cada entrada (linha) contém duas partes: o comprimento daquela instrução JM e um índice para outra ROM, a de micro-operação. O comprimento da instrução JM é usado para permitir que a unidade de decodificação faça a análise sintática (parse) da sequência de bytes que está entrando dividindo-a em instruções, de modo que ela sempre sabe quais bytes são opcodes e quais são operandos. Se o comprimento da instrução em questão for 1 byte (por exemplo, POP), então, a unidade de decodificação sabe que o próximo byte é um opcode. Contudo, se o comprimento da instrução em questão for 2 bytes, a unidade de decodificação sabe que o próximo byte é um operando, seguido imediatamente por um outro opcode. Quando o prefixo WIDE é visto, o próximo byte é transformado em um opcode largo especial, por exemplo, WIDE + ILOAD se torna WIDE_ILOAD. A unidade de decodificação despacha o índice na micro-operação ROM que encontrou em sua tabela para o próximo componente, a unidade de enfileiramento. Essa unidade contém alguma lógica e mais duas tabelas internas, uma em ROM e uma em RAM. A ROM contém o microprograma, sendo que cada instrução JM tem certo número de entradas consecutivas denominadas micro-operações. As entradas devem estar em ordem, por- tanto, não são permitidos truques como o desvio de wide_iload2 para iload2 na Mic-2. Cada sequência JM deve ser escrita por extenso, duplicando sequências em alguns casos. As micro-operações são semelhantes às microinstruções da Figura 4.5, exceto que os campos NEXT_ ADDRESS e JAM estão ausentes e um novo campo codificado é necessário para especificar a entrada do barra- mento A. Dois novos bits também são fornecidos: Final e Goto. O bit Final é marcado na última micro-operação de cada sequência de micro-operação JM para sinalizá-la. O bit Goto é ajustado para marcar micro-operações que são microdesvios condicionais. Elas têm um formato diferente do das micro-operações normais, consistindo nos bits JAM e um índice para a ROM de micro-operação. Microinstruções que fizeram alguma coisa antes com o caminho de dados e também realizaram um microdesvio condicional (por exemplo, iflt4) agora têm de ser sub- divididas em duas micro-operações.
  • 258. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 239 Figura 4.35 Principais componentes da Mic-4. ULA B C Deslocador A Unidade de enleiramento IADD ISUB ILOAD IFLT ROM da micro-operação Unidade de busca de instrução Da memória Comprimento da IJVM Índice de ROM da micro-operação Unidade de decodicação Fila de micro-operações pendentes Final Goto 1 2 3 4 5 6 7 De/para memória ULA C M A B ULA C M A B ULA C M A B ULA C M A B Comanda estágio 4 Comanda estágio 5 Comanda estágio 6 Comanda estágio 7 MIR1 MIR2 MIR4 MIR3 Registradores A unidade de enfileiramento funciona da seguinte maneira. Ela recebe um índice de ROM de micro-operação da unidade de decodificação. Depois, examina a micro-operação e a copia em uma fila interna. Em seguida, tam- bém copia a próxima micro-operação para a fila, bem como a seguinte depois dessa e assim até encontrar uma cujo bit Final é 1. Ela copia essa também, e então para. Considerando que não tenha encontrado uma micro- -operação com o bit Goto ligado e que ainda tenha muito espaço de sobra na fila, a unidade de enfileiramento então devolve um sinal de reconhecimento à de decodificação. Quando esta vê o reconhecimento, envia o índice da próxima instrução JM para a unidade de enfileiramento. Desse modo, por fim, a sequência de instruções JM na memória é convertida em uma sequência de micro-operações em uma fila. Essas micro-operações alimentam os MIRs, que enviam os sinais para controlar o caminho de dados. Contudo, há outro fator que temos de considerar agora: os campos em cada micro-operação não estão ativos ao mesmo tempo. Os campos A e B estão ativos durante o primeiro ciclo, o campo ULA está ativo durante o segundo ciclo, o campo C está ativo durante o terceiro ciclo, e quaisquer operações de memória ocorrem no quarto ciclo. Para fazer com que isso funcione adequadamente, introduzimos quatro MIRs independentes na Figura 4.35. No início de cada ciclo de clock (o tempo ∆w na Figura 4.3), MIR3 é copiado para MIR4, MIR2 é copiado para MIR3, MIR1 é copiado para MIR2, e MIR1 é carregado com uma nova micro-operação da fila. Então, cada MIR emite seus sinais de controle, mas só alguns deles são usados. Os campos A e B de MIR1 são usados para selecio- nar os registradores que serão enviados aos barramentos A e B, mas o campo ULA em MIR1 não é usado e não é conectado a nada mais no caminho de dados.
  • 259. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 240 Um ciclo de clock mais tarde, essa micro-operação passou para MIR2 e os registradores que ela selecionou agora estão seguros nos registradores A e B esperando pelas aventuras que hão de vir. Seu campo de ULA agora é usado para comandar a ULA. No próximo ciclo, seu campo C escreverá os resultados de volta nos registradores. Depois disso, ela passará para MIR4 e iniciará quaisquer operações de memória necessárias usando o MAR agora carregado (e MDR, para uma escrita). Um último aspecto da Mic-4 precisa de um pouco de discussão agora: microdesvios. Algumas instruções JM, como IFLT, precisam desviar condicionalmente com base, por exemplo, no bit N. Quando ocorre um microdesvio, o pipeline não pode continuar. Para lidar com isso, adicionamos o bit Goto à micro-operação. Quando a unidade de enfileiramento atinge uma micro-operação que tenha esse bit ajustado enquanto a está copiando para a fila, ela percebe que há problemas à frente e se abstém de enviar um reconhecimento à unidade de decodificação. O resultado é que a máquina ficará parada nesse ponto até que o microdesvio tenha sido resolvido. É concebível que algumas instruções JM que estão além desse desvio já tenham sido alimentadas na uni- dade de decodificação, mas não na de enfileiramento, já que ela não devolve um sinal de reconhecimento (isto é, continuação) quando atinge uma micro-operação na qual o bit Goto está ligado. São necessários hardware e mecanismos especiais para acabar com a confusão e voltar à trilha certa, mas eles estão além do escopo deste livro. Quando Edsger Dijkstra escreveu seu famoso artigo “GOTO Statement Considered Harmful” [declaração GOTO considerada perigosa (Dijkstra, 1968a)], ele não tinha ideia do quanto estava certo. Percorremos um longo caminho desde a Mic-1. Ela era uma peça de hardware muito simples, com quase todo o controle em software. A Mic-4 tem um projeto de alto pipelining, com sete estágios e hardware muito mais complexo. O pipeline é mostrado em esquema na Figura 4.36. Os números dentro dos círculos referem- -se diretamente aos componentes na Figura 4.35. A Mic-4 faz busca antecipada automática de uma sequência de bytes da memória, decodifica-a para instruções JM, converte-a para uma sequência de micro-operações usando uma ROM e a enfileira para usar quando necessário. Os primeiros três estágios do pipeline podem ser vinculados ao clock do caminho de dados se desejado, mas nem sempre haverá trabalho a fazer. Por exemplo, a FU certamente não pode alimentar um novo opcode JM à unidade de decodificação em cada ciclo de clock porque instruções JM levam vários ciclos para executar e a fila logo transbordaria. Figura 4.36 Pipeline da Mic-4. 1 IFU 2 Decodicador 3 Fila 4 Operandos 5 Execução 6 Escrita 7 Memória Em cada ciclo de clock, os MIRs são deslocados para frente e a micro-operação que está no final da fila é copiada para o MIR1 para iniciar sua execução. Os sinais de controle dos quatro MIRs então se espalham pelo caminho de dados, fazendo com que ocorram ações. Cada MIR controla uma parte diferente do caminho de dados e, portanto, microetapas diferentes. Neste projeto, temos uma CPU de alto pipelining que permite que as etapas individuais sejam muito curtas e, por isso, que a frequência de clock seja alta. Muitas CPUs são projetadas essencialmente dessa maneira, em especial, as que têm de executar um conjunto de instruções mais antigo (CSC). Por exemplo, o conceito da implementação do Core i7 é semelhante ao da Mic-4 em alguns aspectos, como veremos mais adiante neste capítulo.
  • 260. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 241 4.5 Melhoria de desempenho Todos os fabricantes de computadores querem que seus sistemas funcionem com a maior rapidez possível. Nesta seção, veremos algumas técnicas avançadas que estão sendo investigadas para melhorar o desempenho do sistema (em especial, CPU e memória). Pela natureza de alta competitividade da indústria de computadores, a defasagem entre novas ideias que podem tornar um computador mais rápido e sua incorporação a produtos é surpreendentemente curta. Por conseguinte, a maioria das ideias que discutiremos já está em uso em uma grande maioria de produtos. As ideias que discutiremos podem ser classificadas, de modo geral, em duas grandes categorias. Melhorias de implementação e melhorias de arquitetura. Melhorias de implementação são modos de construir uma nova CPU ou memória para fazer o sistema funcionar mais rápido sem mudar a arquitetura. Modificar a implementação sem alterar a arquitetura significa que programas antigos serão executados na nova máquina, um importante argu- mento de venda. Um modo de melhorar a implementação é usar um clock mais rápido, mas esse não é o único. Os ganhos de desempenho obtidos na família 80386 a 80486, Pentium e projetos mais recentes, como o Core i7, se devem a implementações melhores, porque, em essência, a arquitetura permaneceu a mesma em todos eles. Alguns tipos de melhorias só podem ser feitos com a alteração da arquitetura. Às vezes, essas alterações são incrementais, como adicionar novas instruções ou registradores, de modo que programas antigos continuarão a ser executados nos novos modelos. Nesse caso, para conseguir um desempenho completo, o software tem de ser alterado, ou ao menos recompilado com um novo compilador que aproveita as novas características. Contudo, passadas algumas décadas, os projetistas percebem que a antiga arquitetura durou mais do que sua utilidade e que o único modo de progredir é começar tudo de novo. A revolução RSC na década de 1980 foi uma dessas inovações; outra está no ar agora. amos examinar um exemplo (ntel A-64) no Capítulo 5. No restante desta seção, estudaremos quatro técnicas diferentes para melhorar o desempenho da CPU. Começaremos com três melhorias de implementação já estabelecidas e depois passaremos para uma que precisa de um pouco de suporte da arquitetura para funcionar melhor. Essas técnicas são memória cache, previsão de desvio, execução fora da ordem com renomeação de registrador e execução especulativa. 4.5.1 Memo ria cache Um dos aspectos mais desafiadores do projeto de um computador em toda a história tem sido oferecer um sistema de memória capaz de fornecer operandos ao processador à velocidade em que ele pode processá-los. A recente alta taxa de crescimento na velocidade do processador não foi acompanhada de um aumento corres- pondente na velocidade das memórias. Se comparadas com as CPUs, as memórias estão ficando mais lentas há décadas. Dada a enorme importância da memória primária, essa situação limitou muito o desenvolvimento de sistemas de alto desempenho e estimulou a pesquisa a encontrar maneiras de contornar o problema da velocida- de das memórias que são muito menores do que as velocidades das CPUs e, em termos relativos, estão ficando piores a cada ano. Processadores modernos exigem muito de um sistema de memória, tanto em termos de latência (o atraso na entrega de um operando) quanto de largura de banda (a quantidade de dados fornecida por unidade de tempo). nfelizmente, há um grande antagonismo entre esses dois aspectos. Muitas técnicas para aumentar a largura de banda também aumentam a latência. Por exemplo, as técnicas de pipelining usadas na Mic-3 podem ser aplica- das a um sistema de memória que tenha várias memórias sobrepostas e elas serão manipuladas com eficiência. Lamentavelmente, assim como na Mic-3, isso resulta em maior latência para operações individuais de memória. À medida que aumentam as velocidades de clock do processador, fica cada vez mais difícil prover um sistema de memória capaz de fornecer operandos em um ou dois ciclos de clock. Um modo de atacar esse problema é providenciar caches. Como vimos na Seção 2.2.5, uma cache guarda as palavras de memória usadas mais recentemente em uma pequena memória rápida, o que acelera o acesso a elas. Se uma porcentagem grande o suficiente das palavras de memória estiver na cache, a latência efetiva da memória pode ter enorme redução.
  • 261. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 242 Uma das técnicas mais efetivas para melhorar a largura de banda e também a latência é a utilização de várias caches. Uma técnica básica que funciona com grande eficácia é introduzir uma cache separada para instruções e dados. É possível obter muitos benefícios com caches separadas para instruções e dados, algo que muitas vezes denominamos cache dividida. Primeiro, as operações de memória podem ser iniciadas de modo independente em cada cache, o que efetivamente dobra a largura de banda do sistema de memória. É essa a razão por que faz sentido fornecer duas portas de memória separadas, como fizemos na Mic-1: cada porta tem sua própria cache. Note que cada uma tem acesso independente à memória principal. Hoje, muitos sistemas de memória são mais complicados do que isso, e uma cache adicional, denominada cache de nível 2, pode residir entre as caches de instrução e dados e a memória principal. Na verdade, pode haver três ou mais níveis de cache à medida que se exigem sistemas de memória mais sofisticados. Na Figura 4.37, vemos um sistema com três níveis. O próprio chip da CPU contém uma pequena cache de instrução e uma pequena cache de dados, em geral de 16 KB a 64 KB. Então, há a cache de nível 2, que não está no chip da CPU, mas pode ser incluída no pacote da CPU próxima ao chip da CPU e conectada a ela por um caminho de alta velo- cidade. Em geral, ela é unificada, contendo um misto de dados e instruções. Um tamanho típico para a cache L2 é de 512 KB a 1 MB. A cache de terceiro nível está na placa do processador e consiste em alguns poucos megabytes de SRAM, que é muito mais rápida do que a memória principal DRAM. As caches são em geral inclusivas, sendo que o conteúdo total da de nível 1 está na de nível 2 e todo o conteúdo da cache de nível 2 está na de nível 3. Figura 4.37 Sistema com tre s n veis de cache. Placa do processador Pacote da CPU Chip da CPU Controlador de teclado Controlador gráco Controlador de disco Memória principal (DRAM) L1-I L1-D Cache L2 unicada Cache L3 unicada Caches L1 divididas de instrução e dados Cache de nível de placa (SRAM) Caches dependem de dois tipos de endereço de localidade para cumprir seu objetivo. Localidade espacial é a observação de que localizações de memória com endereços numericamente similares a uma localização de memória cujo acesso foi recente provavelmente serão acessadas no futuro próximo. Caches exploram essa pro- priedade trazendo mais dados do que os requisitados, na expectativa de poder antecipar requisições futuras. Localidade temporal ocorre quando localizações de memória recentemente acessadas são acessadas outra vez. sso pode ocorrer, por exemplo, com localizações de memórias próximas ao topo da pilha, ou com instruções dentro de um laço. A localidade temporal é explorada em projetos de cache, principalmente pela escolha do que descartar quando ocorre uma ausência na cache. Muitos algoritmos de substituição de cache exploram a locali- dade temporal descartando as entradas que não tiveram acesso recente. Todas as caches usam o modelo a seguir. A memória principal é dividida em blocos de tamanho fixo, designa- dos linhas de cache. Uma linha típica consiste em 4 a 64 bytes consecutivos. As linhas são numeradas em sequên- cia, começando em 0; portanto, se tivermos uma linha de 32 bytes de tamanho, a linha 0 vai do byte 0 ao byte 31, a linha 1 do byte 32 ao 63, e assim por diante. Em qualquer instante, algumas linhas estão na cache. Quando
  • 262. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 243 a memória é referenciada, o circuito de controle da cache verifica se a palavra referenciada está nela naquele instante. Caso positivo, o valor que ali está pode ser usado, evitando uma viagem até a memória principal. Se a palavra não estiver lá, alguma linha de entrada é removida da cache e a linha necessária é buscada na memória ou na cache de nível mais baixo para substituí-la. Existem muitas variações desse esquema, mas em todas elas a ideia é manter as linhas mais utilizadas na cache o quanto possível, para maximizar o número de referências à memória satisfeitas pela cache. Caches de mapeamento direto A cache mais simples é conhecida como cache de mapeamento direto. Um exemplo de cache de mapeamento direto de um só nível é mostrado na Figura 4.38(a). Esse exemplo contém 2.048 entradas. Cada entrada (linha) pode conter exatamente uma linha de cache da memória principal. Se a linha tiver 32 bytes de tamanho, para esse exemplo, a cache pode conter 2.048 entradas de 32 bytes, ou 64 KB no total. Cada entrada de cache consiste em três partes: 1. O bit Valid indica se há ou não quaisquer dados válidos nessa entrada. Quando o sistema é iniciado, todas as entradas são marcadas como inválidas. 2. O campo Tag consiste em um único valor de 16 bits que identifica a linha de memória correspondente da qual vieram os dados. 3. O campo Data contém uma cópia dos dados na memória. Ele contém uma linha de cache de 32 bytes. Figura 4.38 (a) Cache de mapeamento direto. (b) Enderec o virtual de 32 bits. Valid Entrada 2047 Tag Data Endereços que usam essa entrada (a) (b) Bits 16 11 3 2 TAG LINE WORD BYTE 65504-65535, 131040-131071, … 96-127, 65632-65663, 131168-131199 64-95, 65600-65631, 131136-131167, … 32-63, 65568-65599, 131104-131135, … 0-31, 65536-65567, 131072-131103, … 7 6 5 4 3 2 1 0 Em uma cache de mapeamento direto, uma determinada palavra de memória pode ser armazenada em exa- tamente um lugar dentro da cache. Dado um endereço de memória, há somente um lugar onde procurar por ele. Se não estiver nesse lugar, então ele não está na cache. Para armazenar e recuperar dados da cache, o endereço é desmembrado em quatro componentes, como ilustra a Figura 4.38(b):
  • 263. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 244 1. O campo TAG corresponde aos bits Tag armazenados em uma entrada de cache. 2. O campo LINE indica qual entrada de cache contém os dados correspondentes, se eles estiverem presentes. 3. O campo WORD informa qual palavra dentro de uma linha é referenciada. 4. O campo BYTE em geral não é usado, mas se for requisitado apenas um byte, ele informa qual byte dentro da palavra é necessário. Para uma cache que fornece apenas palavras de 32 bits, esse campo será sempre 0. Quando a CPU produz um endereço de memória, o hardware extrai os 11 bits LINE do endereço e os utiliza para indexá-lo na cache para achar uma das 2.048 entradas. Se essa entrada for válida, o campo TAG do endereço de memória e o campo Tag na entrada da cache são comparados. Sendo compatíveis, a entrada de cache contém a palavra que está sendo requisitada, uma situação denominada presença na cache. Se ocorrer uma presença na cache, uma palavra que está sendo lida pode ser pega, eliminando a necessidade de ir até a memória. Somente a palavra necessária é extraída da entrada da cache. O resto da entrada não é usado. Se a entrada for inválida ou os tags não forem compatíveis, a entrada necessária não está presente, uma situação denominada ausência da cache. Nesse caso, a linha de cache de 32 bytes é buscada na memória e armazenada na linha da cache, substituindo o que lá estava. Contudo, se a linha de cache existente sofreu modificação desde que foi carregada, ela deve ser escrita de volta na memória principal antes de ser sobrescrita. A despeito da complexidade da decisão, o acesso à palavra necessária pode ser extraordinariamente rápido. Assim que o endereço for conhecido, a exata localização da palavra é conhecida, se ela estiver presente na cache. sso significa que é possível ler a palavra da cache e entregá-la ao processador ao mesmo tempo em que está sendo determinado se essa é a palavra correta (por comparação de tags). Portanto, na verdade o processador recebe uma palavra da cache simultaneamente ou talvez até antes de saber se essa é a palavra requisitada. Esse esquema de mapeamento põe linhas de memória consecutivas em linhas de cache consecutivas. De fato, até 64 KB de dados contíguos podem ser armazenados na cache. Contudo, quando a diferença entre o endereço de duas linhas for exatamente 64 KB (65.536 bytes) ou qualquer múltiplo inteiro desse número, elas não podem ser armazenadas na cache ao mesmo tempo (porque têm o mesmo valor de LINE). Por exemplo, se um programa acessar dados na localização X e em seguida executar uma instrução que precisa dos dados na localização X + 65.536 (ou em qualquer outra localização dentro da mesma linha), a segunda instrução forçará a linha de cache a ser recarregada, sobrescrevendo o que lá estava. Se isso acontecer com certa frequência, pode resultar em mau desempenho. Na verdade, o pior comportamento possível de uma cache é ainda pior do que se não houvesse nenhuma, já que cada operação de memória envolve ler uma linha de cache inteira em vez de apenas uma palavra. Caches de mapeamento direto são as mais comuns e funcionam com bastante eficácia, porque com elas é possível fazer colisões como a descrita ocorrerem apenas raramente, ou nunca ocorrerem. Por exemplo, um com- pilador muito esperto pode levar em conta as colisões de cache quando colocar instruções e dados na memória. Note que o caso particular descrito não ocorreria em um sistema com caches de instruções e dados separados, porque as requisições conflitantes seriam atendidas por caches diferentes. Assim, vemos um segundo benefício de ter duas caches em vez de uma: mais flexibilidade para lidar com padrões de memória conflitantes. Caches associativas de conjunto Como já dissemos, muitas linhas diferentes competem na memória pelas mesmas posições na cache (cache slots). Se um programa que utiliza a cache da Figura 4.38(a) usar muito as palavras nos endereços 0 e 65.536, haverá conflitos constantes porque cada referência potencialmente expulsaria a outra. Uma solução para esse problema é permitir duas ou mais linhas em cada entrada de cache. Uma cache com n entradas possíveis para cada endereço é denominada uma cache associativa de conjunto de n vias. Uma cache associativa de conjunto de quatro vias é ilustrada na Figura 4.39.
  • 264. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 245 Figura 4.39 Cache associativa de conjunto de quatro vias. Valid Tag Data 2047 7 6 5 4 3 2 1 0 Entrada A Valid Tag Data Entrada B Valid Tag Data Entrada C Valid Tag Data Entrada D Uma cache associativa de conjunto é inerentemente mais complicada do que uma de mapeamento direto porque, embora a linha de cache correta a examinar possa ser calculada do endereço de memória que está sendo referenciado, um conjunto de n linhas de cache deve ser verificado para ver se a palavra necessária está presente. Ainda assim, a experiência mostra que caches de duas vias e de quatro vias funcionam bem o suficiente para que esses circuitos extras valham a pena. A utilização de caches associativas de conjunto oferece uma opção ao projetista. Quando uma nova linha deve ser trazida para dentro da cache, qual dos itens nela presentes deve ser descartado? É claro que a decisão ideal requer uma olhadela no futuro, mas um algoritmo muito bom para a maioria das finalidades é o LRU (Least Recently Used  usado menos recentemente). Esse algoritmo mantém uma ordenação de cada conjunto de loca- lizações que poderia ser acessado de uma determinada localização de memória. Sempre que qualquer das linhas presentes é acessada, ele atualiza a lista, marcando aquela entrada como a mais recentemente acessada. Quando chega a hora de substituir uma entrada, a que está no final da lista (aquela acessada menos recentemente) é a descartada. Levada ao extremo, uma cache de 2.048 vias que contém 2.048 linhas de entrada também é possível. Nesse caso, todos os endereços de memória mapeiam para um único conjunto, portanto, a consulta requer comparar o endereço contra todos os 2.048 tags na cache. Note que agora cada entrada deve ter lógica de compatibilização de tag. isto que o campo LINE tem comprimento 0, o campo TAG é o endereço inteiro, exceto para os campos WORD e BYTE. Além do mais, quando uma linha de cache é substituída, todas as 2.048 localizações são possíveis candidatas a substituição. Manter uma lista ordenada de 2.048 linhas requer muita contabilidade, o que torna a substituição da LRU inviável. (Lembre-se de que essa lista tem de ser atualizada a cada operação de memória, e não apenas quando ocorre uma ausência na cache.) O surpreendente é que caches de alto grau de associatividade não melhoram muito o desempenho em relação às de baixo grau sob a maioria das circunstâncias e, em alguns casos, até funcionam pior. Por essas razões, a associatividade de conjunto além de quatro vias é relativamente incomum. Por fim, escritas propõem um problema especial para as caches. Quando um processador escreve uma palavra e a palavra está na cache, é óbvio que ele tem de atualizar a palavra ou descartar a entrada da cache. Praticamente todos os modelos atualizam a cache. Mas, e quanto a atualizar a cópia na memória principal? Essa operação pode ser adiada até mais tarde, quando a linha de cache estiver pronta para ser substituída pelo algoritmo LRU. Essa escolha é difícil, e nenhuma das opções é claramente preferível. A atualização imediata da entrada na memória principal é denominada escrita direta (write through). Essa abordagem geralmente é mais simples de realizar e mais confiável, uma vez que a memória está sempre atualizada – é útil, por exemplo, se ocorrer um erro e for necessário recuperar o estado da memória. nfelizmente, também requer mais tráfego de escrita para a memória,
  • 265. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 246 portanto, execuções mais sofisticadas tendem a empregar a alternativa, conhecida como escrita retardada (write deferred) ou escrita retroativa (write back). Há um problema relacionado com as escritas que é preciso atacar: e se ocorrer uma escrita para uma loca- lização que não está na cache naquele momento? Os dados devem ser trazidos para dentro da cache ou apenas escritos na memória? Mais uma vez, nenhuma das respostas é sempre a melhor. A maioria dos projetos que retar- dam escritas para a memória tende a trazer os dados para dentro quando há uma ausência de escrita, uma técnica conhecida como alocação de escrita. Por outro lado, a maioria dos projetos que empregam escrita direta tende a não alocar uma linha em uma escrita porque essa opção complica um projeto que, quanto ao mais, seria simples. Alocação de escrita é melhor apenas se houver escritas repetidas para a mesma palavra ou palavras diferentes dentro de uma linha de cache. O desempenho da cache é crítico para o desempenho do sistema porque a defasagem entre a velocidade da CPU e a da memória é muito grande. Por conseguinte, a pesquisa de melhores estratégias de caching ainda é um tópico muito discutido (Sanchez e Kozyrakis, 2011; e Gaur et al., 2011). 4.5.2 Previsa o de desvio Computadores modernos têm alto grau de pipelining. O pipeline da Figura 4.36 tem sete estágios; computa- dores de última geração às vezes têm dez estágios ou até mais. O pipeline funciona melhor com código linear, de modo que a unidade de busca pode apenas ler palavras consecutivas da memória e as enviar para a unidade de decodificação antes de haver necessidade delas. O único problema com esse maravilhoso modelo é que ele não é nem um pouco realista. Programas não são sequências de código linear – estão repletos de instruções de desvio. Considere as declarações simples da Figura 4.40(a). Uma variável, i, é comparada com 0 (provavelmente o teste mais comum na prática). Dependendo do resultado, um de dois valores possíveis é atribuído a outra variável, k. Figura 4.40 (a) Fragmento de programa. (b) Sua traduc a o para uma linguagem de montagem gene rica. if (i == 0) CMP i,0 ; compare i com 0 k = 1 BNE Else ; ; Desvie se for diferente else Then: MOV k,1 ; Mova 1 para k k = 2 BR Next ; ; Desvio incondicional Else: MOV k,2 ; Mova 2 para k Next: (a) (b) Uma tradução possível para a linguagem de montagem é mostrada na Figura 4.40(b). Estudaremos a lingua- gem de montagem mais adiante neste livro e os detalhes não são importantes agora, mas, dependendo da máquina e do compilador, é provável que haja um código mais ou menos como o da Figura 4.40(b). A primeira instrução compara i com 0. A segunda desvia para o rótulo Else (o início de uma cláusula else) se i não for 0. A terceira instrução atribui 1 a k. A quarta desvia para saltar a próxima declaração. O compilador convenientemente colocou ali um rótulo, Next, portanto, há um lugar para o qual desvia. A quinta instrução atribui 2 a k. Nesse caso, devemos observar que duas das cinco instruções são desvios. Além do mais, uma delas, BNE, é um desvio condicional (tomado se, e somente se, alguma condição for cumprida, nesse caso, que os dois operan- dos da CMP anterior não sejam iguais). A sequência de código linear mais longa no caso são duas instruções. Por conseguinte, buscar instruções a alta velocidade para alimentar o pipeline é muito difícil. À primeira vista, pode parecer que desvios incondicionais, como a instrução BR Next na Figura 4.40(b), não são um problema. Afinal, não há nenhuma ambiguidade sobre aonde ir. Por que a unidade de busca não pode apenas continuar a ler as instruções a partir do endereço visado (o lugar para onde o desvio levará)?
  • 266. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 247 O problema está na natureza do pipelining. Na Figura 4.36, por exemplo, vemos que a decodificação da ins- trução ocorre no segundo estágio. Assim, a unidade de busca tem de decidir de onde buscar em seguida antes de saber que tipo de instrução acabou de obter. Somente um ciclo mais tarde ela pode saber que acabou de pegar um desvio incondicional e, a essa altura, já começou a buscar a instrução que vem após esse desvio. Por conseguinte, um número substancial de máquinas com pipeline (como a UltraSPARC) tem a seguinte propriedade: a instru- ção seguinte a um desvio incondicional é executada, ainda que logicamente não devesse ser. A posição após um desvio é denominada posição de retardo (delay slot). O Core i7 (e a máquina usada na Figura 4.40(b)) não tem essa propriedade, mas a complexidade interna para contornar o problema costuma ser enorme. Um compilador otimizador tentará encontrar alguma instrução útil para colocar na posição de retardo, mas com frequência não há nada disponível, então, ele é forçado a inserir ali uma instrução NOP. Assim, o programa fica correto, mas também maior e mais lento. Por mais que desvios incondicionais sejam irritantes, os desvios condicionais são piores. Além de também terem posições de retardo, agora a unidade de busca não sabe de onde ler até muito mais adiante no pipeline. As primeiras máquinas com pipeline apenas protelavam até saberem se o desvio seria tomado ou não. Uma protelação de três ou quatro ciclos em cada desvio condicional, em especial se 20% das instruções forem desvios condicio- nais, arrasa o desempenho. Por conseguinte, o que a maioria das máquinas faz quando chega a um desvio condicional é prever se ele vai ser tomado ou não. Seria maravilhoso se pudéssemos apenas ligar uma bola de cristal em um encaixe PC livre para ajudar na previsão, mas até agora essa abordagem não deu frutos. Na falta de tal periférico, foram arquitetadas várias maneiras de fazer a previsão. Um modo muito simples é o seguinte: considere que todos os desvios condicionais para trás serão tomados e todos os desvios para frente não serão tomados. O raciocínio que fundamenta a primeira parte é que os desvios para trás costumam estar localizados no final de um laço. A maioria dos laços é executada várias vezes, portanto, prever que um desvio de volta ao início do laço será tomado, em geral é um bom palpite. A segunda parte é mais tumultuada. Alguns desvios para frente ocorrem quando são detectadas condições de erro em software (por exemplo, um arquivo não pode ser aberto). Erros são raros, portanto, quase todos os desvios associados a eles não são tomados. É claro que há uma grande quantidade de desvios para frente que não estão relacionados com o tratamento de erros, portanto, a taxa de sucesso não é tão boa quanto a dos desvios para trás. Embora não seja fantástica, essa regra é, no mínimo, melhor do que nada. Se um desvio for previsto corretamente, não há nada de especial a fazer. A execução apenas continua no endereço de destino. O problema começa quando o desvio é previsto de forma errada. maginar para onde ir e ir para lá não é difícil. A parte difícil é desfazer as instruções que já foram executadas e não deveriam ter sido. Há dois modos de resolver isso. O primeiro é permitir que as instruções buscadas após um desvio con- dicional previsto executem até que tentem mudar o estado da máquina (por exemplo, armazenando em um registrador). Em vez de sobrescrever o registrador, o valor calculado é colocado em um registrador transitório (secreto) e somente copiado para o registrador real após saber que a previsão estava correta. O segundo é registrar o valor de qualquer registrador que esteja pronto para ser sobrescrito – por exemplo, em um registrador transi- tório secreto –, de modo que a máquina possa ser levada de volta ao estado em que estava no momento em que tomou o desvio mal previsto. Ambas as soluções são complexas e requerem contabilidade de nível industrial para conseguir efetuá-las direito. Além do mais, se um segundo desvio condicional for atingido antes de se saber se a previsão do primeiro estava correta, as coisas podem ficar complicadas de fato. Previsa o dina mica de desvios Claro que previsões exatas têm grande valor, uma vez que permitem que a CPU funcione a toda velocidade. Como consequência, grande parte da pesquisa em curso tem como objetivo melhorar algoritmos de previsão de desvio (Chen et al., 2003; Falcon et al., 2004; Jimenez, 2003; e Parikh et al., 2004). Uma abordagem é a CPU man- ter uma tabela histórica (em hardware especial) na qual registra desvios condicionais à medida que eles ocorrem, de modo que eles possam ser consultados quando ocorrerem novamente. A versão mais simples desse esquema
  • 267. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 248 é mostrada na Figura 4.41(a). Nesse exemplo, a tabela histórica contém uma linha para cada instrução de desvio condicional. A linha contém o endereço da instrução de desvio junto com um bit que informa se ele foi tomado da última vez que foi executado. Usando esse esquema, a previsão é apenas que o desvio irá para o mesmo lugar da última vez. Se a previsão estiver errada, o bit na tabela de histórico é alterado. Figura 4.41 (a) Histo rico de desvio de 1 bit. (b) Histo rico de desvio de 2 bits. (c) Mapeamento entre enderec o de instruc a o de desvio e enderec o de destino. Válido 6 5 4 3 2 1 0 Desvio/ nenhum Posição Endereço/tag do desvio Posição Endereço/tag do desvio Posição Endereço/tag do desvio Endereço de destino (a) Válido 6 5 4 3 2 1 0 Bits de previsão (c) Válido 6 5 4 3 2 1 0 Bits de previsão (b) Há diversos modos de organizar a tabela de histórico. Na verdade, são exatamente os mesmos modos usa- dos para organizar uma cache. Considere uma máquina com instruções de 32 bits que são alinhadas por palavra de modo que os 2 bits de ordem baixa de cada endereço de memória sejam 00. Com uma tabela de histórico de mapeamento direto que contém 2n entradas, os n + 2 bits de ordem baixa de uma instrução de desvio podem ser extraídos e deslocados 2 bits para a direita. Esse número de n bits pode ser usado como um índice para a tabela de histórico, onde é feita uma verificação para ver se o endereço ali armazenado é compatível com o endereço do desvio. Como acontece com uma cache, não há necessidade de armazenar os n + 2 bits de ordem baixa, portanto, eles podem ser omitidos (isto é, somente os bits mais altos de endereço – o tag – são armazenados). Se houver compatibilidade, ou seja, uma presença na tabela, o bit de previsão é usado para prever o desvio. Se o tag errado estiver presente ou a entrada for inválida, ocorre uma ausência na tabela (ou não há compatibilidade), exatamente como na cache. Nesse caso, pode ser usada a regra do desvio para frente e para trás. Se a tabela de histórico de desvio tiver, por exemplo, 4.096 entradas, então os desvios nos endereços 0, 16384, 32768, ... serão conflitantes, um problema semelhante ao que encontramos na cache. A mesma solução é possível: uma entrada associativa de duas vias, quatro vias ou n vias. Assim como para a cache, o caso limite é uma única entrada associativa de n vias, que requer associatividade total de consulta. Dada uma tabela de tamanho suficiente e suficiente associatividade, esse esquema funciona bem na maioria das situações. Contudo, sempre ocorre um problema sistemático. Quando por fim se atingir a saída de um laço, é feita uma previsão errada para o desvio e, pior ainda, a má previsão mudará o bit na tabela de histórico para indicar uma futura previsão de “nenhum desvio”. Na próxima vez que se entrar no laço, haverá uma previsão errada de desvio ao final da primeira iteração. Se o laço estiver dentro de um laço externo, ou dentro de um pro- cedimento que é chamado muitas vezes, esse erro pode acontecer com frequência. Para eliminar essa má previsão, podemos dar uma segunda chance à entrada da tabela. Por tal método, a previsão só é alterada após duas previsões incorretas. Essa abordagem requer dois bits de previsão na tabela de histórico, um para o que o desvio “deve” fazer e um para o que fez da última vez, como mostra a Figura 4.41(b). Um modo ligeiramente diferente de considerar esse algoritmo é vê-lo como uma máquina de estado finito de quatro estados, como ilustra a Figura 4.42. Após uma série de previsões sucessivas certas de “nenhum desvio”, a FSM estará no estado 00 e preverá “nenhum desvio” na próxima vez. Se essa previsão estiver errada, ela passará
  • 268. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 249 para o estado 01, mas preverá “nenhum desvio” também na proxima vez. Só se essa previsão estiver errada, ela pas- sará agora para o estado 11 e preverá desvios o tempo todo. Na verdade, o bit da extrema esquerda do estado é a previsão e o da extrema direita é o que o desvio fez da última vez. Embora esse projeto use apenas 2 bits para o histórico, um projeto que monitora 4 ou 8 bits de histórico também é possível. Figura 4.42 Ma quina de estado finito de 2 bits para previsa o de desvio. Nenhum desvio Desvio Desvio 00 Nenhum desvio Prever nenhum desvio 01 Prever nenhum desvio uma vez 10 Prever desvio mais uma vez Desvio Nenhum desvio Desvio Nenhum desvio 11 Prever desvio Essa não é nossa primeira FSM. A Figura 4.28 também era uma FSM. Na realidade, todos os nossos micro- programas podem ser considerados FSMs, uma vez que cada linha representa um estado específico no qual a máquina pode estar, com transições bem definidas para um conjunto finito de outros estados. FSMs são muito usadas em todos os aspectos do projeto de hardware. Até aqui, consideramos que o alvo de cada desvio condicional era conhecido, ou como um endereço explícito para o qual desviar (contido dentro da própria instrução), ou como um deslocamento relativo com referência à ins- trução corrente (isto é, um número com sinal para adicionar ao contador de programa). Muitas vezes, essa suposição é válida, mas algumas instruções de desvio calculam o endereço de destino efetuando a aritmética nos registradores e então se dirigem para aquele endereço. Mesmo que a FSM da Figura 4.42 preveja com exatidão que o desvio será tomado, essa previsão de nada serve se o endereço de destino for desconhecido. Um modo de lidar com essa situa- ção é armazenar na tabela de histórico o endereço ao qual o desvio se dirigiu da última vez, como mostra a Figura 4.41(c). Desse modo, se a tabela informar que da última vez que o desvio no endereço 516 foi tomado ele foi para o endereço 4.000, se a previsão agora for “desvio”, a suposição de trabalho será um desvio para 4.000 novamente. Uma abordagem diferente para a previsão de desvio é monitorar se os últimos k desvios condicionais encon- trados foram tomados, pouco importando quais instruções eram. Esse número de k bits, mantido no registrador de deslocamento da tabela de histórico, é então comparado em paralelo com todas as entradas de uma tabela de histórico que tenham uma chave de k bits e, se ocorrer um sucesso, a previsão encontrada será usada. Por mais surpreendente que seja, essa técnica funciona bastante bem. Previsa o esta tica de desvio Todas as técnicas de previsão de desvio discutidas até agora são dinâmicas, isto é, são realizadas em tempo de execução, durante a execução do programa. Elas também se adaptam ao comportamento corrente do programa, o que é bom. A desvantagem é que elas requerem hardware especializado e caro e muita complexidade no chip. Um modo diferente de trabalhar é fazer com que o compilador ajude. Quando o compilador vir uma decla- ração como for (i = 0; i < 1000000; i++) { ... }
  • 269. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 250 ele sabe muito bem que o desvio no final do laço será tomado quase toda vez. Se ao menos houvesse um meio de ele informar ao hardware, muito esforço seria poupado. Embora seja uma alteração de arquitetura, e não apenas uma questão de execução, algumas máquinas, como a UltraSPARC , têm um segundo conjunto de instruções de desvio condicional, além das normais, que são necessárias por compatibilidade. As novas contêm um bit no qual o compilador pode especificar que ele acha que o desvio será tomado (ou não tomado). Quando uma dessas é encontrada, a unidade de busca apenas faz o que lhe disseram para fazer. Além do mais, não há necessidade de desperdiçar precioso espaço da tabela de histórico de desvios com essas instruções, reduzindo assim o conflito que ali acontece. Por fim, nossa última técnica de previsão de desvio é baseada na determinação de perfil (Fisher e Freudenberger, 1992). Essa também é uma técnica estática, mas em vez de fazer o compilador tentar adivinhar quais desvios serão tomados e quais não serão, o programa é executado (normalmente em um simulador) e o comportamento do desvio é capturado. Essa informação é alimentada no compilador, que então usa as instruções de desvio condicional especial para informar ao hardware o que ele deve fazer. 4.5.3 Execuc a o fora de ordem e renomeac a o de registrador Grande parte das CPUs modernas tem pipeline e também são superescalares, conforme mostra a Figura 2.6. Em geral, isso significa que há uma unidade de busca que retira palavras de instrução da memória antes que elas sejam necessárias, para alimentar uma unidade de decodificação. Esta emite as instruções decodificadas para as unidades funcionais adequadas para execução. Em alguns casos, ela pode desmembrar instruções individuais em micro- -operações antes de emiti-las para as unidades funcionais, dependendo do que as unidades funcionais podem fazer. Claro que o projeto da máquina é mais simples se as instruções forem executadas na ordem em que são buscadas (considerando, por enquanto, que o algoritmo de previsão de desvio nunca faça uma previsão errada). Contudo, a execução em ordem nem sempre resulta em desempenho ideal, devido às dependências entre instru- ções. Se uma instrução precisar de um valor calculado pela anterior, a segunda não pode começar a executar até que a primeira tenha produzido o valor necessário. Nessa situação (uma dependência RAW), a segunda instrução tem de esperar. Também existem outros tipos de dependência, como veremos em breve. Em uma tentativa de contornar esses problemas e produzir melhor desempenho, algumas CPUs permitem saltar instruções dependentes para chegar a instruções futuras que não são dependentes. Não é preciso dizer que o algoritmo de escalonamento de instruções internas usado deve causar o mesmo efeito que causaria se o programa fosse executado na ordem escrita. Agora, demonstraremos como a reordenação de instruções funciona usando um exemplo detalhado. Para ilustrar a natureza do problema, começaremos com uma máquina que sempre emite instruções na ordem do programa e também requer que sua execução seja concluída na ordem do programa. A significância dessa última exigência ficará clara mais adiante. Nosso exemplo de máquina tem oito registradores visíveis para o programador, R0 até R7. Todas as instru- ções aritméticas usam três registradores: dois para os operandos e um para o resultado, igual à Mic-4. amos considerar que, se uma instrução for decodificada no ciclo n, a execução inicia no ciclo n + 1. Para uma instrução simples, como uma adição ou subtração, a escrita retroativa no registrador de destino ocorre ao final do ciclo n + 2. Para uma instrução mais complicada, como uma multiplicação, a escrita retroativa ocorre ao final do ciclo n + 3. Para tornar o exemplo realista, permitiremos que a unidade de decodificação emita até duas instruções por ciclo de clock. Há várias CPUs escalares comerciais que podem emitir quatro ou até seis por ciclo de clock. Nosso exemplo de sequência de execução é mostrado na Figura 4.43. Nesse caso, a primeira coluna dá o número do ciclo e a segunda dá o número da instrução. A terceira coluna relaciona a instrução decodificada. A quarta informa qual instrução está sendo emitida (com um máximo de duas por ciclo de clock). A quinta informa qual instrução foi retirada, ou concluída. Lembre-se de que nesse exemplo estamos exigindo emissão em ordem, bem como conclusão em ordem, portanto, a instrução k + 1 não pode ser emitida até que a k tenha sido emitida e a instrução k + 1 não pode ser retirada (ou seja, não pode ser escrita retroativamente no registrador de destino) até que k tenha sido retirada. As outras 16 colunas são discutidas logo adiante.
  • 270. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 251 Figura 4.43 CPU superescalar com emissa o em ordem e conclusa o em ordem. Registradores lidos Registradores escritos Ciclo # Decodificado Emit. Ret. 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 1 R3=R0 *R1 1 1 1 1 2 R4=R0+R2 2 2 1 1 1 1 2 R5=R0+R1 3 3 2 1 1 1 1 4 R6=R1+R4 – 3 2 1 1 1 1 3 3 2 1 1 1 1 1 4 2 1 1 1 1 2 1 1 1 3 4 5 1 1 1 5 R7=R1 *R2 5 2 1 1 1 1 6 R1=R0−R2 – 2 1 1 1 1 4 7 1 1 1 5 8 6 9 1 1 1 7 R3=R3 *R1 – 1 1 1 10 1 1 1 11 6 12 7 1 1 1 8 R1=R4+R4 – 1 1 1 13 1 1 1 14 1 1 1 15 7 16 2 8 1 17 2 1 18 8 6 3 1 Após decodificar a instrução, a unidade de decodificação tem de decidir se pode ou não emiti-la imediata- mente. Para tomar essa decisão, a unidade de decodificação precisa conhecer o estado de todos os registradores. Se, por exemplo, a instrução corrente precisar de um registrador cujo valor ainda não foi calculado, ela não pode ser emitida e a CPU deve protelar. A utilização do registrador será monitorada com um dispositivo denominado tabela de pontuação (score- board), encontrado pela primeira vez no CDC 6600. A tabela tem um pequeno contador para cada registrador, que informa quantas vezes um determinado registrador é usado como uma fonte por instruções que estão sendo executadas naquele momento. Se, por exemplo, o número máximo de instruções que podem ser executadas ao mesmo tempo for 15, então um contador de 4 bits será suficiente. Quando uma instrução é emitida, as entradas da tabela de pontuação para seus registradores de operandos são incrementadas. Quando uma instrução é retirada, as entradas são decrementadas. A tabela de pontuação também tem contadores para monitorar os registradores usados como destino. Uma vez que só é permitida uma escrita por vez, esses contadores podem ter um bit de largura. As 16 colunas da extrema direita na Figura 4.43 mostram a tabela de pontuação. Em máquinas reais, a tabela também monitora a utilização da unidade funcional, para evitar emitir uma instrução para a qual não há nenhuma unidade funcional disponível. Para simplificar, consideraremos que há sempre uma, portanto, não mostraremos as unidades funcionais na tabela de pontuação. A primeira linha da Figura 4.43 mostra 1 (instrução 1), que multiplica R0 por R1 e coloca o resultado em R3. Uma vez que nenhum desses registradores está em uso ainda, a instrução é emitida e a tabela de pontuação é atualizada para refletir que R0 e R1 estão sendo lidos, e R3 está sendo escrito. Nenhuma instrução subsequente
  • 271. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 252 pode escrever para qualquer um deles, nem pode ler R3, até que 1 seja retirada. isto que essa instrução é uma multiplicação, ela será concluída no final do ciclo 4. Os valores da tabela de pontuação mostrados em cada linha refletem seus estados após a emissão da instrução que está naquela linha. Entradas em branco são 0s. isto que nosso exemplo é uma máquina superescalar que pode emitir duas instruções por ciclo, a segunda instrução (2) é emitida durante o ciclo 1. Ela soma R0 e R2 e armazena o resultado em R4. Para ver se essa ins- trução pode ser emitida, são aplicadas as seguintes regras: 1. Se qualquer operando estiver sendo escrito, não emita (dependência RAW). 2. Se o registrador de resultado estiver sendo lido, não emita (dependência WAR). 3. Se o registrador de resultado estiver sendo escrito, não emita (dependência WAW). Já vimos dependências RAW, que ocorrem quando uma instrução precisa usar como fonte um resultado que uma instrução prévia ainda não produziu. As outras duas dependências são menos sérias – são, em essência, conflitos de recursos. Em uma dependência WR (Write fter Read – escrita após leitura), uma instrução está tentando sobrescrever um registrador que uma instrução anterior pode não ter terminado de ler ainda. Uma dependência WW (Write fter Write – escrita após escrita) é parecida. Muitas vezes, elas podem ser evitadas obrigando a segunda instrução a colocar seus resultados em algum outro lugar (talvez temporariamente). Se não existir nenhuma das três dependências citadas e a unidade funcional de que a instrução necessita estiver disponí- vel, a instrução é emitida. Nesse caso, 2 usa um registrador (R0) que está sendo lido por uma instrução pendente, mas essa sobreposição é permitida, portanto, 2 é emitida. De modo semelhante, 3 é emitida durante o ciclo 2. Agora, chegamos à 4, que precisa usar R4. nfelizmente, vemos pela linha 3 que R4 está sendo escrita. Nesse caso, temos uma dependência RAW, portanto, a unidade de decodificação protela até que R4 fique disponível. Durante a protelação, a unidade de decodificação para de retirar instruções da unidade de busca. Quando os buffers internos da unidade de busca estiverem cheios, ela para de fazer a busca antecipada. ale a pena notar que a próxima instrução na ordem do programa, 5, não tem conflitos com nenhuma das instruções pendentes. Ela poderia ter sido decodificada e emitida se não fosse pelo fato de esse projeto exigir que as instruções sejam emitidas em ordem. Agora, vamos ver o que acontece durante o ciclo 3. 2, por ser uma adição (dois ciclos), termina no final do ciclo 3. nfelizmente, ela não pode ser retirada (e liberar R4 para 4). Por que não? A razão é que esse projeto também requer retirada em ordem. Por quê? Que mal poderia acontecer por fazer o armazenamento em R4 agora e marcá-lo como disponível? A resposta é sutil, mas importante. Suponha que instruções pudessem concluir fora de ordem. Então, se ocorresse uma interrupção, seria muito difícil salvar o estado da máquina de modo que ele pudesse ser restaura- do mais tarde. Em particular, não seria possível afirmar que todas as instruções até algum endereço tinham sido executadas e que todas as instruções depois dele, não. Essa característica é denominada interrupção exata e é desejável em uma CPU (Moudgill e assiliadis, 1996). A retirada fora de ordem torna as interrupções inexatas, e é por isso que algumas máquinas requerem conclusão de instrução em ordem. oltando a nosso exemplo, no final do ciclo 4, todas as três instruções pendentes podem ser retiradas, portanto, 4 pode ser enfim emitida no ciclo 5, junto com a 5 recém-decodificada. Sempre que uma instrução é retirada, a unidade de decodificação tem de verificar se há uma instrução protelada que agora possa ser emitida. No ciclo 6, 6 é protelada por que ela precisa escrever para R1, mas R1 está ocupado. Por fim, ela é iniciada no ciclo 9. A sequência inteira de oito instruções leva 18 ciclos para ser concluída devido a muitas dependências, ainda que o hardware seja capaz de emitir duas instruções em cada ciclo. Entretanto, note que, ao ler a coluna Emit. da Figura 4.43 de cima para baixo, todas as instruções foram emitidas em ordem. Da mesma forma, a coluna Ret. mostra que elas também foram retiradas na ordem. Agora, vamos considerar um projeto alternativo: execução fora de ordem. Nesse projeto, instruções podem ser emitidas e também podem ser retiradas fora de ordem. A mesma sequência de oito instruções é mostrada na Figura 4.44, só que agora são permitidas emissão fora de ordem e retirada fora de ordem.
  • 272. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 253 Figura 4.44 Operac a o de uma CPU superescalar com emissa o de instruc a o fora de ordem e conclusa o de instruc a o fora de ordem. Registradores lidos Registradores escritos Ciclo # Decodificado Emit. Ret. 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 1 R3=R0 *R1 1 1 1 1 2 R4=R0+R2 2 2 1 1 1 1 2 R5=R0+R1 3 3 2 1 1 1 1 4 R6=R1+R4 – 3 2 1 1 1 1 3 1 3 4 5 6 7 8 9 R7=R1*R2 5 3 3 2 1 1 1 1 6 4 3 3 1 1 1 1 2 3 3 2 1 1 1 4 3 4 2 1 1 1 1 1 – 3 4 2 1 1 1 1 1 8 3 4 2 3 1 1 1 1 1 2 3 2 3 1 1 1 3 1 2 2 3 1 1 6 2 1 3 1 1 1 7 2 1 1 3 1 1 1 1 4 1 1 1 2 1 1 1 5 1 2 1 1 8 1 1 1 1 1 1 7 5 6 7 8 S1=R0–R2 R3=R3 S1 S2=R4+R4 * A primeira diferença ocorre no ciclo 3. Ainda que 4 tenha sido protelada, temos permissão para decodificar e emitir 5, uma vez que ela não conflita com qualquer instrução pendente. Contudo, saltar instruções causa um novo problema. Suponha que 5 tenha usado um operando calculado pela instrução que foi saltada, 4. Com a tabe- la de pontuação corrente, não teríamos notado isso. Por conseguinte, temos de estender a tabela para monitorar os armazenamentos feitos por instruções que foram saltadas. sso pode ser feito adicionando um segundo mapa de bits, 1 bit por registrador, para monitorar armazenamentos feitos por instruções proteladas. (Esses contadores não são mostrados na figura.) Agora, a regra de emissão tem de ser estendida para evitar a emissão de qualquer instru- ção que tenha um operando escalonado para ser armazenado por uma instrução que veio antes, mas que foi saltada. amos voltar e examinar 6, 7 e 8 na Figura 4.43. Nela, vemos que 6 calcula um valor em R1 que é usado por 7. Contudo, vemos também que o valor nunca é usado de novo porque 8 sobrescreve R1. Não há nenhuma razão real para usar R1 como o lugar para conter o resultado de 6. Pior ainda, R1 é uma péssima escolha de registrador intermediário, embora seja perfeitamente razoável para um compilador ou programador acostumado com a ideia de execução sequencial sem nenhuma sobreposição de instruções. Na Figura 4.44, introduzimos uma nova técnica para resolver esse problema: registrador de renomeação. A sábia unidade de decodificação transfere a utilização de R1 em 6 (ciclo 3) e 7 (ciclo 4) para um registrador secreto, S1, que não é visível para o programador. Agora, 6 pode ser emitida ao mesmo tempo em que 5. CPUs modernas costumam ter dezenas de registradores secretos para usar com renomeação de registrador. Essa técnica muitas vezes pode eliminar dependências WAR e WAW. Em 8, usamos outra vez a renomeação de registrador. Desta vez, R1 é renomeado para S2, de modo que a adição pode ser iniciada antes que R1 esteja livre, no final do ciclo 6. Se acaso o resultado realmente tiver de estar em R1 desta vez, o conteúdo de S2 sempre pode ser copiado de volta para lá a tempo. Melhor ainda, todas as futuras instruções que precisem dele podem ter suas fontes renomeadas para o registrador onde elas de fato estão armazenadas. Seja como for, desse modo a adição 8 conseguiu começar mais cedo. Em muitas máquinas reais, a renomeação está profundamente embutida no modo como os registradores são organizados. Há muitos registradores secretos e uma tabela que mapeia os registradores visíveis ao programador para os registradores secretos. Assim, o registrador real que está sendo usado para, por exemplo, R0, é localizado
  • 273. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 254 examinando-se a entrada 0 dessa tabela de mapeamento. Desse modo, não existe nenhum registrador real R0, mas apenas uma vinculação entre o nome R0 e um dos registradores secretos. Essa vinculação muda muitas vezes durante a execução, para evitar dependências. Note que, na Figura 4.44, quando lemos a quarta coluna de cima para baixo, as instruções não foram emiti- das em ordem. Tampouco foram retiradas em ordem. A conclusão desse exemplo é simples: usando a execução fora de ordem e a renomeação de registrador, podemos acelerar o cálculo por um fator de dois. 4.5.4 Execuc a o especulativa Na seção anterior, introduzimos o conceito de reordenação de instruções de modo a melhorar o desempe- nho. Embora não o tenhamos mencionado explicitamente, o foco estava sobre a reordenação de instruções dentro de um único bloco básico. Agora, está na hora de examinar essa questão mais de perto. Programas de computador podem ser desmembrados em blocos básicos, em que cada um consiste em uma sequência linear de código com um ponto de entrada no início e uma saída no final. Um bloco básico não con- tém qualquer estrutura de controle (por exemplo, instruções if ou declarações while), de modo que sua tradução para linguagem de máquina não contém nenhum desvio. Os blocos básicos são conectados por declarações de controle. Um programa nessa forma pode ser representado por um gráfico orientado, conforme mostra a Figura 4.45. Nesse exemplo, calculamos as somas dos cubos dos inteiros pares e ímpares até algum limite e as acumulamos em evensum e oddsum, respectivamente. Dentro de cada bloco básico, as técnicas de reordenação da seção anterior funcionam bem. Figura 4.45 (a) Fragmento de programa. (b) Gra fico de blocos ba sicos correspondente. evensum = 0; oddsum = 0; i = 0; while (i < limit) { k = i * i * i; k = i * i * i; if (((i/2) * 2) == i) evensum = evensum + k; else oddsum = oddsum + k; } (a) (b) evensum = 0; oddsum = 0; i = 0; while (i < limit) if (((i/2) * 2) == i) T F evensum = evensum + k; oddsum = oddsum + k; i = i + 1; i = i + 1; i >= limit O problema é que a maioria dos blocos básicos é curta e não há paralelismo suficiente para explorá-los de modo efetivo. Por conseguinte, a próxima etapa é permitir que a reordenação cruze as fronteiras de blocos básicos na tentativa de preencher todas as posições de emissão. Os maiores ganhos ocorrem quando uma operação poten- cialmente lenta pode ser passada para cima no gráfico para ser iniciada mais cedo. Essa instrução pode ser uma instrução LOAD, uma operação de ponto flutuante ou até mesmo o início de uma longa cadeia de dependência. A transferência de um código para cima através de um desvio é denominada elevação.
  • 274. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 255 magine que, na Figura 4.45, todas as variáveis fossem mantidas em registradores, exceto evensum e oddsum, por falta de registradores. Portanto, talvez fizesse sentido passar suas instruções LOAD para o topo do laço antes de calcular k, para iniciá-las cedo, de modo que os valores estarão disponíveis quando necessários. Claro que somente uma delas será necessária em cada iteração, portanto, a outra LOAD será desperdiçada, mas se a cache e a memória tiverem pipelining e houver posições de emissão disponíveis, talvez ainda valesse a pena fazer isso. A execução de código antes mesmo de saber se ele será necessário é denominada execução especulativa. Usar essa técnica requer suporte do compilador e do hardware, bem como algumas extensões na arquitetura. Em geral, reordenar instruções atravessando fronteiras de blocos básicos está além da capacidade do hardware, portanto, o compilador deve mover as instruções explicitamente. A execução especulativa introduz alguns problemas interessantes. Um deles é que nenhuma das instruções especulativas tem resultados irrevogáveis, porque mais tarde pode-se descobrir que elas não deveriam ter sido executadas. Na Figura 4.45, é bom buscar evensum e oddsum, e também é bom efetuar a adição tão logo k esteja disponível (mesmo antes da declaração if), mas não é bom armazenar os resultados de volta na memória. Em sequências de código mais complicadas, um modo comum de evitar que o código especulativo sobrescreva regis- tradores antes de se saber se isso é desejado é renomear todos os registradores de destino usados pelo código especulativo. Desse modo, apenas registradores temporários são modificados, portanto, não há problema algum se, afinal, o código não for necessário. Se o código for necessário, os registradores transitórios são copiados para os verdadeiros registradores de destino. Como você pode imaginar, a tabela de pontuação para monitorar tudo isso não é simples, mas, com hardware suficiente, pode ser feita. Entretanto, há outro problema introduzido pelo código especulativo que não pode ser resolvido por reno- meação de registrador. O que acontece se uma instrução executada por especulação causar uma exceção? Um exemplo doloroso, mas não fatal, é uma instrução LOAD que causa uma ausência da cache em uma máquina cuja linha de cache é de tamanho grande (por exemplo, 256 bytes) e a memória é muito mais lenta do que a CPU e a cache. Se um LOAD que é realmente necessário fizer a máquina parar de vez durante muitos ciclos enquanto a linha de cache está sendo carregada, bom, são coisas da vida, já que a palavra é necessária. Contudo, protelar a máquina para buscar uma palavra que, afinal, não é necessária, é contraproducente. Muitas dessas “otimizações” podem fazer a CPU ficar mais lenta do que se ela não as tivesse. Se a máquina tiver memória virtual, que é dis- cutida no Capítulo 6, um LOAD especulativo pode até causar uma falta de página, o que requer uma operação de disco para trazer a página necessária. Falsas faltas de página podem causar um efeito terrível sobre o desempenho, portanto, é importante evitá-las. Uma solução presente em várias máquinas modernas é inserir uma instrução SPECULATIVE-LOAD que tenta buscar a palavra na cache, mas, se ela não estiver lá, desiste. Se o valor estiver na cache quando for mesmo neces- sário, ele pode ser usado ou não; caso não esteja, o hardware tem de entrar em cena e obtê-lo imediatamente. Se o valor se revelar não necessário, nada de ruim aconteceu pela ausência da cache. Uma situação muito pior pode ser ilustrada com a seguinte declaração: if (x > 0) z = y/x; em que x, y e z são variáveis de ponto flutuante. Suponha que as variáveis são todas buscadas com antecedên- cia para registradores e que a divisão com ponto flutuante (uma operação lenta) é elevada para cima do teste if. nfelizmente, x é 0 e a exceção resultante, isto é, a divisão por zero, encerra o programa. O resultado líquido é que a especulação causou a falha de um programa correto. Pior ainda, o programador inseriu um código explícito para evitar essa situação e, mesmo assim, ela aconteceu. Provavelmente, o programador não ficará feliz com isso. Uma solução possível é ter versões especiais e instruções que poderiam causar exceções. Além disso, um bit denominado bit envenenado é adicionado a cada registrador. Quando uma instrução especulativa especial falhar, em vez de causar uma exceção, ela ajusta o bit envenenado no registrador de resultado. Se mais adiante uma instrução normal chegar a esse registrador, a armadilha ocorre nesse momento (como deveria). Contudo, se o resultado nunca é usado, o bit envenenado mais cedo ou mais tarde é eliminado e não há prejuízo algum.
  • 275. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 256 4.6 Exemplos do n vel de microarquitetura Nesta seção, apresentaremos exemplos resumidos de três processadores de alta tecnologia, mostrando como eles empregam os conceitos explorados neste capítulo. Os exemplos terão que ser breves porque máquinas reais são de uma complexidade enorme, contendo milhões de portas. Os exemplos são os mesmos que usamos até agora: Core i7, OMAP4430 e ATmega168. 4.6.1 A microarquitetura da CPU Core i7 Por fora, o Core i7 parece uma máquina CSC tradicional, com um conjunto de instruções imenso e desajeitado que suporta operações com inteiros de 8, 16 e 32 bits, bem como operações de ponto flutuante de 32 bits e 64 bits. Tem somente oito registradores visíveis por processador e não há dois deles que sejam exatamente iguais. Os com- primentos de instruções variam de 1 a 17 bytes. Resumindo, é uma arquitetura herdada que parece fazer tudo errado. Entretanto, por dentro, contém um núcleo RSC moderno, enxuto e de alto grau de pipelining, que trabalha a uma taxa de clock de extrema rapidez e que provavelmente crescerá nos anos vindouros. É impressionante como os engenheiros da ntel conseguiram construir um processador de última geração para implementar uma arquite- tura antiga. Nesta seção, examinaremos a microarquitetura do Core i7 para ver como ela funciona. Visa o geral da microarquitetura Sandy Bridge do Core i7 A microarquitetura do Core i7, denominada microarquitetura Sandy Bridge, é uma ruptura total em relação às microarquiteturas ntel anteriores, incluindo as antigas P4 e P6. Uma visão geral esquemática da microarqui- tetura do Core i7 é dada na Figura 4.46. Figura 4.46 Diagrama de blocos do Core i7. Para cache L3 compartilhada ULAs de inteiros, unidades de ponto utuante, buffer de armazenamento Cache de micro-operações Renomeação, escalonamento Previsor de desvio Cache de instrução nível 1 Unidade de execução Unidade de retirada Controle de fora de ordem Terminal frontal Cache de dados nível 1 Cache nível 2 (instruções e dados) Interface do sistema Subsistema de memória Unidade de busca/ decodicação O Core i7 consiste em quatro subseções principais: o subsistema de memória, o terminal frontal, o controle de fora de ordem e as unidades de execução. amos examiná-las uma por uma, começando na parte superior esquerda e percorrendo o chip em sentido anti-horário.
  • 276. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 257 Cada processador no Core i7 contém um subsistema de memória com uma cache L2 (de nível 2) unificada, bem como a lógica para acessar a cache L3 (nível 3). Uma única cache L3 grande é compartilhada por todos os processadores, e essa é a última parada antes de sair do chip da CPU e fazer a longa jornada até a RAM externa pelo barramento de memória. As caches L2 do Core i7 têm um tamanho de 256 KB, e cada uma é organizada como uma cache associativa de 8 vias com linhas de 64 bytes. A cache L3 compartilhada varia em tamanho de 1 MB a 20 MB. Se você pagar mais à ntel, terá mais cache em retorno. ndependentemente do seu tamanho, a L3 é organizada como uma cache associativa em 12 vias, com linhas de cache de 64 bytes. Caso haja uma ausência de cache L3, o acesso é enviado à RAM externa por meio do barramento de RAM DDR3. Associada à cache L1 estão duas unidades de busca antecipada (que não aparecem na figura) que tentam buscar dados com antecedência de níveis inferiores do sistema de memória para a cache L1, antes de eles serem necessários. Uma unidade de busca antecipada consulta o próximo bloco de memória quando detecta que um “fluxo” de sequência da memória está sendo buscado para o processador. Um segundo buscador antecipado, mais sofisticado, cuida da sequência de endereços dos loads e stores do programa específico. Se eles prosseguirem a um passo regular (por exemplo, 0x1000... 0x1020... 0x1040...), ele buscará o próximo elemento que provavelmente será acessado de modo antecipado ao programa. Essa pré-busca orientada a passo faz maravilhas para programas que estão marchando pelas fileiras de variáveis estruturadas. O subsistema de memória na Figura 4.46 está conectado tanto ao terminal frontal quanto à cache de dados L1. O terminal frontal é responsável por buscar instruções do sistema de memória, decodificando-as para micro- -operações parecidas com RSC e armazenando-as em duas caches de armazenamento de instrução. Todas as ins- truções buscadas são colocadas na cache de instrução L1 (nível 1). Esta tem um tamanho de 32 KB e é organizada como uma cache associativa de 8 vias com blocos de 64 bytes. À medida que as instruções são buscadas da cache L1, elas entram nos decodificadores que determinam a sequência de micro-operações usada para implementar a instrução no pipeline de execução. O mecanismo decodificador une a lacuna entre um conjunto de instruções CSC antigo e um caminho de dados RSC moderno. As micro-operações decodificadas são alimentadas na cache de micro-operações, que a ntel chama de cache de instruções L0 (de nível 0). Ela é semelhante a uma cache de instruções tradicional, mas tem muito espaço extra para armazenar as sequências de micro-operações produzidas pelas instruções individuais. Quando as micro-operações decodificadas, em vez das instruções originais, são colocadas em cache, não é preciso deco- dificar a instrução em execuções subsequentes. À primeira vista, você poderia pensar que a ntel fez isso para acelerar o pipeline (e, na verdade, isso agiliza o processo de produção de uma instrução), mas a empresa afirma que a cache de micro-operações foi incluída para reduzir o consumo de potência do terminal frontal. Com a cache de micro-operações no lugar, o restante do terminal frontal dorme em um modo de baixa potência sem clock durante 80% do tempo. A previsão de desvio também é realizada no terminal frontal. O previsor de desvio é responsável por desco- brir quando o fluxo do programa sai da busca de sequência pura, e deve ser capaz de fazer isso muito antes que as instruções de desvio sejam executadas. O previsor de desvio no Core i7 é incrível. nfelizmente para nós, os detalhes dos previsores de desvio do processador são segredos mantidos para a maior parte dos projetos. sso por- que o desempenho do previsor geralmente é o componente mais crítico da velocidade geral do projeto. Quanto mais exatidão na previsão os projetistas puderem espremer de cada micrômetro quadrado de silício, melhor o desempenho do projeto inteiro. Assim, as empresas escondem esses segredos a sete chaves, e até mesmo ameaçam os funcionários com processo criminal se qualquer um deles decidir compartilhar essas joias de conhecimento. Basta dizer, no entanto, que todos eles acompanham de que modo os desvios anteriores seguiram e usam isso para fazer previsões. Os detalhes de exatamente o que eles registram e como eles armazenam e consultam a informação é um algoritmo altamente secreto. Afinal, se você tivesse um modo infalível de prever o futuro, é bem provável que não o colocaria na Web para todo mundo ver. nstruções são alimentadas da cache de micro-operações para o escalonador fora de ordem, na ordem ditada pelo programa, porém, elas não são necessariamente emitidas na ordem do programa. Quando é encontrada uma micro-operação que não pode ser executada, o escalonador a retém mas continua processando o fluxo de instru- ções para emitir instruções subsequentes para as quais todos os recursos (registradores, unidades funcionais etc.)
  • 277. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 258 estão disponíveis. A renomeação de registradores também é feita aqui, para permitir que instruções com uma dependência WAR ou WAW prossigam sem atraso. Embora instruções possam ser emitidas fora de ordem, o requisito de interrupções exatas da arquitetura do Core i7 significa que as instruções SA devem ser retiradas (isto é, seus resultados devem ficar visíveis) na ordem original do programa. A unidade de retirada executa essa tarefa. No back end do processador, temos as unidades de execução que efetuam as instruções de inteiros, de ponto flutuante e especializadas. Existem várias dessas unidades e elas funcionam em paralelo. Elas obtêm seus dados do arquivo do registrador e da cache de dados L1. O pipeline da Sandy Bridge do Core i7 A Figura 4.47 é uma versão simplificada da microarquitetura Sandy Bridge, mostrando o pipeline. Na parte superior, está o terminal frontal, cuja tarefa é buscar instruções na memória e prepará-las para execução. O terminal frontal recebe novas instruções x86 da cache de instruções L1. Ele as decodifica para micro-operações para armazenamento na cache de micro-operações, que retém mais ou menos 1,5 K micro-operações. Uma cache de micro-operações desse tamanho dá um desempenho comparável ao de uma cache L0 convencional de 6 KB. A cache de micro-operações contém grupos de seis micro-operações em uma única linha de rastreamento. Para sequências mais longas de micro-operações, várias linhas de rastreamento podem ser interligadas. Figura 4.47 Visa o simplificada do caminho de dados do Core i7. Cache de instrução nível 1 Unidade de decodicação Previsor de desvio/ buffer de destino do desvio Cache de micro-operações Para cache compartilhada nível 3 Unidade de alocação/renomeação Cache unicada nível 2 Escalonador sem memória Controle de fora de ordem Terminal frontal Escalonador com memória ULA 1 Store ULA 2 ULA 3 Load 1 Load 2 Cache de dados nível 1 Unidade de retirada Se a unidade de decodificação encontrar um desvio condicional, ela consulta sua direção prevista no Previsor de esvio. O previsor de desvio contém o histórico dos desvios encontrados no passado e usa esse histórico para descobrir se um desvio condicional será ou não tomado da próxima vez que for encontrado. É aí que é usado o algoritmo altamente secreto. Se a instrução de desvio não estiver na tabela, é usada previsão estática. Um desvio para trás é entendido como parte de um laço e admite-se que deve ser tomado. A exatidão dessas previsões estáticas é extremamente alta. Um desvio para frente é entendido como parte de uma declaração if e admite-se que não deve ser tomado. A exatidão dessas previsões estáticas é bem mais baixa do que a de desvios para trás.
  • 278. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 259 Para um desvio tomado, o BB (Branch arget Buffer – buffer de alvo de desvio) é consultado para deter- minar o endereço de destino. O BTB mantém o endereço de destino do desvio na última vez que ele foi tomado. Quase sempre, esse endereço está correto (na verdade, ele está sempre correto para desvios com um deslocamento constante). Os desvios indiretos, como os usados pelas chamadas de função virtual e comandos switch da C++, vão para muitos endereços, e eles podem ser interpretados incorretamente pelo BTB. A segunda parte do pipeline, a lógica de controle fora de ordem, é alimentada a partir da cache de micro- -operações. À medida que cada micro-operação chega ao terminal frontal, até quatro por ciclo, a unidade de alocação/renomeação a registra em uma tabela de 168 entradas denominada ROB (ReOrder Buffer  buffer de reordenação). Essa entrada monitora o estado da micro-operação até ela ser retirada. Em seguida, a unidade de alocação/renomeação verifica para ver se os recursos de que a micro-operação necessita estão disponíveis. Se estiverem, ela é enfileirada para execução em uma das filas do escalonador. São mantidas filas separadas para micro-operações da memória e para as que não são da memória. Se uma micro-operação não puder ser executada, ela é retardada, mas as subsequentes são processadas, o que leva à execução fora de ordem das micro-operações. Essa estratégia foi projetada para manter todas as unidades funcionais o mais ocupadas possí- vel. Até 154 instruções podem estar no ar a qualquer instante e até 64 dessas podem ser carregadas da memória e até 36 podem ser armazenamentos para a memória. Às vezes, uma micro-operação é protelada porque precisa escrever para um registrador que está sendo lido ou escrito por uma micro-operação anterior. Esses conflitos são denominados dependências WAR e WAW, res- pectivamente, como vimos antes. Renomeando o alvo da nova micro-operação para permitir que ela escreva seu resultado em um dos 160 registradores transitórios em vez de no alvo pretendido, mas ainda ocupado, pode ser possível escalonar a micro-operação para execução imediatamente. Se não houver nenhum registrador transitório disponível, ou se a micro-operação tiver uma dependência RAW (que nunca poderá ser ignorada), o alocador observa a natureza do problema na entrada do ROB. Quando todos os recursos requisitados ficam disponíveis mais tarde, a micro-operação é colocada em uma das filas do escalonador. O escalonador envia as micro-operações para as seis unidades funcionais quando elas estiverem prontas para executar. As unidades funcionais são as seguintes: 1. ULA 1 e a unidade de multiplicação de ponto flutuante. 2. ULA 2 e a unidade de adição/subtração de ponto flutuante. 3. ULA 3 e a unidade de processamento de desvio e comparações de ponto flutuante. 4. nstruções store. 5. nstruções load 1. 6. nstruções load 2. Uma vez que os escalonadores e as ULAs podem processar uma operação por ciclo, um Core i7 de 3 GHz tem o desempenho do escalonador para realizar 18 bilhões de operações por segundo; porém, o processador na realidade nunca alcançará esse nível de vazão. isto que o terminal frontal fornece no máximo quatro micro-operações por ciclo, seis micro-operações só podem ser emitidas em curtas rajadas, pois logo as filas do escalonador se esvaziarão. Além disso, cada unidade de memória usa quatro ciclos para processar suas opera- ções, de modo que elas poderiam contribuir para a vazão de execução máxima apenas em pequenas rajadas. Apesar de serem capazes de saturar totalmente os recursos de execução, as unidades funcionais oferecem uma capacidade de execução significativa, e é por isso que o controle de fora de ordem tem tanto trabalho para encontrar trabalho para ela realizarem. As três ULAs de inteiros não são idênticas. A ULA 1 pode executar todas as operações aritméticas, lógicas, multiplicações e desvios. A ULA 2 pode efetuar apenas operações aritméticas e lógicas. A ULA 3 pode realizar operações aritméticas e lógicas e resolver desvios. Da mesma forma, as duas unidades de ponto flutuante também não são idênticas. A primeira pode realizar aritmética de ponto flutuante, incluindo multiplicações, enquanto a segunda só pode realizar adições, subtrações e movimentações de ponto flutuante.
  • 279. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 260 As unidades de ULA e ponto flutuante são alimentadas por um par de arquivos de registradores de 128 entra- das, um para inteiros e um para números de ponto flutuante. Eles fornecem todos os operandos para as instruções a serem executadas e um repositório para resultados. Devido à renomeação de registradores, oito deles contêm os registradores visíveis no nível SA (EAX, EBX, ECX, EDX etc.), porém, quais oito deles retêm os valores “reais” varia ao longo do tempo à medida que o mapeamento muda durante a execução. A arquitetura Sandy Bridge introduziu a Advanced ector Extensions (A), que admite operações de vetor com dados paralelos de 128 bits. As operações de vetor incluem vetores de ponto flutuante e inteiros, e essa nova extensão SA representa um aumento de duas vezes no tamanho dos vetores agora admitidos em comparação com as extensões SA SSE e SSE2 anteriores. Como a arquitetura executa operações de 256 bits somente com caminhos de dados e unidades funcionais de 128 bits? Ela coordena, de modo inteligente, duas portas de escalonador de 128 bits para produzir uma única unidade funcional de 256 bits. A cache de dados L1 é firmemente acoplada ao back end da arquitetura paralela Sandy Bridge. Ela é uma cache de 32 KB e mantém inteiros números de ponto flutuante e outros tipos de dados. Diferente da cache de micro-ope- rações, ela não é decodificada de modo algum e apenas retém uma cópia dos bytes na memória. A cache de dados L1 é uma cache associativa de 8 vias com 64 bytes por linha. É uma cache de escrita direta, o que significa que, quando uma linha de cache é modificada, é imediatamente copiada de volta para a cache L2 quando sai da cache de dados L1. A cache pode manipular duas operações de leitura e uma de escrita por ciclo de clock. Esses múltiplos acessos são executados usando banking, que divide a cache em subcaches separadas (8 no caso da Sandy Bridge). Desde que todos os três acessos sejam para bancos separados, eles podem prosseguir em sequência; caso contrário, todos menos um dos acessos conflitantes ao banco terão que ser protelados. Quando uma palavra necessária não estiver presente na cache L1, uma requisição é enviada à L2 que, ou responde imediatamente, ou busca a linha de cache na L3 com- partilhada e então responde. Até dez requisições da cache L1 à cache L2 podem estar em curso a qualquer instante. Como micro-operações são executadas fora de uma ordem, não são permitidos armazenamentos (stores) na cache L1 até que todas as instruções anteriores à que causou o armazenamento tenham sido retiradas. A tarefa da unidade de retirada é retirar instruções, em ordem, e monitorar onde elas estão. Se ocorrer uma interrupção, as instruções que ainda não foram retiradas são abortadas, portanto, o Core i7 tem “interrupções precisas”, de modo que, na ocorrência de uma interrupção, todas as instruções foram concluídas até um determinado ponto, e nenhuma instrução após essa interrupção tem qualquer efeito. Se uma instrução de armazenamento foi retirada, mas instruções anteriores ainda estiverem em curso, a cache L1 não pode ser atualizada, portanto, os resultados são colocados em um buffer especial de armazenamento pendente. Esse buffer tem 36 entradas, correspondentes aos 36 armazenamentos que podem estar em execução ao mesmo tempo. Se uma carga subsequente tentar ler os dados armazenados, ela pode ser passada do buffer de armazenamento pendente para a instrução, mesmo que ainda não esteja na cache de dados L1. Esse processo é denominado repasse de armazenamento para carga. Embora tal mecanismo de encaminhamento possa parecer simples, na prática é muito complicado de se realizar, pois os armazenamentos intervenientes podem ainda não ter calculado seus endereços. Nesse caso, a microarquitetura pode não saber definitivamente qual armazenamento no buffer produzirá o valor necessário. O processo de determinação de qual armazenamento oferece o valor para uma carga é chamado de desambiguação. A essa altura, deve estar claro que o Core i7 tem uma microarquitetura de alta complexidade cujo projeto foi dirigido pela necessidade de executar o antigo conjunto de instruções Pentium em um núcleo RSC moderno, de alto grau de pipelining. Ele cumpre esse objetivo desmembrando instruções Pentium em micro-operações, colo- cando-as em cache e alimentando-as no pipeline quatro por vez para execução em um conjunto de ULAs capaz de executar até seis micro-operações por ciclo em condições ideais. Micro-operações são executadas fora de ordem, mas retiradas em ordem e os resultados são armazenados nas caches L1 e L2 em ordem. 4.6.2 A microarquitetura da CPU OMAP4430 No núcleo do sistema-em-um-chip OMAP4430 estão dois processadores ARM Cortex A9. O Cortex A9 é uma microarquitetura de alto desempenho, que executa o conjunto de instruções ARM (versão 7). O processador
  • 280. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 261 foi projetado pela ARM Ltd. e está incluído com pequenas variações em uma grande variedade de dispositivos embutidos. A ARM não fabrica o processador, mas apenas fornece o projeto para os fabricantes de silício que desejam incorporá-lo em seu projeto de sistema-em-um-chip (Texas nstruments, neste caso). O processador Cortex A9 é uma máquina de 32 bits, com registradores de 32 bits e um caminho de dados de 32 bits. Assim como a arquitetura interna, o barramento de memória tem 32 bits de largura. Diferente do Core i7, o Cortex A9 é uma arquitetura RSC verdadeira, o que significa que ela não precisa de um mecanismo complexo para converter antigas instruções CSC em micro-operações para execução. Na verdade, as instruções do núcleo já são instruções ARM do tipo das micro-operações. Contudo, nos últimos anos foram adicionadas instruções gráficas e de multimídia, que requerem hardware especial para sua execução. Visa o geral da microarquitetura Cortex A9 do OMAP4430 O diagrama de blocos da microarquitetura Cortex A9 é dado na Figura 4.48. No todo, ele é muito mais simples do que a microarquitetura Sandy Bridge do Core i7 porque tem uma arquitetura SA mais simples para implementar. Ainda assim, alguns dos componentes básicos são semelhantes aos usados no Core i7. As seme- lhanças são, em sua maioria, comandadas pela tecnologia, restrições de energia ou por razões econômicas. Por exemplo, os dois projetos empregam uma hierarquia de cache multinível para atender as rigorosas restrições de custo das aplicações embutidas típicas; porém, o último nível do sistema de memória cache do Cortex A9 (L2) tem apenas 1 MB de tamanho, muito menor do que no Core i7, que admite caches de último nível (L3) de até 20 MB. As diferenças, ao contrário, se devem principalmente à diferença entre ter ou não ter de preencher a lacuna entre um conjunto de instrução CSC antigo e um núcleo RSC moderno. Figura 4.48 Diagrama de blocos da microarquitetura Cortex A9 da CPU OMAP4430. À memória LPDDR2 Cache de inst. nível 1 Look-aside de laço rápido Previsor de desvio/cache de endereço de destino do desvio Interface do sistema Controlador de memória Unidade de emissão de instrução/ decodicador/renomeador Cache unicada nível 2 Fila de instruções Cache de dados nível 1 ULAs FPUs Unidade de load-store/ buffer de store Retirada Na parte superior da Figura 4.48 está a cache de instruções associativa de 4 vias e 32 KB, que usa linhas de cache de 32 bytes. Já que a maioria das instruções ARM é de 4 bytes, há espaço para cerca de 8 K instruções nessa cache, bem maior que a de micro-operações do Core i7. A unidade de emissão de instrução prepara até quatro instruções para execução por ciclo de clock. Se hou- ver uma ausência na cache L1, menos instruções serão emitidas. Quando é encontrado um desvio condicional, um previsor de desvio com 4 K entradas é consultado para prever se busca a próxima instrução ou a que está no endereço de destino. Se for previsto o caminho tomado, a cache de endereço de destino do desvio com 1 K entrada é consultada em busca do endereço de destino previsto. Além disso, se o terminal frontal detectar que o
  • 281. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 262 programa está executando um laço estreito (ou seja, um pequeno laço não aninhado), ele o carregará na cache look-aside de laço rápido. Essa otimização acelera a busca de instruções e reduz o consumo de energia, pois as caches e os previsores de desvio podem estar em um modo de baixo consumo de energia enquanto o laço estreito está sendo executado. A saída da unidade de missão de instrução flui para os decodificadores, que determinam quais recursos e entradas são necessários pelas instruções. Assim como o Core i7, as instruções são renomeadas após a decodifi- cação, para eliminar dependências WAR que podem atrasar a execução fora de ordem. Depois da renomeação, as instruções são colocadas na fila de despacho de instruções, que as emitirá quando as entradas estiverem prontas para as unidades funcionais, potencialmente fora de ordem. A fila de despacho de instruções envia instruções para as unidades funcionais, como mostra a Figura 4.48. A unidade de execução de inteiros contém duas ULAs, bem como um pequeno pipeline para instruções de desvio. O arquivo de registradores físicos, que mantém registradores SA e alguns temporários, também estão contidos lá. O pipeline do Cortex A9 opcionalmente pode conter um ou mais mecanismos de computação, que atuam como unidades funcionais extras. O ARM admite um mecanismo para cálculo de ponto flutuante, chamado VFP, e um mecanismo de cálculo de vetor SMD, chamado NEON. A unidade de load/store manipula várias instruções de carga e armazenamento, e tem caminhos para a cache de dados e o buffer de armazenamento. A cache de dados é uma tradicional cache de dados L1 associativa de quatro vias e 32 KB que usa uma linha de 32 bytes de tamanho. O buffer de armazenamento mantém os armaze- namentos que ainda não gravaram seu valor na cache de dados (na retirada). Uma carga que é executada tentará primeiro buscar seu valor do buffer de armazenamento, usando o encaminhamento store-to-load, como o do Core i7. Se o valor não estiver disponível no buffer de armazenamento, ele o buscará da cache de dados. Um resultado possível de uma execução de carga é uma indicação, do buffer de armazenamento, que ele deve esperar, pois um armazenamento anterior com um endereço desconhecido está bloqueando sua execução. No evento de ausência de dados na cache de dados L1, o bloco de memória será buscado da cache unificada L2. Em certas circunstâncias, o Cortex A9 também realiza a busca antecipada em hardware da cache L2 para a cache de dados L1, de modo a melhorar o desempenho de cargas e armazenamentos. O chip OMAP 4430 também contém lógica para controlar o acesso à memória. Essa lógica é subdividida em duas partes: a interface de sistema e o controlador de memória. A interface de sistema faz a ligação com a memória por um barramento LPDDR2 de 32 bits de largura. Todas as requisições de memória para o mundo exterior passam por essa interface. O barramento LPDDR2 admite um endereço de 26 bits (palavra, não byte) para 8 bancos por canal LPDDR2. O OMAP4430 tem dois deles, de modo que pode endereçar até 4 GB de RAM externa. O controlador de memória mapeia endereços virtuais de 32 bits para endereços físicos de 32 bits. O Cortex A9 suporta memória virtual (discutida no Capítulo 6), com um tamanho de página de 4 KB. Para acelerar o mapeamento, são fornecidas tabelas especiais denominadas LBs (ranslation Lookaside Buffers  buffers de tradução lateral), para comparar o endereço virtual corrente que está sendo referenciado com os endereços referenciados no passado recente. Duas dessas tabelas são fornecidas para o mapeamento de endereços de ins- truções e dados. Pipeline no Cortex A9 da CPU OMAP4430 O Cortex A9 tem um pipeline de 11 estágios, ilustrado em forma simplificada na Figura 4.49. Os 11 estágios são designados por nomes de estágios curtos, mostrados no lado esquerdo da figura. amos agora examinar rapi- damente cada um. O estágio Fe1 (Fetch #1) está no início do pipeline. É nele que o endereço da próxima instrução a ser buscada é usado para indexar a cache de instruções e iniciar uma previsão de desvio. Em geral, esse endereço é um a mais que o da instrução anterior. Porém, essa ordem sequencial pode ser quebrada por diversos motivos, como quando uma instrução anterior é um desvio que foi previsto para ser tomado, ou quando uma interrupção precisa ser atendida. Como a busca de instrução e previsão de desvio ocupam mais de um ciclo, o estágio Fe2 (Fetch #2) oferece tempo extra para executar essas operações. No estágio Fe3 (Fetch #3), as instruções buscadas (até quatro) são colocadas na fila de instruções.
  • 282. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 263 Figura 4.49 Uma representac a o simplificada do pipeline do Cortex A9 da CPU OMAP4430. Cache de inst. nível 1 Look-aside de laço rápido Estágio Fe1 Previsor de desvio Fila de instruções Fe2 Fe3 Decodicação de instrução Id1 Id2 Renomeação de instrução Re Iss ULA 1 Fila de emissão de instrução ULA 2 Unidade de load-store Ex1 Cache de dados nível 1 Cache unicada nível 2 FPU/ NEON Multi- plica- ção Ex2 Ex3 Retirada … WB Unidade de emissão de instrução Os estágios De1 e De2 (Decodificação) decodificam as instruções. Essa etapa determina de quais entradas as instruções precisarão (registradores e memória) e quais recursos elas exigirão para serem executadas (unidades funcionais). Quando a decodificação estiver concluída, as instruções entram no estágio Re (Renomeação), onde os registradores acessados são renomeados para eliminar dependências WAR e WAW durante a execução fora de ordem. Esse estágio contém a tabela de renomeação que registra qual registrador físico mantém todos os regis- tradores arquitetônicos. Usando essa tabela, qualquer registrador de entrada pode ser facilmente renomeado. O registrador de saída deverá receber um novo registrador físico, que é retirado de um conjunto de registradores físicos não usados. O registrador físico designado estará em uso pela instrução até que ela seja retirada. Em seguida, as instruções entram no estágio Iss (nstruction ssue – emissão de instrução), em que elas são lançadas para a fila de emissão de instrução. A fila de emissão observa instruções cujas entradas estão todas prontas. Quando prontas, suas entradas de registrador são adquiridas (do arquivo de registrador físico ou do barramento de contorno) e então a instrução é enviada aos estágios de execução. Assim como o Core i7, o Cortex A9 potencialmente emite instruções fora da ordem do programa. Até quatro instruções podem ser emitidas a cada ciclo. A escolha das instruções é restringida pelas unidades funcionais disponíveis.
  • 283. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 264 Os estágios Ex (Execução) são onde as instruções são de fato executadas. Quase todas as instruções aritméti- cas, booleanas e de deslocamento utilizam as ULAs de inteiros e são concluídas em um ciclo. Cargas e armazena- mentos utilizam dois ciclos (se estiverem presentes na cache L1), e multiplicações utilizam três ciclos. Os estágios Ex contêm várias unidades funcionais, que são: 1. ULA 1 de inteiros. 2. ULA 2 de inteiros. 3. Unidade de multiplicação. 4. ULA de ponto flutuante e vetor de SMD (opcional com suporte a FP e NEON). 5. Unidade de carga e armazenamento (load/store). nstruções de desvio condicional também são processadas no primeiro estágio Ex e sua direção (desvio/sem desvio) é determinada. No caso de um erro de previsão, um sinal é enviado de volta ao estágio Fe1 e o pipeline é anulado. Depois de concluir sua execução, as instruções entram no estágio WB (WriteBack), onde cada uma atualiza de imediato o arquivo de registrador físico. Depois, quando a instrução é a mais antiga em andamento, ela gravará o resultado do seu registrador no arquivo arquitetônico de registradores. Se houver uma interrupção, são esses valores, e não os dos registradores físicos, que se tornam visíveis. O ato de armazenar o registrador no arquivo arquitetônico é equivalente à retirada no Core i7. Além disso, no estágio WB, quaisquer instruções de armazena- mento agora completam a escrita de seus resultados na cache de dados L1. Essa descrição do Cortex A9 está longe de ser completa, mas deve dar uma ideia razoável de como ele fun- ciona e de quais são as diferenças entre sua microarquitetura e a do Core i7. 4.6.3 A microarquitetura do microcontrolador ATmega168 Nosso último exemplo de uma microarquitetura é a da Atmel ATmega168, mostrada na Figura 4.50. Essa microarquitetura é bem mais simples do que as do Core i7 e do OMAP4430. A razão para essa simplicidade é que o chip é muito pequeno e barato para atender ao mercado de projetos embutidos. Dessa forma, o objetivo principal era fazer um chip barato, não rápido. Barato e simples são bons amigos; barato e rápido, não. O coração do ATmega168 é o barramento principal de 8 bits. Ligado a ele estão vários registradores e bits de estado, ULA, memória e dispositivos de E/S. amos descrevê-los brevemente agora. O arquivo de registradores contém 32 registradores de 8 bits, que são usados para armazenar valores temporários do programa. O registrador de estado e controle mantém os códigos de condição da última operação da ULA (ou seja, sinal, excesso, negati- vo, zero e vai-um), mais um bit que indica se uma interrupção está pendente. O contador de programa mantém o endereço da instrução em execução. Para realizar uma operação na ULA, primeiro os operandos são lidos do registrador e enviados à ULA. A saída da ULA pode ser escrita em qualquer um dos registradores passíveis de escrita por meio do barramento principal. O ATmega168 tem diversas memórias para dados e instruções. A SRAM de dados tem 1 KB, muito grande para ser totalmente endereçada com um endereço de 8 bits no barramento principal. Assim, a arquitetura AR permite que os endereços sejam construídos com um par sequencial de registradores de 8 bits, produzindo assim um endereço de 16 bits que admite até 64 KB de memória de dados. A EEPROM oferece até 1 KB de armazena- mento não volátil, onde os programas podem escrever variáveis que precisam sobreviver a uma falta de energia. Existe um mecanismo semelhante para endereçar a memória do programa, mas 64 KB de código é muito pouco, até mesmo para sistemas embutidos, de baixo custo. Para permitir que mais memória de instruções seja endereçada, a arquitetura AR define três registradores de página de RAM (RAMP, RAMPY e RAMPZ), cada um com 8 bits de largura. O registrador de página de RAM é concatenado com um par de registradores de 16 bits para produzir um endereço de programa de 24 bits, permitindo assim 16 MB de espaço de endereço de instruções.
  • 284. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 265 Figura 4.50 Microarquitetura do ATmega168. Barramento principal de 8 bits Estado e controle Registradores de uso geral 32 × 8 ULA SRAM de dados EEPROM Módulo de E/S 1 Módulo de E/S 2 Módulo de E/S 3 Comparador analógico Temporizador watchdog Unidade de SPI Unidade de interrupção Contador de programa Memória de programa ash Registrador de instrução Decodicador de instrução Linhas de controle Endereçamento direto Endereçamento indireto Para e pense nisso por um instante. 64 KB de código é muito pouco para um microcontrolador que poderia controlar um brinquedo ou um pequeno aparelho. Em 1964, a BM lançou o System 360 Model 30, que tinha 64 KB de memória total (sem truques para aumentá-la). Ele era vendido por US$ 250 mil, que é cerca de US$ 2 milhões em dólares de hoje. O ATmega168 custa cerca de US$ 1, ou menos se você comprar em quantidade. Se você verificar, digamos, o custo de venda de um Boeing, verá que os preços de aeronaves não caíram por um fator de 250.000 nos últimos 50 anos ou mais. E nem os valores de carros ou televisores, ou qualquer outra coisa, exceto computadores. Além disso, o ATmega168 tem um controlador de interrupção no chip, interface de porta serial (SP) e tem- porizadores, que são essenciais para aplicações de tempo real. Há também três portas de E/S digitais de 8 bits, que lhe permitem controlar até 24 botões externos, luzes, sensores, acionadores e assim por diante. É a presença dos temporizadores e portas de E/S, mais do que qualquer outra coisa, que possibilita o uso do ATmega168 para aplicações embutidas sem quaisquer chips adicionais. O ATmega168 é um processador síncrono, com a maior parte das instruções usando apenas um ciclo de clock, embora algumas usem mais. O processador é paralelo, de modo que, enquanto uma instrução está sendo buscada, a anterior está sendo executada. Entretanto, o pipeline tem apenas dois estágios, busca e execução. Para executar instruções em um ciclo, o ciclo de clock deve acomodar a leitura do registrador do arquivo de regis- tradores, seguida pela execução da instrução na ULA, seguida pela escrita do registrador de volta ao arquivo de registradores. Como todas essas operações ocorrem em um ciclo de clock, não é preciso de lógica de contorno (bypass) ou detecção de protelação (stall). As instruções do programa são executadas em ordem, em um ciclo, e sem sobreposição com outras instruções. Embora pudéssemos entrar em mais detalhes sobre o ATmega168, a descrição que demos e a Figura 4.50 oferecem uma ideia básica. O ATmega168 tem um único barramento principal (para reduzir a área do chip),
  • 285. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 266 um conjunto heterogêneo de registradores e uma série de memórias e dispositivos de E/S pendurados no bar- ramento principal. A cada ciclo do caminho de dados, dois operandos são lidos do arquivo de registradores e passam pela ULA, com os resultados enviados de volta a um registrador, assim como nos computadores mais modernos. 4.7 Comparac a o entre i7, OMAP4430 e ATmega168 Nossos três exemplos são muito diferentes, porém, ainda assim exibem certa dose de características em comum. O Core i7 tem um conjunto de instruções CSC antigo que os engenheiros da ntel adorariam jogar na Baía de São Francisco, caso isso não violasse as leis antipoluição das águas da Califórnia. O OMAP4430 é um projeto RSC puro, com um conjunto de instruções enxuto e esperto. O ATmega168 é um processador simples de 8 bits para aplicações embutidas. Ainda assim, o coração de cada um deles é um conjunto de registradores e uma ou mais ULAs que efetuam operações aritméticas e booleanas simples em operandos de registradores. A despeito de suas óbvias diferenças externas, o Core i7 e o OMAP4430 têm unidades de execução bastante semelhantes. Ambas as unidades de execução aceitam micro-operações que contêm um opcode, dois registradores de origem e um registrador de destino. Ambos podem executar uma micro-operação em um ciclo. Ambos têm alto grau de pipelining, previsão de desvio e caches de instruções () e de dados (D) divididas. Essa semelhança interna não é um acidente ou nem mesmo causada pela eterna rotatividade de empregos dos engenheiros do ale do Silício. Como vimos em nossos exemplos de Mic-3 e Mic-4, é fácil e natural construir um caminho de dados com pipeline que pega dois registradores de origem, passa-os por uma ULA e armazena os resultados em um registrador. A Figura 4.34 mostra esse pipeline graficamente. Com a tecnologia atual, esse é o projeto mais eficaz. A principal diferença entre as CPUs Core i7 e OMAP4430 é o modo como elas vão de seu conjunto de instrução SA até a unidade de execução. O Core i7 tem de fragmentar suas instruções CSC para colocá-las no formato de três registradores de que a unidade de execução necessita. É isso que faz o terminal frontal na Figura 4.47 – desmembra instruções grandes em micro-operações caprichadas e jeitosas. O OMAP4430 não tem de fazer nada porque suas instruções nativas já são micro-operações caprichadas e jeitosas. É por isso que grande parte das novas SAs são do tipo RSC – para oferecer melhor compatibilidade entre o conjunto de instruções SA e o mecanismo interno de execução. É instrutivo comparar nosso projeto final, a Mic-4, com esses dois exemplos do mundo real. A Mic-4 é muito parecida com o Core i7. A tarefa de ambos é interpretar um conjunto de instrução SA que não é RSC. Ambos fazem isso desmembrando as instruções SA em micro-operações com um opcode, dois registradores de origem e um de destino. Em ambos os casos, as micro-operações são depositadas em uma fila para execução mais tarde. A política estrita do projeto da Mic-4 prevê emissão, execução, retirada em ordem, ao passo que o Core i7 tem uma política de emissão em ordem, execução fora de ordem, retirada em ordem. Na realidade, Mic-4 e OMAP4430 não podem ser comparados, porque o conjunto de instruções SA do OMAP4430 é composto de instruções RSC (isto é, micro-operações de três registradores). Essas instruções não têm de ser desmembradas e podem ser executadas como se apresentam, cada uma em um único ciclo de caminho de dados. Em comparação com Core i7 e OMAP4430, o ATmega168 é realmente uma máquina simples. Tende mais para RSC do que para CSC porque grande parte de suas instruções simples pode ser executada em um ciclo de clock e não precisa ser desmembrada. Ele não tem pipelining, nem cache, e tem emissão, execução e retirada em ordem. Em sua simplicidade, é muito mais semelhante à Mic-1. 4.8 Resumo O coração de todo computador é o caminho de dados. Ele contém alguns registradores, um, dois ou três bar- ramentos e uma ou mais unidades funcionais, como ULAs e deslocadores. O laço de execução principal consiste
  • 286. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 267 em buscar alguns operandos em registradores e enviá-los pelos barramentos à ULA e a outras unidades funcionais para execução. Então, os resultados são armazenados de volta nos registradores. O caminho de dados pode ser controlado por um sequenciador que busca microinstruções em um armazena- mento de controle. Cada microinstrução contém bits que controlam o caminho de dados por um ciclo. Esses bits especificam quais operandos selecionar, qual operação executar e o que fazer com os resultados. Além disso, cada microinstrução especifica sua sucessora, em geral explicitamente por conter seu endereço. Algumas microinstru- ções modificam esse endereço de base efetuando operações OR com bits no endereço antes de usá-lo. A máquina JM é uma máquina de pilha com opcodes de 1 byte que passam palavras para a pilha, retiram- -nas da pilha e combinam palavras (por exemplo, somando-as) na pilha. Uma execução microprogramada foi dada à microarquitetura Mic-1. Adicionando uma unidade de busca de instrução para carregar os bytes antecipa- damente no fluxo de instruções, foi possível eliminar muitas referências ao contador de programa e a máquina ficou muito mais veloz. Há muitas maneiras de projetar o nível de microarquitetura. Existem muitos compromissos, incluindo proje- tos com dois barramentos e três barramentos, campos de microinstrução codificados e não codificados, presença ou ausência de busca antecipada, alto grau ou baixo grau de pipelining e muito mais. A Mic-1 é uma máquina simples, controlada por software, com execução sequencial e nenhum paralelismo. Por comparação, a Mic-4 é uma microarquitetura de alto grau de paralelismo com sete estágios de pipeline. O desempenho pode ser melhorado de várias maneiras, sendo que a memória cache é uma das principais. Caches de mapeamento direto e caches associativas de conjunto costumam ser usadas para acelerar referências à memória. Previsão de desvio – estática e dinâmica – é importante, assim como execução fora de ordem e execução especulativa. Nossas três máquinas de exemplo – Core i7, OMAP4430 e ATmega168 – têm, todas, microarquiteturas que não são visíveis aos programadores de linguagem de montagem SA. O Core i7 tem um esquema complexo para converter instruções SA em micro-operações, colocá-las em cache e alimentá-las em um núcleo RSC superescalar para execução fora de ordem, renomeação de registradores e todos os truques do repertório para extrair a última gota possível de velocidade do hardware. O OMAP4430 tem alto grau de pipelining, porém, no mais, é relativamente simples, com emissão em ordem, execução em ordem e retirada em ordem. O ATmega168 é muito simples, com um único barramento principal direto, ao qual estão ligados um punhado de registradores e uma ULA. Problemas 1. Quais são as quatro etapas que as CPUs utilizam para executar instruções? 2. Na Figura 4.6, o registrador do barramento B está codificado em um campo de 4 bits, mas o barramento C é representado com um mapa de bits. Por quê? 3. Na Figura 4.6, há um retângulo denominado “bit alto”. Apresente um diagrama de circuito para ele. 4. Quando o campo JMPC em uma microinstrução é desabilitado, é efetuada uma operação OR entre MBR e NEXT_ADDRESS para formar o endereço da próxima microinstrução. Há alguma circunstância na qual faz sentido que NEXT_ADDRESS seja 0x1FF e use JMPC? 5. Suponha que no exemplo da Figura 4.14(a) a decla- ração k = 5; é adicionada após a declaração if. Qual seria o novo código de montagem? Considere que o compilador é um compilador otimizador. 6. Dê duas traduções JM diferentes para a seguinte declaração Java: i = k + n + 5; 7. Dê a declaração Java que produziu o seguinte código JM: ILOAD j ILOAD n ISUB BIPUSH 7 ISUB DUP IADD ISTORE i
  • 287. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 268 8. No texto, mencionamos que, quando traduzimos a declaração if (Z) goto L1; else goto L2 para binário, L2 tem de estar nas últimas 256 pala- vras do armazenamento de controle. Não seria igual- mente possível que L1 estivesse em, por exemplo, 0x40 e L2, em 0x140? Explique sua resposta. 9. No microprograma para Mic-1, em if_icmpeq3, MDR é copiado para H. Algumas linhas mais adiante ele é subtraído de TOS para verificar a igualdade. Com certeza seria melhor ter aqui uma declaração: if_icmpeq3 Z = TOS − MDR; rd Por que isso não é feito? 10. Quanto tempo leva uma Mic-1 de 2,5 GHz para exe- cutar a seguinte declaração Java: i = j + k; Dê sua resposta em nanossegundos. 11. Repita a pergunta anterior, agora para uma Mic-2 de 2,5 GHz. Com base nesse cálculo, quanto tempo um programa que executa durante 100 s na Mic-1 demoraria na Mic-2? 12. Escreva um microcódigo para a Mic-1 a fim de executar a instrução JM POPTWO. Essa instrução retira duas palavras do topo da pilha. 13. Na máquina JM completa, há opcodes especiais de 1 byte para armazenar de 0 até 3 locais na pilha em vez de usar a instrução geral ILOAD. Como a JM deve ser modificada para fazer o melhor uso dessas instruções? 14. A instrução ISHR (deslocamento aritmético de intei- ro para a direita) existe em JM, mas não em JM. Ela usa os dois valores do topo da pilha, substituin- do-os por um valor único, o resultado. A segunda palavra a partir do topo de uma pilha é o operando a ser deslocado. Seu conteúdo é deslocado para a direi- ta por um valor entre 0 e 31, inclusive, dependendo do valor dos 5 bits menos significativos da palavra que está no topo da pilha (os outros 27 da palavra do topo são ignorados). O bit de sinal é duplicado para a direita por tantos bits quanto for o inteiro de deslo- camento. O opcode para ISHR é 122 (0x7A). a. Qual é a operação aritmética equivalente ao deslo- camento para a esquerda por uma contagem de 2? b. Estenda o microcódigo para incluir essa instrução como uma parte da JM. 15. A instrução ISHL (deslocamento de inteiro para a esquerda) existe em JM, mas não em JM. Ela usa os dois valores do topo da pilha, substituindo-os por um valor único, o resultado. A segunda palavra a partir do topo da pilha é o operando a ser deslocado. Seu conteúdo é deslocado para a esquerda por um valor entre 0 e 31, inclusive, dependendo do valor dos 5 bits menos signifi- cativos da palavra que está no topo da pilha (os outros 27 da palavra do topo são ignorados). Zeros são deslocados para a direita por tantos bits quanto for o inteiro de des- locamento. O opcode para ISHL é 120 (0x78). a. Qual é a operação aritmética equivalente ao deslo- camento para a esquerda por uma contagem de 2? b. Estenda o microcódigo para incluir essa instrução como uma parte da JM. 16. A instrução JM INVOKEVIRTUAL precisa saber quantos parâmetros ela tem. Por quê? 17. Execute a instrução JVM DLOAD para a Mic-2. Ela tem um índice de 1 byte e passa a variável local que está nessa posição para a pilha. Então, ela também passa para a pilha a próxima palavra mais alta. 18. Desenhe uma máquina de estado finito para a conta- gem de pontos no jogo de tênis. As regras do tênis são as seguintes. Para ganhar, você precisa de um mínimo de quatro pontos e deve ter no mínimo dois pontos a mais do que seu adversário. Comece com um estado (0, 0) que indica que nenhum ponto foi marcado ainda. Depois, adicione um estado (1, 0), que signi- fica que A marcou um ponto. Denomine A o arco de (0, 0) a (1, 0). Agora, adicione um estado (0, 1) que indica que B marcou um ponto e denomine B o arco de (0, 0). Continue adicionando estados e arcos até que todos os estados possíveis tenham sido incluídos. 19. Reconsidere o problema anterior. Há quaisquer esta- dos que poderiam ser agrupados sem mudar o resul- tado de qualquer jogo? Caso a resposta seja positiva, quais são equivalentes? 20. Desenhe uma máquina de estado finito para previsão de desvio que seja mais persistente do que a Figura 4.42. Ela deve alterar previsões somente após três previsões erradas consecutivas. 21. O registrador de deslocamento da Figura 4.27 tem uma capacidade máxima de 6 bytes. Uma versão mais barata da FU poderia ser construída com um regis- trador de deslocamento de 5 bytes? E de 4 bytes? 22. Agora que já estudamos FUs mais baratas na per- gunta anterior, vamos examinar FUs mais caras. Haveria alguma razão para termos nas FUs mais caras um registrador de deslocamento muito maior, por exemplo, de 12 bytes? Justifique sua resposta. 23. No microprograma para a Mic-2, o código para if_icmpeq6 vai para T quando Z é ajustado para 1. Contudo, o código em T é o mesmo que goto1. Seria possível ir para goto1 diretamente? Fazer isso deixa- ria a máquina mais rápida? 24. Na Mic-4, a unidade de decodificação mapeia o opco- de JM para o índice da ROM onde as micro-ope- rações correspondentes estão armazenadas. Parece
  • 288. C a p  t u l o 4 O n  v e l d e m i c r o a r q u i t e t u r a 269 mais simples apenas omitir o estágio de decodifica- ção e alimentar o opcode JM diretamente no enfi- leiramento. Ela poderia usar o opcode JM como um índice para a ROM, do mesmo modo que faz a Mic-1. O que está errado nesse plano? 25. Por que os computadores são equipados com vários níveis de cache? Não seria melhor apenas ter uma grande cache? 26. Um computador tem uma cache de dois níveis. Suponha que 60% das referências à memória obtêm presença na cache de primeiro nível, 35% na de segundo nível, e 5% encontram ausência da cache. Os tempos de acesso são 5 ns, 15 ns e 60 ns, respec- tivamente, e os tempos para a cache de nível 2 e para a memória começam a ser contados no momento em que elas sabem que são necessários (por exemplo, o acesso à cache de nível 2 nem mesmo inicia até ocorrer uma ausência da de nível 1). Qual é o tempo médio de acesso? 27. No final da Seção 4.5.1, dissemos que uma alocação de escrita vence somente se houver possibilidade de várias escritas sequenciais para a mesma linha de cache. E o caso de uma escrita seguida por várias leituras – tam- bém não seria um grande vencedor? 28. No primeiro rascunho deste livro, a Figura 4.39 mostrava uma cache associativa de três vias em vez de uma de quatro vias. Um dos revisores teve um ataque de nervos dizendo que isso provocaria uma terrível confusão para os estudantes porque 3 não é uma potência de 2 e os computadores fazem tudo em binário. Uma vez que o cliente sempre tem razão, a figura foi alterada para uma cache associa- tiva de quatro vias. O revisor tinha razão? Discuta sua resposta. 29. Muitos arquitetos de computador gastam muito tempo tornando seu pipeline mais profundo. Por quê? 30. Um computador com pipeline de cinco estágios trata dos desvios condicionais protelando durante os três ciclos seguintes após chegar a um desses desvios. Qual seria o prejuízo causado por essa protelação se 20% de todas as instruções forem desvios condicio- nais? gnore todas as fontes de protelação, exceto os desvios condicionais. 31. Suponha que um computador faz busca antecipada de até 20 instruções. Todavia, na média, quatro delas são desvios condicionais, cada um com probabilidade de 90% de previsão correta. Qual é a probabilidade de a busca antecipada estar no caminho certo? 32. Suponha que temos de alterar o projeto da máquina usada na Figura 4.43 para ter 16 registradores em vez de 8. Então, trocamos 6 para usar R8 como seu des- tino. O que acontece nos ciclos a partir do ciclo 6? 33. Dependências em geral causam problemas em CPUs com pipeline. Há alguma otimização que possa ser feita com dependências WAW que poderia realmente melhorar a situação? Qual? 34. Reescreva o interpretador Mic-1 mas agora com LV apontando para a primeira variável local em vez de para o ponteiro de ligação. 35. Escreva um simulador para uma cache de mapeamen- to direto de uma via. Considere o número de entradas e o tamanho da linha como parâmetros da simulação. Faça alguns experimentos e escreva um relatório sobre o que constatou.
  • 289. E ste capítulo discute em detalhes o nível da arquitetura do conjunto de instrução (SA – nstruction Set Architecture). Esse nível está posicionado entre o da microarquitetura e o do sistema operacional, como vimos na Figura 1.2. Historicamente, ele foi desenvolvido antes de quaisquer outros níveis e, na verdade, na origem era o único. Até hoje, não é raro ouvir esse nível ser chamado de “a arquitetura” de uma máquina ou, às vezes (incorretamente), como a “linguagem de montagem”. O nível SA tem um significado especial que o torna importante para arquitetos de sistemas: é a interface entre o software e o hardware. Embora seja possível o hardware executar diretamente programas escritos em C, C++, Java ou alguma outra linguagem de alto nível, isso não seria uma boa ideia. A vantagem em desempenho da compilação em relação à interpretação seria perdida. Além do mais, para ter muita utilidade prática, a maioria dos computadores deve ser capaz de executar programas escritos em várias linguagens, e não apenas em uma. A abordagem de base adotada por todos os projetistas de sistemas é traduzir programas escritos em várias lingua- gens de alto nível para uma forma intermediária comum – nível SA – e construir hardware que possa executar pro- gramas diretamente no nível SA. O nível SA define a interface entre os compiladores e o hardware. É a linguagem que ambos têm de entender. A relação entre os compiladores, o nível SA e o hardware pode ser vista na Figura 5.1. O ideal é que, ao projetar uma nova máquina, os arquitetos conversem com os escritores de compiladores e também com os engenheiros de hardware para descobrir quais características cada um deles quer no nível SA. Se os escritores de compiladores quiserem alguma característica que os engenheiros não podem realizar de modo eficiente em custo (por exemplo, uma instrução desvie-e-processe-folha-de-pagamento), ela não entra no hardware. Da mesma forma, se a turma do hardware tiver alguma nova característica elegante que quer acrescentar (por exemplo, uma memória na qual as palavras cujos endereços são números primos sejam super-rápidas), mas a turma do software não consegue imaginar como gerar código para usá-la, ela não passará da prancheta. Após muita negociação e simulação, surgirá uma SA perfeitamente otimizada para as linguagens de programação pretendidas, que será implementada. O n vel de arquitetura do conjunto de instruc a o 5 Cap tulo
  • 290. C a p  t u l o 5 O n  v e l d e a r q u i t e t u r a d o c o n j u n t o d e i n s t r u c  a  o 271 Figura 5.1 O n vel ISA e  a interface entre os compiladores e o hardware. Software Hardware Hardware Programa em C Nível ISA Programa ISA executado pelo microprograma ou hardware programa em FORTRAN Programa em FORTRAN compilado para programa ISA Programa em C compilado para programa ISA sso é a teoria. Agora, vamos à triste realidade. Quando surge uma nova máquina, a primeira pergunta que todos os clientes potenciais fazem é: “Ela é compatível com sua antecessora?”. A segunda é: “Ela pode executar meu sistema operacional antigo?”. A terceira é: “Ela executará todos os meus programas de aplicação existentes sem modificação?”. Se qualquer uma das respostas a essas perguntas for “não”, os projetistas terão muitas explicações a dar. É raro que os clientes se disponham a jogar fora todos os seus programas antigos e começar tudo de novo. Essa atitude pressiona muito os arquitetos de computadores a manter a mesma SA entre modelos, ou ao menos torná-la compatível com os modelos anteriores. Com isso, queremos dizer que a nova máquina deve ser capaz de executar programas antigos sem alteração. Contudo, é totalmente aceitável que a nova máquina tenha novas instruções e outras características que só possam ser exploradas por novo software. Em termos da Figura 5.1, contanto que os projetistas garantam que a SA seja compatível com os modelos anteriores, eles têm toda a liberdade para fazer o que quiserem com o hardware porque, na verdade, quase ninguém se importa muito com o hardware real (ou nem mesmo sabe o que ele faz). Eles podem passar de um projeto microprogramado para exe- cução direta, ou adicionar paralelismo ou facilidades superescalares ou qualquer outra coisa que queiram, contanto que mantenham a compatibilidade com a SA anterior. A meta é garantir que velhos programas sejam executados na nova máquina. Então, o desafio se torna construir máquinas melhores sujeitas às restrições de compatibilidade. O que acabamos de dizer não tem a intenção de dar a entender que o projeto da SA não importa. Uma boa SA tem vantagens significativas em relação a uma ruim, em particular quando se trata de comparar capacidade computacional bruta com custo. Se quanto ao mais os projetos forem equivalentes, as SAs podem ser responsáveis por uma diferença de até 25% em desempenho. O que queremos deixar claro é que as forças do mercado dificultam (mas não impossibilitam) descartar uma SA antiga e introduzir uma nova. Não obstante, de vez em quando surge uma nova SA de uso geral e, em mercados especializados (por exemplo, sistemas embutidos ou processadores multimídia), elas ocorrem com muito mais frequência. Por conseguinte, é importante entender o projeto da SA. O que faz uma SA ser boa? Há dois fatores primordiais. Primeiro, ela deve definir um conjunto de instruções que pode ser executado com eficiência em tecnologias atuais e futuras, resultando em projetos efetivos em custo por várias gerações. Um mau projeto é mais difícil de realizar e pode exigir um número muito maior de portas para implementar um processador e mais memória para executar programas. Além disso, a execução pode ser mais lenta porque a SA encobre oportunidades de sobrepor operações, exigindo projetos muito mais sofisticados para obter desempenho equivalente. Um projeto que aproveita as peculiaridades de determinada tecnologia pode ter um êxito fugaz e produzir uma única geração de implementações com custo eficaz e então ser ultrapassado por SAs mais avançadas. Segundo, uma boa SA deve fornecer um alvo claro para o código compilado. Regularidade e completude de uma faixa de opções são aspectos importantes que nem sempre estão presentes em uma SA. Essas propriedades são importantes para um compilador, que pode ter problemas para escolher a melhor opção entre alternativas
  • 291. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 272 limitadas, em particular quando algumas alternativas que parecem óbvias não são permitidas pela SA. Em resu- mo, uma vez que a SA é a interface entre hardware e software, ela tem de contentar os projetistas de hardware (fácil de implementar com eficiência) e satisfazer os projetistas de software (fácil de gerar bom código para ela). 5.1 Visa o geral do n vel ISA amos começar nosso estudo do nível SA perguntando o que ele é. Essa pergunta pode parecer simples, mas é mais complicada do que poderíamos imaginar à primeira vista. Na seção seguinte, abordaremos algumas dessas questões. Em seguida, vamos examinar modelos de memória, registradores e instruções. 5.1.1 Propriedades do n vel ISA Em princípio, o nível SA é definido pelo modo como a máquina se apresenta a um programador de lingua- gem de máquina. Já que mais ninguém (normal) faz muita programação em linguagem de máquina, vamos rede- finir isso dizendo que código de nível SA é o que um compilador produz (ignorando, por enquanto, chamadas ao sistema operacional e a linguagem de montagem simbólica). Para produzir código de nível SA, o escritor de compilador tem de saber qual é o modelo de memória, quais e quantos são os registradores, quais tipos de dados e instruções estão disponíveis, e assim por diante. O conjunto de todas essas informações define o nível SA. De acordo com essa definição, questões como se a microarquitetura é microprogramada ou não, se ela tem paralelismo ou não, se ela é superescalar ou não, e assim por diante, não fazem parte do nível SA, porque não são visíveis para o escritor de compilador. Todavia, essa observação não é de todo verdadeira, porque algumas dessas propriedades afetam o desempenho e isso é visível para o escritor do compilador. Considere, por exem- plo, um projeto superescalar que pode emitir instruções uma atrás da outra no mesmo ciclo, contanto que uma seja uma instrução de número inteiro e outra de ponto flutuante. Se o compilador alternar instruções de número inteiro e instruções de número de ponto flutuante, obterá desempenho visivelmente melhor do que se não fizer isso. Assim, os detalhes da operação superescalar são visíveis no nível SA, portanto, a separação entre as cama- das não é tão clara como poderia parecer de início. Para algumas arquiteturas, o nível SA é especificado por um documento formal de definição, muitas vezes pro- duzido por um consórcio do setor. Para outras, não. Por exemplo, a ARM v7 (SA ARM versão 7) tem uma definição oficial publicada pela ARM Ltd. A finalidade de um documento de definição é possibilitar que diferentes realizadores construam a máquina e todas elas executem exatamente o mesmo software e obtenham resultados idênticos. No caso da SA ARM, a ideia é permitir que vários fabricantes de chips produzam chips ARM idênticos em termos funcionais, e diferentes apenas em desempenho e preço. Para essa ideia dar certo, os fabricantes têm de saber o que um chip ARM deve fazer (no nível SA). Por conseguinte, o documento de definição informa qual é o modelo da memória, quais registradores estão presentes, o que as instruções fazem e assim por diante, mas não qual é o aspecto da microarquitetura. Esses documentos de definição contêm seções normativas, que impõem requisitos, e seções informativas, cuja intenção é ajudar o leitor, mas não fazem parte da definição formal. As seções normativas usam com fre- quência palavras como deve, não pode e deveria para requerer, proibir e sugerir aspectos da arquitetura, respecti- vamente. Por exemplo, uma sentença como Executar um opcode reservado deverá causar uma exceção. informa que, se um programa executar um opcode que não é definido, ele deve causar uma exceção e não pode ser apenas ignorado. Uma técnica alternativa poderia ser deixar essa questão em aberto, quando então a sentença poderia ser O efeito da execução de um opcode reservado é definido pela implementação. sso significa que o escritor do compilador não pode contar com qualquer comportamento particular, o que dá a dife- rentes implementadores a liberdade de opções diferentes. A maioria das especificações de arquitetura é acompanhada de conjuntos de testes para verificar se uma execução que se afirma compatível com a especificação realmente o é.
  • 292. C a p  t u l o 5 O n  v e l d e a r q u i t e t u r a d o c o n j u n t o d e i n s t r u c  a  o 273 O motivo por que a ARM v7 tem um documento que define seu nível SA é claro: todos os chips ARM exe- cutarão o mesmo software. Por muitos anos, não houve um documento de definição formal para a SA A-32 (às vezes, denominada SA x86), pois a ntel não queria abrir a guarda para que outros fabricantes produzissem chips compatíveis com a ntel. Na verdade, a ntel já apelou para a justiça para tentar impedir que outros fabricantes clonassem seus chips, mas perdeu a causa. Porém, no final da década de 1990, a empresa lançou uma especi- ficação completa do conjunto de instruções A-32. Talvez isso tenha acontecido porque eles sentiram o erro e quiseram ajudar os companheiros arquitetos e programadores, ou talvez porque os Estados Unidos, o Japão e a Europa estivessem investigando a ntel por suposta violação das leis antitruste. Essa SA bem documentada ainda está sendo atualizada no site para desenvolvedores (http://developer.intel.com). A versão lançada com o Core i7 da ntel possui 4.161 páginas, o que nos faz lembrar novamente que o Core i7 é um computador com conjunto complexo de instruções. Outra propriedade importante do nível SA é que, na maioria das máquinas, há no mínimo dois modos. O modo núcleo (kernel) deve executar o sistema operacional e permite que todas as instruções sejam exe- cutadas. O modo usuário (user) deve executar programas de aplicação e não permite que certas instruções sensíveis (como as que manipulam a cache diretamente) sejam executadas. Neste capítulo, focalizaremos principalmente instruções e propriedades do modo usuário. 5.1.2 Modelos de memo ria Todos os computadores dividem a memória em células que têm endereços consecutivos. O tamanho de célula mais comum no momento é 8 bits, mas células de 1 bit a 60 bits já foram usadas no passado (veja a Figura 2.10). Uma célula de 8 bits é denominada byte (ou octeto). A razão para usar bytes de 8 bits é que os caracteres ASC têm 7 bits, de modo que um caractere ASC (mais um bit de paridade muito pouco utilizado) se encaixa em um byte. Outros códigos, como Unicode e UTF-8, utilizam múltiplos de 8 bits para representar caracteres. Em geral, os bytes são agrupados em palavras de 4 bytes (32 bits) ou 8 bytes (64 bits) com instruções disponíveis para manipular palavras inteiras. Muitas arquiteturas precisam que as palavras sejam alinhadas em seus limites naturais; assim, por exemplo, uma palavra de 4 bytes pode começar no endereço 0, 4, 8 etc., mas não no endereço 1 ou 2. De modo semelhante, uma palavra de 8 bytes pode começar no endereço 0, 8 ou 16, mas não no endereço 4 ou 6. O alinhamento de palavras de 8 bytes é ilustrado na Figura 5.2. Figura 5.2 Palavra de 8 bytes em uma memo ria little-endian. (a) Alinhada. (b) Na o alinhada. Algumas ma quinas requerem que palavras na memo ria sejam alinhadas. 24 Endereço Palavra de 8 bytes alinhada no endereço 8 16 8 15 14 13 12 11 (a) 10 9 8 0 8 bytes 24 Endereço Palavra de 8 bytes não alinhada no endereço 12 16 8 15 14 13 12 19 (b) 18 17 16 0 8 bytes O alinhamento costuma ser exigido porque memórias funcionam com mais eficiência desse modo. O Core i7, por exemplo, que busca 8 bytes por vez na memória, usa uma interface DDR3, que admite apenas acessos ali- nhados em 64 bits. Assim, o Core i7 não poderia fazer uma referência desalinhada à memória nem que quisesse, porque a interface de memória exige endereços que sejam múltiplos de 8.
  • 293. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 274 Contudo, esse requisito de alinhamento às vezes causa problemas. O Core i7 permite que programas SA referenciem palavras que começam em qualquer endereço, uma propriedade que remonta ao 8088, que tinha um barramento de dados de 1 byte de largura (e, assim, nenhum requisito de alinhamento de referências à memória em limites de 8 bytes). Se um programa Core i7 ler uma palavra de 4 bytes no endereço 7, o hardware tem de fazer uma referência à memória para obter os bytes de 0 a 7 e uma segunda referência à memória para obter os bytes de 8 a 15. Então, a CPU tem de extrair os 4 bytes requisitados dos 16 bytes lidos da memória e montá-los na ordem correta para formar uma palavra de 4 bytes. Fazer isso regularmente não leva a uma velocidade fantástica. Ter a capacidade de ler palavras em endereços arbitrários requer lógica extra no chip, o que o torna maior e mais caro. Os engenheiros projetistas adorariam livrar-se dela e apenas exigir que todos os programas fizessem referências à memória alinhadas por palavra. O problema é que, sempre que os engenheiros dizem “E quem se importa com executar programas 8088 antigos e bolorentos que referenciam a memória de modo errado?”, o pessoal de marketing tem uma resposta curta e rápida: “Nossos clientes”. A maioria das máquinas tem um único espaço de endereço linear no nível SA, que se estende do endereço 0 até algum máximo, geralmente 232 – 1 bytes ou 264 – 1 bytes. Contudo, algumas têm espaços de endereços separados para instruções e dados, de modo que uma busca de instrução no endereço 8 vai para um espaço de endereço diferente de uma busca de dados no endereço 8. Esse esquema é mais complexo do que ter um único espaço de endereço, mas tem duas vantagens. Primeiro, torna-se possível ter 232 bytes de programa e 232 bytes adicio- nais de dados usando apenas endereços de 32 bits. Segundo, como todas as escritas vão automaticamente para o espaço de dados, fica impossível sobrescrever por acidente o programa, eliminando assim uma fonte de bugs de programas. Separar espaços de instrução e dados também torna os ataques por malware muito mais difíceis de serem bem-sucedidos, pois ele não pode alterar o programa – não consegue sequer endereçá-lo. Observe que ter um espaço de endereços separado para instruções e dados não é o mesmo que ter uma cache de nível 1 dividida. No primeiro caso, a quantidade total de espaço de endereço é duplicada e leituras de qualquer endereço dão resultados diferentes, dependendo de a leitura ser de uma instrução ou de uma palavra de dados. Com uma cache dividida, ainda há apenas um espaço de endereço, só que caches diferentes armazenam partes diferentes desse espaço. Ainda outro aspecto do modelo de memória de nível SA é a semântica da memória. É muito natural esperar que uma instrução LOAD que ocorre após uma instrução STORE, e que referencia o mesmo endereço, retornará o valor que acabou de ser armazenado. Todavia, como vimos no Capítulo 4, em muitos projetos, as microinstruções são reordenadas. Assim, há um perigo real de que a memória não terá o comportamento esperado. O problema fica ainda pior em um multiprocessador, no qual cada uma das várias CPUs envia uma sequência de requisições de escrita e leitura (talvez reordenadas) a uma memória compartilhada. Projetistas de sistemas podem adotar qualquer uma de diversas técnicas para resolver esse problema. Em um extremo, todas as requisições de memória podem ser serializadas, portanto, cada uma é concluída antes de a próxima ser emitida. Essa estratégia prejudica o desempenho, mas resulta na semântica de memória mais simples (todas as operações são executadas estritamente na ordem do programa). No outro extremo, não são dadas garantias de espécie alguma. Para forçar uma ordenação na memória, o programa deve executar uma instrução SYNC, que bloqueia a emissão de todas as novas operações de memória até que todas as anteriores tenham sido concluídas. Esse esquema atribui uma grande carga aos compiladores, porque eles têm de entender, com detalhes, como a microarquitetura subjacente funciona, embora dê aos proje- tistas de hardware a máxima liberdade para otimizar a utilização da memória. Também são possíveis modelos de memória intermediários, nos quais o hardware bloqueia automaticamente a emissão de certas referências à memória (por exemplo, as que envolvem uma dependência RAW ou WAR), mas não bloqueia outras. Embora seja um aborrecimento ter todas essas peculiaridades causadas pela micro- arquitetura expostas no nível SA (ao menos para os escritores de compiladores e programadores em linguagem assembly), essa é a tendência. Ela é causada pelas execuções subjacentes, como reordenação de microinstruções, paralelismo profundo, vários níveis de cache e assim por diante. eremos outros exemplos desses efeitos não naturais adiante neste capítulo.
  • 294. C a p  t u l o 5 O n  v e l d e a r q u i t e t u r a d o c o n j u n t o d e i n s t r u c  a  o 275 5.1.3 Registradores Todos os computadores têm alguns registradores visíveis no nível SA. Eles estão lá para controlar a execução do programa, reter resultados temporários e para outras finalidades. Em geral, os registradores visíveis no nível de microarquitetura, como TOS e MAR na Figura 4.1, não o são no nível SA. Contudo, alguns deles, como o contador de programa e o ponteiro de pilha, são visiveis em ambos os níveis. Por outro lado, registradores visíveis no nível SA são sempre visíveis no nível da microarquitetura, já que é ali que são implementados. Registradores de nível SA podem ser divididos em duas categorias: de uso especial e de uso geral. Os de uso especial incluem coisas como o contador de programa e o ponteiro de pilha, bem como outros registradores com uma função específica. Ao contrário, os registradores de uso geral estão ali para conter as variáveis locais funda- mentais e resultados intermediários de cálculos. Sua função principal é prover acesso rápido a dados muito usados (basicamente evitando acessos à memória). Máquinas RSC, com suas CPUs velozes e memórias (relativamente) len- tas, costumam ter ao menos 32 registradores de uso geral, e a tendência em novos projetos de CPU é ter ainda mais. Em algumas máquinas, os registradores de uso geral são completamente simétricos e intercambiáveis. Se os registradores forem todos equivalentes, um compilador pode usar R1 para reter um resultado temporário, mas também pode usar R25 da mesma forma. A escolha de registrador não importa. Todavia, em outras máquinas, alguns dos registradores de uso geral podem ser um tanto especiais. Por exemplo, no Core i7 há um registrador denominado EDX, que pode ser usado como registrador geral, mas que também recebe metade do produto em uma multiplicação e retém metade do dividendo em uma divisão. Mesmo quando os registradores de uso geral são completamente intercambiáveis, é comum que o sistema ope- racional ou compiladores adotem convenções sobre como eles são usados. Por exemplo, alguns registradores podem conter parâmetros para procedimentos chamados e outros podem ser usados como transitórios. Se um compilador colocar uma variável local importante em R1 e depois chamar um procedimento de biblioteca que pensa que R1 é um registrador transitório disponível para ele, quando o procedimento de biblioteca retornar, R1 poderá conter lixo. Se houver convenções em nível de sistema sobre como os registradores devem ser usados, aconselhamos os compiladores e programadores em linguagem assembly a adotá-las para evitar problemas. Além dos registradores de nível SA visíveis aos programas do usuário, há sempre uma grande quantidade de registradores de uso especial, disponíveis somente em modo núcleo. Eles controlam as várias caches, memória, dispositivos de E/S e outros recursos de hardware da máquina. São usados apenas pelo sistema operacional, de modo que compiladores e usuários não precisam conhecê-los. Um registrador de controle, que é algo como um híbrido de núcleo/usuário, é o registrador de flags ou PSW (Program Status Word  palavra de estado do programa). Esse registrador contém vários bits diversos, necessá- rios pela CPU. Os mais importantes são os códigos de condição. Esses bits são ajustados a cada ciclo da ULA e refletem o estado do resultado da operação mais recente. Entre os bits de condição típicos estão: N – Marcado quando o resultado foi Negativo. Z – Marcado quando o resultado foi Zero.  – Marcado quando o resultado causou um transbordo (overflow) C – Marcado quando o resultado causou um vai-um (Carry) do bit da extrema esquerda. A – Marcado quando houve um vai-um do bit 3 (vai-um Auxiliar – veja a seguir). P – Marcado quando o resultado teve Paridade par. Os códigos de condição são importantes porque as instruções de comparação e desvio condicional (também denominadas instruções de salto condicional) os utilizam. Por exemplo, a instrução CMP normalmente subtrai dois operandos e ajusta os códigos de condição com base na diferença. Se os operandos forem iguais, então a dife- rença será zero, e o bit de código de condição Z no registrador PSW será marcado. Uma instrução BEQ (Branch EQual) subsequente testa o bit Z e desvia se ele estiver marcado.
  • 295. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 276 O PSW contém mais do que apenas códigos de condição, mas o conteúdo total varia de uma máquina para outra. Campos adicionais típicos são o modo da máquina (por exemplo, usuário ou núcleo), o bit de rastreamento (usado para depuração), o nível de prioridade da CPU e o estado de habilitação de interrupção. Muitas vezes, o PSW pode ser lido em modo usuário, mas alguns dos campos só podem ser escritos em modo núcleo (por exemplo, o bit de modo usuário/núcleo). 5.1.4 Instruc o es A principal característica do nível SA é o seu conjunto de instruções de máquina, que controlam o que a máquina pode fazer. Há sempre instruções LOAD e STORE (de uma forma ou de outra) para mover dados entre a memória e registradores e instruções MOVE para copiar dados entre os registradores. nstruções aritméticas estão sempre presentes, assim como instruções booleanas e aquelas para comparar itens de dados e desviar conforme os resultados. Já vimos algumas instruções SA típicas (veja a Figura 4.11) e estudaremos muitas mais neste capítulo. 5.1.5 Visa o geral do n vel ISA do Core i7 Neste capítulo, discutiremos três SAs muito diferentes: a A-32 da ntel, incorporada no Core i7; a arquitetura ARM v7, executada no sistema-em-um-chip OMAP4430; e a arquitetura de 8 bits AR, usada pelo microcontrolador ATmega168. A intenção não é dar uma descrição exaustiva de quaisquer delas, mas demonstrar aspectos importan- tes de uma SA e mostrar como esses aspectos podem variar de uma SA para outra. amos começar com o Core i7. O processador Core i7 evoluiu por muitas gerações, e sua linhagem pode ser rastreada até alguns dos mais antigos microprocessadores que já foram construídos, como discutimos no Capítulo 1. Embora a SA básica mantenha total suporte para execução de programas escritos para os processadores 8086 e 8088 (que tinham a mesma SA), também contém sobras do 8080, um processador de 8 bits popular na década de 1970. O 8080, por sua vez, sofreu forte influência das restrições de compatibilidade com o processador 8008, mais antigo ainda, que era baseado no 4004, um chip de 4 bits usado na época em que os dinossauros vagavam pela Terra. Do ponto de vista estrito do software, o 8086 e o 8088 eram máquinas normais de 16 bits (embora o 8088 tivesse um barramento de dados de 8 bits). O sucessor deles, o 80286, também era uma máquina de 16 bits. Sua principal vantagem era um espaço de endereço maior, embora poucos programas o usassem, já que ele consistia em 16.384 segmentos de 64 KB, em vez de uma memória linear de 230 bytes. O 80386 foi a primeira máquina de 32 bits da família ntel. Todas as que vieram depois dela (80486, Pentium, Pentium Pro, Pentium , Pentium , Pentium 4, Celeron, eon, Pentium M, Centrino, Core 2 duo, Core i7 etc.) têm na essência a mesma arquitetura de 32 bits do 80386, denominada I-32, e portanto é essa que focalizaremos aqui. A única alteração importante na arquitetura desde o 80386 foi a introdução das instruções MM, SSE e SSE2 em versões mais recentes da série x86. Essas instruções têm alto grau de especialização e foram projetadas para melhorar o desempenho em aplicações multimídia. Outra extensão importante foi o x86 de 64 bits (normalmente denominado x86-64), que aumentou os cálculos de inteiros e o tamanho do endereço virtual para 64 bits. Embora quase todas as extensões fossem introduzidas pela ntel e, mais tarde, executadas pelos concorrentes, esse foi um caso em que a AMD introduziu uma extensão que a ntel teve de adotar. O Core i7 tem três modos de operação, dois dos quais o fazem agir como um 8088. No modo real, todas as características que foram acrescentadas desde o 8088 são desligadas e o Core i7 se comporta como um simples 8088. Se algum programa fizer algo errado, a máquina inteira falha. Se a ntel tivesse projetado seres humanos, ela teria inserido um bit que os faria voltar ao modo chimpanzé – grande parte do cérebro desativada, não falaria, dormiria em árvores, comeria principalmente bananas etc. Um degrau acima é o modo virtual 8086, que possibilita executar antigos programas 8088 de modo prote- gido. Nesse modo, um sistema operacional real está no controle de toda a máquina. Para executar um programa 8088 antigo, o sistema operacional cria um ambiente isolado especial que age como um 8088, exceto que, se seu programa falhar, o sistema operacional é avisado, em vez de a máquina falhar. Quando um usuário do Windows inicia uma janela MS-DOS, o programa ali executado é iniciado em modo virtual 8086 para proteger o próprio Windows contra o mau comportamento de programas MS-DOS.
  • 296. C a p  t u l o 5 O n  v e l d e a r q u i t e t u r a d o c o n j u n t o d e i n s t r u c  a  o 277 O modo final é o modo protegido, no qual o Core i7 age de fato como um Core i7 em vez de um 8088 muito caro. Há quatro níveis de privilégio disponíveis, controlados por bits no PSW. O nível 0 corresponde ao modo núcleo em outros computadores e tem acesso total à máquina. É usado pelo sistema operacional. O nível 3 é para programas do usuário. Ele bloqueia o acesso a certas instruções críticas e controla registradores para impedir que um programa do usuário trapaceiro faça a máquina inteira falhar. Os níveis 1 e 2 pouco são usados. O Core i7 tem um espaço de endereço enorme, com memória dividida em 16.384 segmentos, cada um indo do endereço 0 ao endereço 232 – 1. Contudo, a maioria dos sistemas operacionais (incluindo o UN e todas as versões do Windows) aceita apenas um segmento; portanto, o que a maioria dos programas de aplicação vê, na verdade, é um espaço de endereço linear de 232 bytes e, às vezes, parte desse espaço está ocupado pelo sistema operacional. Todos os bytes no espaço de endereço têm seu próprio endereço, sendo que as palavras têm 32 bits de comprimento. Palavras são armazenadas em formato little-endian (o byte menos significativo tem o endereço mais baixo). Os registradores do Core i7 são mostrados na Figura 5.3. Os quatro primeiros, EAX, EBX, ECX e EDX, são registradores de 32 bits, mais ou menos de uso geral, embora cada um tenha suas próprias peculiaridades. O EAX é o principal registrador aritmético; o EBX é bom para conter ponteiros (endereços de memória); o ECX tem uma função na execução de laços; o EDX é necessário para multiplicação e divisão e, junto com o EAX, retém produtos e dividendos de 64 bits. Cada um deles contém um registrador de 16 bits nos 16 bits de ordem baixa e um de 8 bits nos 8 bits de ordem baixa. Esses registradores facilitam a manipulação de quantidades de 16 e 8 bits, respectivamente. O 8088 e o 80286 tinham só os registradores de 8 e 16 bits. Os registradores de 32 bits foram adicionados com o 80386, junto com o prefixo E, que representa Extended (estendido). Figura 5.3 Principais registradores do Core i7. EAX AL AH A X EBX BL BH B X ECX CL CH C X EDX ESI EDI EBP ESP DL CS EIP EFLAGS SS DS ES FS GS DH D X 8 8 16 Bits
  • 297. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 278 Os quatro seguintes são, de certa forma, de uso geral, porém, com mais peculiaridades. A tarefa dos regis- tradores ESI e EDI é conter ponteiros para a memória, em especial para as instruções de manipulação de cadeias por hardware, nas quais o ESI aponta para a cadeia de fonte e EDI aponta para a cadeia de destino. O registrador EBP também é um registrador de ponteiro. Ele é usado para apontar para a base do quadro de pilha corrente, o mesmo que LV na JM. Quando um registrador como EBP é usado para apontar para a base do quadro de pilha local, costuma ser denominado ponteiro de quadro. Por fim, ESP é o ponteiro de pilha. O próximo grupo de registradores, de CS até GS, são registradores de segmento. Até certo ponto, eles são trilo- bitas eletrônicos, fósseis antigos que restaram de uma época em que o 8088 tentava endereçar 220 bytes de memória usando endereços de 16 bits. Basta dizer que, quando o Core i7 é ajustado para usar um único espaço de endereços linear de 32 bits, eles podem ser ignorados sem problema algum. O seguinte é o EIP, que é o contador de programa (Extended nstruction Pointer – ponteiro de instrução estendido). Por fim, chegamos ao EFLAGS, que é o PSW. 5.1.6 Visa o geral do n vel da ISA ARM do OMAP4430 A arquitetura ARM foi apresentada pela primeira vez em 1985 pela Acorn Computer. Era inspirada nas pesquisas realizadas em Berkeley na década de 1980 (Patterson, 1985; Patterson e Séquin, 1982). A arquitetura ARM original (denominada ARM2) era uma arquitetura de 32 bits que aceitava um espaço de endereço de 26 bits. O OMAP4430 utiliza a microarquitetura ARM Cortex A9, que executa a versão 7 da ARM, e essa é a SA que descreveremos neste capítulo. Para manter a coerência com o resto do livro, aqui vamos nos referir à OMAP4430 mas, no nível SA, todos os projetos baseados na ARM Cortex A9 implementam a mesma SA. A estrutura de memória do OMAP4430 é limpa e simples: a memória endereçável é um arranjo linear de 232 bytes. Processadores ARM são bi-endian, de modo que acessam a memória com a ordem big-endian ou little- -endian. A escolha é feita com base em um bloco de memória do sistema que é lido logo após a inicialização do processador. Para garantir que o bloco de memória seja lido corretamente, ele deve estar no formato little-endian, mesmo que a máquina deva ser configurada para operação em big-endian. É importante que a SA tenha um limite maior do que as execuções necessitam, porque é quase certo que futuras implementações precisarão aumentar o tamanho da memória que o processador pode acessar. O espaço de endereços de 32 bits da SA ARM está dando muito trabalho a diversos projetistas, pois muitos sistemas baseados na ARM, como smartphones, já têm mais de 232 bytes de memória. Até agora, os projetistas têm trabalhado em torno desses problemas tornando a maior parte da memória um armazenamento de drive flash, que é acessado com uma interface de disco com suporte para um espaço de endereços maior, orientado a bloco. Para resolver essa limitação com potencial para matar o mercado, a ARM (a empresa) publicou recentemente a definição da SA ARM versão 8, que aceita espaços de endereços de 64 bits. Um dos problemas mais sérios encontrados por arquiteturas bem-sucedidas é que suas SAs limitavam a quantidade de memória endereçável. Na ciência da computação, o único erro que não pode ser contornado é não ter bits suficientes. Um dia nossos netos nos perguntarão como, antigamente, os computadores conseguiam fazer algo tendo somente endereços de 32 bits e apenas 4 GB de memória real, quando um joguinho médio precisa de 1 TB só para ser iniciado. A SA ARM é limpa, embora a organização dos registradores seja um tanto complexa, em uma tentativa de simplificar algumas codificações de instrução. A arquitetura mapeia o contador de programa para o arquivo de registradores de inteiros (como o registrador R15), pois isso permite que sejam criados desvios com operações da ULA que tenham R15 como registrador de destino. A experiência tem mostrado que a organização de registra- dores não vale o trabalho que dá, mas aquela antiga regra de compatibilidade não permite que nos livremos dela. A SA ARM tem dois grupos de registradores: 16 de uso geral de 32 bits e 32 de ponto flutuante de 32 bits (se houver suporte para o coprocessador FP). Os registradores de uso geral são denominados R0 até R15, embora outros nomes sejam usados em certos contextos. Os nomes alternativos e as funções dos registradores são mostrados na Figura 5.4.
  • 298. C a p  t u l o 5 O n  v e l d e a r q u i t e t u r a d o c o n j u n t o d e i n s t r u c  a  o 279 Figura 5.4 Registradores gerais da ARM versa o 7. Registrador Nome alternativo Função R0–R3 A1–A4 Mantém parâmetros para o procedimento que está sendo chamado R4–R11 V1–V8 Mantém variáveis locais para o procedimento atual R12 IP Registrador de chamada dentro do procedimento (para chamadas de 32 bits) R13 SP Ponteiro de pilha R14 LR Registrador de ligação (endereço de retorno para função atual) R15 PC Contador de programa Todos os registradores gerais têm 32 bits de largura e podem ser lidos e escritos por diversas instruções de carga e armazenamento. Os usos atribuídos na Figura 5.4 são baseados, em parte, na convenção, mas também, em parte, no modo como o hardware os trata. Em geral, não é sensato nos desviarmos das utilizações relacionadas na figura, a menos que sejamos faixa preta em ARM e que realmente, mas realmente, saibamos o que estamos fazen- do. Cabe ao compilador ou programador a responsabilidade de garantir que o programa acesse os registradores de modo correto e efetue neles o tipo certo de aritmética. Por exemplo, é muito fácil carregar números de ponto flutuante nos registradores gerais e então efetuar adição de inteiros neles, uma operação que produzirá total e absoluto absurdo, mas que a CPU realizará com alegria se assim for instruída. Os registrados Vx são usados para reter constantes, variáveis e ponteiros que são necessários em procedi- mentos, embora possam ser armazenados e recarregados em entradas e saídas de procedimento, se for preciso. Os registradores Ax são usados para passar parâmetros a procedimentos a fim de evitar referências à memória. Mais adiante, explicaremos como isso funciona. Quatro registradores dedicados são usados para finalidades especiais. O registrador IP contorna as limitações da instrução de chamada funcional da ARM (BL), que não pode endereçar totalmente todos os seus 232 bytes de espaço de endereços. Se o destino de uma chamada estiver muito distante para que seja expresso pela instrução, esta chamará um trecho de código “embutido”, que usa o endereço no registrador IP como destino da chamada de função. O registrador SP indica o topo da pilha atual e flutua à medida que as palavras são colocadas na pilha ou retiradas dela. O terceiro registrador de uso especial é LR. Ele é usado para manter o endereço de retorno nas chamadas de procedimento. O quarto, como já dissemos, é o contador de programa PC. Guardar um valor nesse registrador redireciona a busca de instruções para aquele endereço recém-depositado no PC. Outro registrador importante na arquitetura ARM é o de estado do programa (PSR), que mantém o estado dos cálculos anteriores da ULA, incluindo Zero, Negativo e Transbordo, entre outros bits. A SA ARM (quando configurada com o coprocessador FP) também tem 32 registradores de ponto flutu- ante de 32 bits. Esses registradores podem ser acessados diretamente, como 32 valores de ponto flutuante com precisão simples, ou como 16 valores de ponto flutuante de 64 bits com precisão dupla. O tamanho do registrador de ponto flutuante acessado é determinado pela instrução; em geral, todas as instruções ARM de ponto flutuante vêm com variantes de precisão simples e dupla. A arquitetura ARM é uma arquitetura carregar/armazenar. sto é, as únicas operações que acessam a memó- ria diretamente são as instruções LOAD e STORE, para mover dados entre os registradores e a memória. Todos os operandos para instruções aritméticas e lógicas devem vir de registradores, ou ser fornecidos pela instrução (e não pela memória), e todos os resultados devem ser salvos em um registrador (e não na memória).
  • 299. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 280 5.1.7 Visa o geral do n vel ISA AVR do ATmega168 Nosso terceiro exemplo é o ATmega168. Diferente do Core i7 (que é mais usado em máquinas de uso geral e conjuntos de servidores) e do OMAP4430 (que é usado principalmente em telefones, tablets e outros dispositivos móveis), o ATmega168 é usado em sistemas embutidos de classe mais baixa, como sinais de trânsito e rádios- -relógio, para controlar o dispositivo e gerenciar botões ou teclas, luzes e outras partes da interface de usuário. Nesta seção, faremos uma breve introdução técnica à SA AR do ATmega168. O ATmega168 tem um único modo e nenhuma proteção de hardware, já que nunca executa programas múltiplos que pertencem a usuários potencialmente hostis. O modelo de memória é de extrema simplicidade. Há 16 KB de memória para programas e um segundo 1 KB de memória para dados. Cada um tem seu próprio espaço de endereços, de modo que um endereço irá referenciar uma memória diferente, dependendo se o acesso é para a memória de programas ou dados. Os espaços de programa e dados são separados, para possibilitar a execução do espaço de programa em memória flash e o de dados em SRAM. árias implementações diferentes de memória são possíveis, dependendo do quanto o projetista quer pagar pelo processador. Na mais simples, o ATmega48, há uma memória flash de 4 KB para o programa e uma SRAM de 512 bytes para dados. Ambas, flash e RAM, estão dentro do chip. Essa quantidade de memória costuma ser suficiente para pequenas aplicações, e ter toda a memória no chip da CPU representa uma grande vantagem. O ATmega88 tem duas vezes mais memória em chip: 8 KB de ROM e 1 KB de SRAM. O ATmega168 usa uma organização de memória em duas camadas, oferecendo mais segurança ao programa. A memória flash para programas é dividida em uma seção de carregador de inicialização e uma seção de aplicação, com o tamanho de cada uma sendo determinado pelos bits de “fusível”, que são programados uma vez quando o microcontrolador é ligado inicialmente. Por motivos de segurança, somente o código executado pela seção de car- regador de inicialização pode atualizar a memória flash. Com esse recurso, qualquer código pode ser colocado na área de aplicação (incluindo aplicações baixadas de terceiros), com a certeza de que ela nunca sujará outro código no sistema (pois o código da aplicação estará rodando pelo espaço da aplicação, que não pode escrever na memória flash). Para amarrar de verdade um sistema, um fornecedor pode assinar o código digitalmente. Com código assina- do, o carregador de inicialização carrega o código na memória flash apenas se ele estiver assinado digitalmente por um fornecedor de software aprovado. Dessa forma, o sistema só rodará código que tenha sido “abençoado” por um fornecedor de software confiável. A técnica é bastante flexível, pois até mesmo o carregador de inicialização pode ser substituído, se o novo código tiver sido assinado digitalmente de forma apropriada. sso é semelhante ao modo como Apple e Tio garantem que o código rodando em seus dispositivos é seguro contra danos. O ATmega168 contém 32 registradores de uso geral de 8 bits, que são acessados por instruções por meio de um campo de 5 bits, especificando qual deles usar. Os registradores são denominados R0 até R31. Uma proprie- dade peculiar dos registradores do ATmega168 é que eles também estão presentes no espaço de memória. O byte 0 do espaço de dados é equivalente a R0 do conjunto de registradores 0. Quando uma instrução muda R0 e mais tarde lê o byte de memória 0, ele encontra lá o novo valor de R0. De modo semelhante, o byte 1 da memória é R1, e assim por diante, até o byte 31. O arranjo pode ser visto na Figura 5.5. Diretamente acima dos 32 registradores de uso geral, nos endereços de memória 32 a 95, existem 64 bytes de memória reservados para acessar registradores de dispositivo de E/S, incluindo os dispositivos internos do sistema-em-um-chip. Além dos quatro conjuntos de oito registradores, o ATmega168 tem uma pequena quantidade de registrado- res de uso especial, cujos mais importantes aparecem na Figura 5.5. O registrador de estado (SREG) contém, da esquerda para a direita, o bit de habilitação de interrupção, o de carga/armazenamento, o bit auxiliar de vai-um, o bit de sinal, o de transbordo, o flag de negativo, o flag de zero e o bit de vai-um. Todos esses bits de estado, exceto o de habilitação de interrupção, são marcados como resultado de operações aritméticas. O bit I do registrador de estado permite que as interrupções sejam habilitadas ou desabilitadas de modo glo- bal. Se o bit I for 0, todas as interrupções são desabilitadas. Limpar esse bit permite desabilitar quaisquer outras interrupções em uma única instrução. Marcar o bit permite que quaisquer interrupções atualmente pendentes sejam executadas, bem como as futuras. Cada dispositivo tem, associado a ele, um bit de habilitação de interrup- ção. Se o bit de habilitação do dispositivo estiver marcado e o bit I de habilitação global de interrupção estiver marcado, o dispositivo pode interromper o processador.
  • 300. C a p  t u l o 5 O n  v e l d e a r q u i t e t u r a d o c o n j u n t o d e i n s t r u c  a  o 281 Figura 5.5 Registrador no chip e organizac a o de memo ria do ATmega168. Memória do programa Memória da aplicação Carregador de inicialização Registrador de estado (SREG) Ponteiro de pilha (SP) Endereço 80 Registradores Memória de dados Dados temporários Memória de E/S 1023 95 32 31 0 Endereço 81 Alto Baixo 7 I T H S V N Z C 0 0 16383 O ponteiro de pilha SP mantém o endereço atual na memória de dados onde as instruções PUSH e POP acessarão seus dados, semelhante à instrução de mesmo nome na JM da Java, do Capítulo 4. O ponteiro de pilha está localizado na memória de E/S, no endereço 80. Um único byte de memória com 8 bits é muito pequeno para endereçar 1.024 bytes da memória de dados, de modo que o ponteiro de pilha é composto de dois locais conse- cutivos na memória, formando um endereço de 16 bits. 5.2 Tipos de dados Todos os computadores precisam de dados. Na verdade, há muitos sistemas de computação cujo único propósito é processar dados financeiros, comerciais, científicos, de engenharia ou outros. Os dados têm de ser representados de alguma forma específica no interior do computador. No nível SA, são usados vários tipos de dados diferentes, que serão explicados a seguir. Uma questão fundamental é se há ou não suporte de hardware para um tipo particular de dados. Suporte de hardware significa que uma ou mais instruções esperam dados em um formato particular e o usuário não tem liberdade de escolher um diferente. Por exemplo, os contadores têm o hábito peculiar de escrever números negativos com um sinal de menos à direita do número em vez de à esquerda, onde os cientistas da computação o colocam. Suponha que, em um esforço de impressionar o patrão, o chefe do centro de computação de um escri- tório de contabilidade altere todos os números, em todos os computadores, para usar o bit da extrema direita (e não o da extrema esquerda) como o bit de sinal. Sem dúvida, isso impressionaria muito o patrão – porque, de pronto, todo o software deixaria de funcionar corretamente. O hardware espera certo formato para inteiros e não funciona direito quando recebe qualquer outra coisa. Agora, considere outro escritório de contabilidade, que acabou de firmar um contrato para verificar a dívida federal (quanto o governo dos Estados Unidos deve a todos os cidadãos). Usar aritmética de 32 bits não funcio- naria nesse caso, porque os números envolvidos são maiores do que 232 (cerca de 4 bilhões). Uma solução é usar dois inteiros de 32 bits para representar cada número, o que dá 64 bits no total. Se a máquina não suportar esse tipo de número de dupla precisão, toda a aritmética efetuada com eles teria de ser executada em software, mas as duas partes podem estar em qualquer ordem, já que o hardware não se importa. Esse é um exemplo de tipo de dados sem suporte de hardware e, por isso, sem uma determinada representação requerida em hardware. Nas seções seguintes, examinaremos tipos de dados suportados pelo hardware e, por conseguinte, dados para os quais são exigidos formatos específicos.
  • 301. O r g a n i z a c  a  o e s t r u t u r a d a d e c o m p u t a d o r e s 282 5.2.1 Tipos de dados nume ricos Os tipos de dados podem ser divididos em duas categorias: numéricos e não numéricos. O principal entre os tipos de dados numéricos são os inteiros. Eles podem ter muitos comprimentos, em geral 8, 16, 32 e 64 bits. nteiros contam coisas (por exemplo, o número de chaves de fenda que uma loja de ferragens tem em estoque), identificam coisas (por exemplo, números de contas correntes) e muito mais. A maioria dos computadores modernos armazena inteiros em notação binária de complemento de dois, embora outros sistemas já tenham sido usados no passado. Números binários serão discutidos no Apêndice A. Alguns computadores suportam inteiros sem sinal, bem como inteiros com sinal. No caso de um inteiro sem sinal, não há bit de sinal e todos os bits contêm dados. Esse tipo de dado tem a vantagem de um bit extra, portanto, por exemplo, uma palavra de 32 bits pode conter um único inteiro sem sinal na faixa de 0 a 232 – 1, inclusive. Ao contrário, um inteiro de 32 bits com sinal, representado por complemento de dois, só pode mani- pular números até 231 – 1, mas, é claro, também pode manipular números negativos. Para números que não podem ser expressos como um inteiro, como 3,5, são usados números de ponto flu- tuante. Esses números serão discutidos no Apêndice B. Eles têm comprimentos de 32, 64 ou, às vezes, 128 bits. A maioria dos computadores tem instruções para efetuar aritmética de ponto flutuante. Muitos deles têm regis- tradores separados para conter operandos inteiros e para conter operandos de ponto flutuante. Algumas linguagens de programação, em especial COBOL, permitem números decimais como um tipo de dado. Máquinas que querem ser amigáveis à linguagem COBOL costumam suportar números decimais em hard- ware, normalmente codificando um dígito decimal em 4 bits e então empacotando dois dígitos decimais por byte (formato decimal em código binário). Todavia, a aritmética binária não funciona direito em números decimais empacotados, portanto, são necessárias instruções especiais de correção de aritmética decimal. Essas instruções precisam conhecer o vai-um do bit 3. É por essa razão que o código de condição muitas vezes contém um bit auxiliar de vai-um. A propósito, o problema do Y2K (bug do ano 2000), tão comentado, foi causado por progra- madores COBOL que decidiram que poderiam representar o ano com dois dígitos decimais (8 bits) em vez de quatro dígitos decimais (ou um número binário de 8 bits), que podem manter ainda mais valores (256) do que dois dígitos decimais (100). Grande otimização! 5.2.2 Tipos de dados na o nume ricos Embora quase todos os primeiros computadores ganhassem suas vidas triturando números, computadores modernos são usados com frequência para aplicações não numéricas, como e-mail, navegar pela Web, fotografia digital e criação e reprodução de multimídia. Para essas aplicações, são necessários outros tipos de dados, que muitas vezes são suportados por instruções de nível SA. Nesse caso, é clara a importância dos caracteres, embo- ra nem todos os computadores ofereçam suporte de hardware para eles. Os códigos mais comuns são ASC e Unicode. Eles suportam caracteres de 7 bits e de 16 bits, respectivamente. Ambos foram discutidos no Capítulo 2. Não é incomum que o nível SA tenha instruções especiais destinadas a manipular cadeias de caracteres, isto é, carreiras consecutivas de caracteres. Essas cadeias às vezes são delimitadas por um caractere especial na extremidade. Como alternativa, um campo de comprimento de cadeia pode ser usado para monitorar essa extre- midade