Resumo - Centro de Ciências Exatas e da Terra

Transcrição

Resumo - Centro de Ciências Exatas e da Terra
Universidade Federal do Rio Grande do Norte
Centro de Ciências Exatas e da Terra
Departamento de Informática e Matemática Aplicada
Curso de Ciências da Computação
Uma Plataforma para Sistemas Embarcados:
Desenvolvimento e Avaliação de Desempenho de um
Processador RTL e uma Cache L1 usando SystemC
RELATÓRIO DE GRADUAÇÃO
José Diego Saraiva da Silva
Natal/RN, Dezembro de 2006
José Diego Saraiva da Silva
Uma Plataforma para Sistemas Embarcados:
Desenvolvimento e Avaliação de Desempenho de um
Processador RTL e uma Cache L1 usando SystemC
Trabalho apresentado como requisito para aprovação na disciplina Relatório de Graduação, ministrada pelo professor Bruno Motta de Carvalho
Orientador: Prof. Dr. Ivan Saraiva Silva
Uma Plataforma para Sistemas Embarcados: Desenvolvimento e
Avaliação de Desempenho de um Processador RTL e uma Cache L1
usando SystemC
José Diego Saraiva da Silva
Esta relatório de graduação foi avaliado e considerado aprovado pelo Curso de Ciências da Computação do Departamento de Informática e Matemática Aplicada da Universidade Federal do Rio
Grande do Norte.
Prof. Dr. Ivan Saraiva Silva
Orientador
Banca Examinadora:
Prof. Dr. Bruno Motta de Carvalho
Membro
Profa. Dra. Elizabeth Ferreira Gouvêa Goldbarg
Membro
ii
AGRADECIMENTOS
A Deus, por me abençoar e conceder várias oportunidades, embora nem sempre tenha sido
merecedor.
Aos meus pais e ao meu irmão Diógenes, pelo apoio e reconhecimento em todos os momentos. Por me ajudarem a me manter firme em todos os momentos. Muito Obrigado.
Aos Professor Ivan Saraiva, meu orientador, por acreditar no sucesso deste trabalho e, principalmente, pelo incentivo.
À minha amiga Tássia, por contribuir no desenvolvimento dos algoritmos de substituição
e por me ajudar nos estudos durante o curso. E aos meus amigos Guilherme e Ronualdo, por
transmitirem conhecimentos valiosos.
iii
Este trabalho foi desenvolvido com o apoio da Agência Nacional do Petróleo, através do Programa de Formação de Recursos Humanos No 22 - Formação em Geologia, Geofísica e Informática no Setor Petróleo e Gás Natural na UFRN - com especialização em Sistemas em Tempo
Real para Otimização e Automação do Setor Petróleo e Gás Natural.
iv
Resumo
Diversos setores da indústria do petróleo e gás natural necessitam de soluções computacionais
com alto poder de processamento, alta escalabilidade e com capacidade para se comunicar com
o meio através de sensores e atuadores ou através de outros sistemas. Neste contexto, os sistemas
embarcados apresentam-se como ótimas soluções computacionais.
Este trabalho consiste na modelagem, design e implementação de um processador SPARC V8
e módulos de cache L1 para a concepção de uma plataforma MP-SoC para sistemas embarcados
voltada para o setor de petróleo e gás natural.
A plataforma atualmente é composta pelos seguintes componentes: processador SPARC
V8, módulo de Cache, módulo de Memória, módulo de Diretório e dois diferentes modelos
de Network-on-Chip, a NoCX4 e a Árvore Obesa. Todos os módulos de cache foram implementados utilizando a linguagem de descrição de hardware SystemC.
Palavras-chave: SPARC, Cache, Sistemas Embarcados, System-on-Chip, Network-on-Chip,
Projeto Baseado em Plataforma, SystemC.
v
Abstract
Many sectors from oil and natural gas industry need computational solutions with huge processing capabilities, high scalability and ability to communicate with the environment through
sensors, actuators and even other systems. In this context, embedded systems are presented as an
excellent computational solutions.
This work consists in the modeling, design and implementation of a SPARC V8 processor and
L1 Cache Modules in order to compose an MP-SoC Plataform for embedded systems, focusing
the oil and natural gas sector.
Currently the platform is composed of the following components: SPARC V8 processor,
Cache module, Memory module, Directory module and two different modules of network-onchip, NoCX4 and Obese tree. All modules were implemented using using the SystemC hardware
description language.
Key words: SPARC, Cache, Embedded Systems, System-on-Chip, Network-on-Chip, PlatformBased, SystemC.
vi
Sumário
1
INTRODUÇÃO
1
2
METODOLOGIA
2.1 Implementação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.1 Montador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2 Validação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
6
6
6
3
PROJETO BASEADO EM PLATAFORMA
3.1 A Plataforma STORM . . . . . . . . . .
3.1.1 CaCoMa . . . . . . . . . . . . .
3.1.2 Diretório . . . . . . . . . . . . .
3.1.3 Memória . . . . . . . . . . . . .
3.1.4 Interconexão . . . . . . . . . . .
4
SPARC V8
4.1 A Arquitetura SPARC V8 . . . . . . . . .
4.1.1 Formato de Instruções . . . . . .
4.1.2 Conjunto de Instruções . . . . . .
4.1.3 Conjunto de Registradores . . . .
4.1.4 Formatos de Dados . . . . . . . .
4.1.5 Modo Usuário e Modo Supervisor
4.1.6 Modelo de Memória . . . . . . .
4.1.7 Modos de Endereçamento . . . .
4.1.8 Tratamento de Interrupções . . .
4.1.9 Instruções de LDSTUB e SWAP .
4.1.10 Sincronismo das Instruções . . . .
4.1.11 Mecanismos de bypassing . . . .
vii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
8
12
12
13
13
14
.
.
.
.
.
.
.
.
.
.
.
.
16
17
19
20
21
23
24
24
25
26
27
28
28
4.2
5
6
4.1.12 Previsão de Desvios . . . . . .
4.1.13 Unidade de Controle Distribuída
O Sistema de Caches . . . . . . . . . .
4.2.1 Mapeamento . . . . . . . . . .
4.2.2 Política de Substituição . . . . .
4.2.3 Política de Atualização . . . . .
4.2.4 Tamanho do Bloco . . . . . . .
Experimentos Computacionais
5.1 Simulações . . . . . . . . . . . . . . .
5.1.1 Fatorial . . . . . . . . . . . . .
5.1.2 Seqüência de Fibonacci . . . . .
5.1.3 Run-length encoding - RLE . .
5.1.4 Cifra de César . . . . . . . . .
5.1.5 Busca Binária . . . . . . . . . .
5.1.6 MergeSort . . . . . . . . . . .
5.1.7 Algoritmo de Prim . . . . . . .
5.1.8 Cifra de Hill . . . . . . . . . .
5.1.9 JPEG . . . . . . . . . . . . . .
5.2 Análise dos Parâmetros da Cache . . . .
5.3 Análise dos Algoritmos de Substituição
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
29
30
30
32
33
38
38
.
.
.
.
.
.
.
.
.
.
.
.
39
39
40
42
42
44
45
46
47
48
50
52
53
CONCLUSÃO
55
6.1 Trabalho Futuros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
viii
Lista de Figuras
2.1
Duas metodologias de projeto (a) Metodologia tradicional; (b) Metodologia SystemC. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
3.1
3.2
3.3
3.4
3.5
Retorno financeiro de projeto em função do tempo de projeto.
Retorno financeiro de projeto em função do tempo de projeto.
Módulos da STORM . . . . . . . . . . . . . . . . . . . . . .
Topologia NoCX4. . . . . . . . . . . . . . . . . . . . . . . .
Topologia Árvore Obesa. . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
9
11
12
14
14
4.1
4.2
4.3
4.4
4.5
4.6
4.7
Visão geral da Arquitetura SPARC V8.
Visão geral do SPARC. . . . . . . . .
Formatos de instruções . . . . . . . .
Janela de Registradores. . . . . . . . .
Mecanismo de bypassing. . . . . . . .
Árvore de decisão do pseudo-LRU. . .
Fluxo lógico de uma cache SLRU. . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
18
18
20
22
29
34
36
5.1
5.2
Figura utilizada na simulação do JPEG. . . . . . . . . . . . . . . . . . . . . . . 52
Associatividade versus Tamanho da Cache. . . . . . . . . . . . . . . . . . . . . 53
ix
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Lista de Tabelas
4.1
4.2
4.3
4.4
4.5
4.6
conjunto de instruções do SPARC. . . . . . . . . . . . . .
Equivalente SPARC de outros modos de endereçamento. .
Número de ciclos gasto para execução de instruções. . . .
Identificadores de espaço de endereçamento. . . . . . . . .
Representação da árvore binária em forma de string de bits.
Atualização dos bits de estados. . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
21
25
28
31
35
35
5.1
5.2
5.3
5.4
5.5
5.6
5.7
5.8
5.9
5.10
5.11
5.12
Template das tabelas de resultados. . . . . . . . . . . . . . . . . .
Resultados do Fatorial em assembler. . . . . . . . . . . . . . . . .
Resultados do Fatorial desenvolvido em C. . . . . . . . . . . . . .
Resultados do Fibonacci. . . . . . . . . . . . . . . . . . . . . . .
Resultados do RLE. . . . . . . . . . . . . . . . . . . . . . . . . .
Resultados do algoritmo cifra de César. . . . . . . . . . . . . . .
Resultados da Busca Binária. . . . . . . . . . . . . . . . . . . . .
Resultados do Mergesort. . . . . . . . . . . . . . . . . . . . . . .
Resultados do Prim. . . . . . . . . . . . . . . . . . . . . . . . . .
Resultados da simulação do algoritmo Hill. . . . . . . . . . . . .
Resultados da simulação do JPEG. . . . . . . . . . . . . . . . . .
Tamanho versus Algoritmo de Substituição versus Taxa de acerto.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
39
41
41
42
43
44
46
47
48
50
51
54
x
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Lista de Siglas
P&G
STORM
CISC
RISC
SPARC
RTL
CI
SoC
NoC
VLIW
DSP
ASIPs
RTOS
NRE
CaCoMa
IU
FPU
CP
PC
ULA
EF
PSR
EC
Bicc
FBfcc
Petróleo e Gás Natural
MP-Soc DirecTory-Based PlatfORM
Complex Instruction Set Computer
Reduced Instruction Set Complex
Scalable Processor ARChitecture
Register Transfer Level
Circuito Integrado
System-on-Chip
network-on-chip
Very-Long Instruction Word
Digital Signal Processing
Application Specific Integrated Processor
Real Time Operating Systems
Non-Recurrent Engineering
Cache Communication Manager
Integer Unit
Floating-Point Unit
Co-Processador
Program Counter
Unidade Lógico-Aritmética
Enable Floating
Processor Status Register
Enable_Coprocessor
Branch on Integer Condition Codes
Branch on Floating-point Condition Codes
xi
CBccc
CWP
WIN
TBR
TSO
ASR
FSR
ET
TEM
PIL
tt
ASI
LDA
STA
FIFO
LFU
LRU
SLRU
ASCII
DCT
Branch on Coprocessor Condition Codes
Current Window Point
Window Invalid Mask
Trap Base Register
Total Store Order
Ancillary State Register
FPU Status Register
Enable Trap
Trap Enable Mask
Processor Interrupt Level
Trap Type
Address Space Identifier
Load Word from Alternate space
Store Word into Alternate space
First-In-First-Out
Least Frequently Used
Least Recently Used
Segmented Least Frequently Used
American Standard Code for Information Interchange
Discrete Cossine Transform
xii
Capítulo 1
INTRODUÇÃO
Vários problemas encontrados na indústria do petróleo e gás natural (P&G) exigem soluções
computacionais que atendam a requisitos rígidos de tempo na operação do sistema, baixo consumo de energia e elevado grau de processamento para atender a grande demanda de dados produzidas pelos vários sensores que monitoram ou controlam o meio. Neste contexto os sistemas
embarcados apresentam-se como ótimas soluções computacionais. Dentre as várias aplicações
dos sistemas embarcados na indústria do petróleo, temos: técnicas de avaliação de formações;
sistemas de detecção e controle de vazamento em dutos de petróleo; sistemas capazes de prover
mecanismos automáticos de posicionamento global em navios de plataformas de perfuração em
águas profundas.
As técnicas de avaliação de formações visam definir a capacidade produtiva e a valoração
das reservas de óleo e gás de uma jazida petrolífera. Estas técnicas se baseiam principalmente
na perfilagem de poço aberto, perfilagem de produção, nos testes de pressão e nos testes de
formação.
A perfilagem é o processo de traçar uma imagem visual ou perfil, em relação à profundidade,
de uma ou mais propriedades das rochas perfuradas. Tais perfis são obtidos através do deslocamento contínuo de sensores de perfilagem dentro do poço [22]. A perfilagem a poço aberto é feita
antes da descida do revestimento de produção e tem como objetivo a identificação da litologia
do poço, estimar a porosidade das rochas e detectar a presença de hidrocarbonetos leves ou gás.
Já a perfilagem de produção é feita após a descida do revestimento de produção e completação 1
inicial do poço. O objetivo desta perfilagem é determinar a efetividade de uma completação e as
condições de produtividade.
1
Conjunto de operações destinadas a preparar o poço para produzir óleo ou gás
CAPÍTULO 1. INTRODUÇÃO
2
As etapas de perfilagem geram um grande volume de informações sobre a espessura, profundidade e comportamento das camadas de rochas existentes nas vizinhanças do poço.
Os testes de pressão determinam as pressões no fundo do poço antes e durante a produção
de óleo ou gás. Conhecendo-se as pressões, as vazões e as propriedades dos fluídos produzidos,
pode-se obter informações a respeito da rocha-reservatório 2 .
Por fim, temos os testes de formação. O teste de formação é a técnica utilizada para confirmar
a presença de hidrocarboneto na formação e estimar a capacidade produtiva das zonas investigadas. Tal procedimento é baseado no estabelecimento de um diferencial de pressão entre esta zona
estudada e o interior do poço através da remoção da pressão hidrostática da coluna de lama que
se encontra acima de tal zona. Este diferencial de pressão permite que os fluidos da formação
penetrem na coluna vazia que foi descida no poço e alcancem a superfície. Os dados obtidos
nestes testes incluem a quantidade e qualidade dos fluidos produzidos, durante o intervalo de
tempo, assim como pressões de surgência e estática do reservatório.
Os dados coletados nos testes de avaliação de formações convencionais utilizam formato analógico de medição que são interpretados em algum momento após os testes feitos pelos técnicos.
O uso de sistemas embarcados pode permitir o monitoramento em tempo real do testes de
avaliação de formações, melhorar a precisão dos dados, pois coletam dados no formato digital, e
reduzir o tempo gasto na interpretação do grande volume de dados. Porém, o desenvolvimento de
sistemas embarcados é um processo complexo que envolve a definição da arquitetura de hardware
e de software a cada projeto. Isto dificulta a reutilização do sistema ou parte dele em outras
aplicações, além de aumentar o tempo e o custo do projeto.
Uma plataforma para projetos de sistemas embarcados foi iniciada no Programa de PósGraduação em Sistemas e Computação da Universidade Federal do Rio Grande do Norte por
[16]. Esta plataforma, denominada STORM (MP-Soc DirecTory-Based PlatfORM), visa diminuir o tempo e os custos de desenvolvimento de sistemas embarcados.
O presente trabalho alia-se a este esforço de desenvolvimento com o objetivo específico de
especializar esta plataforma para aplicações na área de exploração de petróleo e gás natural. As
aplicações desta área de atuação exigem soluções computacionais de alto poder de processamento, alta escalabilidade e com capacidade para se comunicar com o meio através de sensores,
atuadores ou através de outros sistemas.
O principal empecilho para a aplicação da STORM na área do petróleo e gás natural era a falta
de uma unidade de processamento capaz de prover alto poder de processamento, escabilidade e
a capacidade de comunicação à plataforma. Portanto, o objetivo deste trabalho é desenvolver
2
Rocha aonde ocorre o acumulo de petróleo. São rochas que possuem boa porosidade e permeabilidade.
CAPÍTULO 1. INTRODUÇÃO
3
um processador para a plataforma STORM que permita a mesma prover os recursos de hardware
necessários para o desenvolvimento de aplicações seqüências e distribuídas na área do petróleo
e gás.
Inicialmente, havia duas opções básicas na escolha do processador: A arquitetura CISC
(Complex Instruction Set Computer - Computador com um Conjunto Complexo de Instruções)
ou a arquitetura RISC (Reduced Instruction Set Complex - Conjunto Reduzido de Instruções
Complexas).
A primeira opção é baseada no desenvolvimento de instruções complexas e na microprogramação. A microprogramação significa que cada instrução é interpretada por um microprograma
localizado em uma memória interna à pastilha do processador. A segunda opção utiliza apenas
instruções simples, com execução direta, transferindo para o compilador a responsabilidade de
emular as funções mais complexas.
Os microprocessadores RISC possuem uma arquitetura interna mais simples, o que permite
que eles sejam implementados com tecnologia menos sofisticada, mais barata, e com menor gasto
de área, diminuindo os custos de fabricação. Estas qualidades fizeram dos microprocessadores
RISC as melhores opções para o mercado embutido, uma vez que, este mercado compete em
custo e energia. Estima-se que 90% do mercado embutido utilize a arquitetura RISC [10].
Dentre as várias arquiteturas RISC disponíveis, optou-se pelo processador SPARC V8. O
SPARC (Scalable Processor ARChitecture) [17] é uma arquitetura de microprocessador aberta
desenvolvida pela Sun Microsystems que permite a elaboração de implementações personalizadas, embora mantendo a compatibilidade binária. É um processador de porte variável, utilizado
em sistemas que vão desde sistemas embarcados até grandes servidores.
Ele foi escolhido para integração com a plataforma STORM por ter arquitetura aberta e pela
vasta gama de ferramentas disponíveis, dentre elas o compilador de C da GNU, o GCC [9], o
que facilita a simulação de aplicações reais, além de ser um compilador disponível em várias
arquiteturas de hardware e em vários sistemas operacionais.
Este texto está organizado da seguinte forma: O Capítulo 2 apresenta a metodologia adotada
no trabalho. O Capítulo 3 apresenta os conceitos e fundamentos do paradigma de concepção
de sistemas baseado em plataforma. Além disso, esta seção apresenta em detalhes a plataforma
STORM. O Capítulo 4 descreve em detalhes o processador SPARC V8 e o sistemas de cache
desenvolvidos no escopo deste trabalho. Os resultados dos experimentos computacionais realizados são apresentados no Capítulo 5. E por fim, o Capítulo 6 expõe as considerações finais
deste trabalho.
Capítulo 2
METODOLOGIA
O processador SPARC V8 e o sistema cache propostos neste trabalho foram implementados
utilizando a linguagem de descrição de hardware SystemC. De fato, o SystemC não é uma linguagem de descrição de hardware, mas sim uma biblioteca de classes C++ e uma metodologia
de desenvolvimento [20].
Tal biblioteca fornece ao C++ padrão características como temporização de hardware, atividade comportamental, concorrência e mecanismos de simulação. Desta maneira, o SystemC
combina as vantagens de C++ como popularidade, robustez e eficiência com uma biblioteca de
classes apropriada para a descrição de hardware.
O SystemC cria uma especificação executável do sistema. Uma especificação executável é
um programa em C++ que exibe o mesmo comportamento do sistema descrito quando executa.
Essa especificação executável provê muitos benefícios, tais como: evitar inconsistências e erros,
ajudar na verificação da completude da especificação, assegurar uma interpretação não ambígua
para a especificação do sistema, verificar a funcionalidade do sistema antes do início da sua
implementação, criar modelos de desempenho do sistema e estimar a performance do sistema
[20].
A metodologia de projeto, que adota a linguagem SystemC, pressupõe o refinamento progressivo do sistema, ou seja, inicia-se como uma aplicação puramente em C++ que refinada até o
nível RTL (Register Transfer Level - Nível de Transferência de Registradores). Esta metodologia
de projeto rompe com o paradigma tradicional de desenvolvimento de hardware.
Na metodologia tradicional de design, o desenvolvimento inicia-se com a construção de um
modelo em C ou C++ do sistema para verificar os algoritmos e conceitos no nível de sistema.
Após a validação dos conceitos e dos algoritmos, o modelo feito em C ou C++ é implementado
CAPÍTULO 2. METODOLOGIA
5
em hardware através transcrição do código para HDL 1 em um único passo. A Figura 2 resume
as diferenças entre as duas abordagens.
Figura 2.1: Duas metodologias de projeto (a) Metodologia tradicional; (b) Metodologia SystemC.
A abordagem tradicional possui três grande problemas que diminuem a produtividade e aumentam o tempo de projeto. O primeiro é a transcrição manual e em um único passo do modelo
em C para o modelo em HDL pela equipe de desenvolvedores. Este processo é tedioso e propício
a erros [20]. O segundo grande problema é desconexão do modelo em C do modelo em HDL.
Após a transcrição, o modelo em C fica rapidamente obsoleto pois o foco do desenvolvimento
passa a ser o modelo HDL. O último grande problema é o fato de que a equipe de desenvolvimento não pode utilizar o testbench desenvolvido para o modelo em alto nível diretamente no
modelo HDL. Ou seja, além do sistema, a equipe precisa ser transcrever toda a suíte de testes
para HDL.
A abordagem adotada pelo SystemC possui duas grandes vantagens sobre o modelo tradicional. A primeira é a metodologia de refinamento. Nesta metodologia, o projetista não converte a
descrição em C para HDL em um único passo. Ao invés disso, o projetista realiza vários refinamentos em pequenas seções, seguidos da verificação do atual modelo para uma eventual correção
de bugs. A segunda grande vantagem do uso do SystemC é o fato do projetista utilizar apenas
uma única linguagem no desenvolvimento do sistema. O que permite a reutilização direta do
1
Hardware description language ou HDL é uma classe de linguagem de computador para a descrição formal de
circuitos eletrônicos.
CAPÍTULO 2. METODOLOGIA
6
testbench desenvolvido, economizando o tempo gasto na conversão do mesmo.
2.1
Implementação
Os módulos previstos neste trabalho foram implementados utilizando a ferramenta SystemC.
Como foi dito anteriormente, esta ferramenta possibilita a implementação em diversos níveis de
abstração e precisão. Para este projeto definiu-se que os módulos devem apresentar precisão de
ciclos em suas operações. Este nível de descrição, denominado RTL cycle-accurate, foi escolhido
por permitir a verificação do comportamento da arquitetura ciclo a ciclo sem que se tenha que
implementar todas as portas e sinais da arquitetura bit a bit, e por ser o nível de descrição dos
outros módulos da plataforma STORM.
2.1.1
Montador
Um montador (assembler) SPARC foi desenvolvido junto com a plataforma STORM para permitir o desenvolvimento de aplicações em linguagem C para a plataforma. A função do montador
é fazer a conexão entre o compilador GCC e a plataforma STORM. O montador reconhece o
código gerado pelo GCC e produz um binário que é utilizado como entrada para a plataforma.
Por não ter um sistema operacional para a STORM, a gerência de memória é feita diretamente
pela plataforma e pelo montador. Isto obriga a plataforma a utilizar um esquema de alocação de
memória estática. Neste esquema, o tamanho de cada região da memória é definido em tempo
de compilação. Sendo de responsabilidade do montador alocar as variáveis globais, a memória
de programa e a região de pilha dos processadores.
2.2
Validação
A validação da plataforma STORM e dos módulos propostos neste trabalho foi realizada através de aplicações genéricas e específicas para a área do petróleo e gás natural. As aplicações
genéricas consistem em algoritmos de ordenação, criptografia, compactação de imagens, árvore
geradora mínima dentre outros. Estas aplicações são apresentadas com mais detalhes no Capítulo
5 e foram utilizadas para validar as questões mais rudimentares do funcionamento do processador como busca e decodificação de instruções, execução de saltos, acessos a memória, integração
do SPARC com a plataforma dentre outras questões de projeto.
CAPÍTULO 2. METODOLOGIA
7
As aplicações específicas para a área do petróleo e gás natural consistem de metaheurísticas
voltadas para o problema da rede de distribuição de gás natural. As metaheurísticas que foram
utilizadas para validar a plataforma são: Busca Tabu, GRASP e Algoritmos transgenéticos.
Todas essas aplicações foram desenvolvidas de forma seqüencial e paralela pela aluna Tássia
Freitas [7]. O desenvolvimento destas metaheurísticas objetiva validar a plataforma como um
todo, verificando o comportamento da mesma em ambientes seqüencias e paralelos que exigem
alto poder de processamento.
Capítulo 3
PROJETO BASEADO EM
PLATAFORMA
Nos últimos anos, a demanda por sistemas embarcados vem crescendo de maneira avassaladora
em diversas áreas e com diversos propósitos. Pode-se encontrar tais sistemas em carros, eletrodomésticos, aparelhos telefônicos, caixas eletrônicos de bancos, câmeras digitais, sistemas de
controle de vôo, etc.
Esta proliferação dos sistemas embarcados ocorreu devido ao aumento significativo da capacidade do Circuito Integrado (CI), o que permitiu a construção de sistemas inteiros em um único
chip (SoC - System-on-Chip).
Define-se como sistema embarcados todo sistema computacional de propósito especial, o
qual é completamente encapsulado pelo dispositivo que ele controla. O sistema embarcado tem
como principal característica o fato de sua principal funcionalidade não ser computacional, mas o
controle desta funcionalidade é computacional. Ou seja, os sistemas embarcados são desenhados
para realizar tarefas específicas.
A arquitetura de hardware de um SoC embarcado pode conter um ou mais processadores,
memórias, interfaces para periféricos e blocos dedicados. Os componentes são interligados por
uma estrutura de comunicação que pode variar de um barramento a redes de interconexão (NoC
- network-on-chip)[6].
Os processadores podem ser de tipos diversos (RISO, VLIW, DSP, até ASIPs - processadores
integrados para aplicações específicas), conforme a aplicação. No caso de sistemas contendo
componentes programáveis, o software de aplicação pode ser composto por múltiplos processos,
distribuídos entre diferentes processadores e comunicando-se através de mecanismos variados
[5].
CAPÍTULO 3. PROJETO BASEADO EM PLATAFORMA
9
Além disso, a arquitetura de um sistema embarcado pode conter um sistema operacional de
tempo real (RTOS) com a finalidade de oferecer serviços como comunicação, escalonamento de
processos, sincronização de tarefas, gerência de memória etc.
Em geral, nos projetos de sistemas embarcados é necessário definir toda a arquitetura de
software e hardware devido as limitações de poder computacional e capacidade de memória do
sistema. Assim, requisitos não funcionais como consumo de energia, tempo de resposta, segurança, tolerância à falhas, expectativa de vida e área ocupada também devem ser considerados
pelos projetistas. Estas características do projeto de sistemas embarcados implica em equipes
grandes de projetistas, tempos de projetos longos e caros.
A alta demanda exigida pelo mercado atual e a contínua evolução tecnológica impõe as empresas a desenvolverem novos sistemas embarcados em um curto espaço de tempo. Ou seja, as
empresas precisam diminuir o time-to-mark dos seus produtos.
Time-to-mark é o tempo decorrido desde o inicio do projeto até a sua disponibilização no
mercado. Um elevado time-to-mark representa maiores custos para o desenvolvimento do sistemas e ao mesmo tempo, representa uma menor curva de faturamento. A Figura 3.1 mostra
que o lucro gerado por um produto tem estrita relação com a velocidade de seu lançamento no
mercado.
Figura 3.1: Retorno financeiro de projeto em função do tempo de projeto.
Na figura, observa-se que à medida que o lançamento é adiado em relação ao surgimento
inicial daquele tipo de produto no mercado, o lucro obtido com a venda do produto cai rapidamente. Desta maneira, os novos produtos têm uma vida cada vez mais curta, de modo que o
CAPÍTULO 3. PROJETO BASEADO EM PLATAFORMA
10
retorno financeiro do projeto deve ser obtido também em pouco tempo.
Outro grande problema diz respeitos ao aumento dos custos de engenharia não recorrentes
(NRE, do inglês). Tais custos estão associados com design e a utilização de ferramentas no
desenvolvimento de complexos chips. Estima-se que um conjunto de máscaras de fabricação
está alcançando a ordem de milhões de dólares, o que obriga as empresas a garantirem um alto
volume de produção para amortizar os gastos de fabricação.
Entretanto, a metodologia tradicional de projeto full-custom, onde a equipe de projetistas desenha o chip transistor a transistor, está se tornando inadequada para atender alta produtividade
e o baixo time-to-mark exigidos pela atual dinâmica do mercado. Devido aos problemas apresentados, as empresas de eletrônica procuraram aumentar a produtividade e flexibilidade, e ao
mesmo tempo, diminuir o tempo e os custos de projeto através de metodologias que disciplinem
os seus designers.
Em geral, tais metodologias visam balancear os custos de produção com o custo e o tempo de
desenvolvimento do ponto de vista da performance e da funcionalidade do sistema. Nos últimos
anos, várias abordagens foram propostas para conseguir atingir este equilíbrio, dentre elas, a
metodologia de Projeto Baseado em Plataforma.
Projeto Baseado em Plataforma é um novo paradigma de concepção de sistemas embarcados
em um único chip, que é orientado à integração e ao reuso. O conceito de plataforma não tem
uma definição única, mas de maneira geral, pode ser entendido como uma abstração que cobre
diversos possíveis refinamentos em baixo-nível [1].
No contexto de sistemas integrados, uma plataforma é comumente expressa como um conjunto de componentes previamente projetados e testados. Estes componentes, geralmente chamados de IP cores, determinam a capacidade da plataforma.
A plataforma deve incluir primitivas de comunicação como barramentos, NoCs e crossbar
switches. Tais primitivas de comunicação devem garantir a ortogonalidade da comunicação
versus a funcionalidade dos blocos. Esta característica da comunicação entre os componentes
garante que o re-uso dos componentes seja feito com nenhum ou pouco esforço.
O principal benefício da política de reutilização de componentes de software e de hardware
é a redução do time-to-mark. Outro benefício é a alta flexibilidade que a plataforma oferece,
uma vez que, os componentes são altamente parametrizáveis. A Figura 3.2, retirada do roadmap
ITRS [11], mostra que as metodologias tradicionais de projeto têm custos crescentes que não
conseguem acompanhar a evolução tecnológica prevista pela lei de Moore.
Pode-se observar, na Figura 3.2, que os custos de projeto podem ser sensivelmente reduzidos
pelo re-uso de plataformas e componentes. O gráfico mostra que no período de 1997 a 2001,
CAPÍTULO 3. PROJETO BASEADO EM PLATAFORMA
11
Figura 3.2: Retorno financeiro de projeto em função do tempo de projeto.
os custos dos projetos que utilizam apenas a metodologia full-custom mais que triplicaram, enquanto que os custos dos projetos que utilizam alguma metodologia de projeto aumentaram em
1,5 vezes apenas.
O projeto da um SoC embarcado consiste em escolher uma instância da plataforma que
atenda os requisitos funcionais e não funcionais da aplicação. Uma instância da plataforma é
uma arquitetura derivada da plataforma através da seleção e do ajustes de parâmetros dos componentes que forma a biblioteca de componentes da plataforma.
Um ponto crítico do projeto é o mapeamento da aplicação para a arquitetura alvo. Nesta
etapa do projeto, decide-se que funcionalidades da aplicação serão implementadas em software e
as que serão implementadas em hardware. É evidente que o processo de mapeamento determina
o custo de design e o desempenho do SoC embarcado.
CAPÍTULO 3. PROJETO BASEADO EM PLATAFORMA
3.1
12
A Plataforma STORM
A plataforma STORM (MP-SoC DirecTory-Based PlatfORM) é uma plataforma de desenvolvimento de sistemas embarcados. Por ser uma plataforma, não possui uma arquitetura definida,
mas sim um conjunto de módulos e especificações sobre como devem ser utilizados, sendo possível para o projetista criar instâncias de arquitetura com diversas características.
A STORM é composta pelos seguintes módulos: processador SPARC V8, módulos de caches, módulos de memória, módulo de diretório e dois modelos de redes-em-chip. O processador
SPARC V8 e o sistema de caches foram desenvolvidos no escopo específico deste trabalho. Eles
serão apresentados no Capítulo 4. A Figura 3.3 ilustra os componentes da plataforma e suas
relações.
Figura 3.3: Módulos da STORM
A seguir, temos uma breve explicação sobre a funcionalidade de cada módulo da STORM
que não está no escopo específico deste trabalho.
3.1.1
CaCoMa
O CaCoMa (Cache Communication Manager) é um módulo especialmente desenvolvido para
os propósitos da plataforma. Ele possui como função principal a gerência da comunicação das
CAPÍTULO 3. PROJETO BASEADO EM PLATAFORMA
13
memórias cache (e conseqüentemente, do processador) com seu roteador, e com o resto da plataforma. O CaCoMa está ligado às caches de dados e instruções, e ao roteador da NoC.
As principais funções do CaCoMa são: tradução dos endereços lógicos enviados pelo processador em endereços físicos, envio e recebimento de pedidos de leitura e escrita de blocos para
o diretório e tratamento das requisições vinda do diretório referentes ao protocolo de coerência
de cache. Tais requisições pode ser invalidação de blocos ou envio de blocos modificados pelas
memórias caches associadas ao CaCoMa em questão.
3.1.2
Diretório
Todo ambiente concorrente que utiliza um ou mais níveis de cache associados a cada processador
deve ter um mecanismo para manter a coerência entre todas as cache do sistema. Uma vez que,
esta organização cria um problema chamado de coerência de cache. O problema ocorre porque
podem existir simultaneamente múltiplas cópias do mesmo dado em diferentes caches, e se os
processadores realizarem atualizações em suas cópias livremente, o resultado será imprevisível.
O módulo de Diretório tem a função implementar o protocolo de coerência de cache da
STORM. Cada módulo de memória está conectado um módulo Diretório, que controla seu funcionamento e faz sua conexão com a NoC e, portanto, com o resto da plataforma. O diretório é
um controlador centralizado que mantém informações sobre as localizações e o estado das cópias de blocos de um módulo de memória a ele associado. Antes que qualquer processador da
plataforma possa atualizar a sua cópia local de uma linha da cache, ele deve requisitar o acesso
exclusivo a está linha da cache ao diretório.
3.1.3
Memória
A plataforma STORM faz uso de memória compartilhada, onde diversos blocos de memória
espalhados pela NoC formam um único espaço de endereçamento, visível por todos os processadores. No modelo de memória compartilhada não existe memória local ou remota. Este modelo
de memória é de mais fácil programação do que os modelos de memória distribuída.
Em sistemas multi-processadores interligados por barramento, o modelo de memória compartilhada possui uma escalabilidade limitada devido à necessidade de operações de broadcast
realizadas pelos mecanismos de coerência de cache baseados em protocolos snoop. Entretanto,
a STORM é um sistema multiprocessado interligado por redes-em-chip e o uso de diretório evita
o broadcast na manutenção da carência de cache. Desta maneira, a escalabilidade do sistema não
é comprometida pelo modelo de memória adotado.
CAPÍTULO 3. PROJETO BASEADO EM PLATAFORMA
3.1.4
14
Interconexão
O sistema de interconexão da STORM é realizado através de redes-em-chip (do inglês, networkon-chip). Dois diferentes módulos de NoC estão presentes na STORM: a NoCX4 e a Árvore
Obesa. A NoCX4 consiste em uma malha de roteadores, cada um ligado a um módulo da plataforma (topologia direta). A Figura 3.4 a seguir mostra esta topologia.
Figura 3.4: Topologia NoCX4.
A Árvore Obesa possui topologia indireta, na qual os roteadores são alocados nos níveis da
árvore. O nível mais baixo é composto por Roteadores Folha (Leaf Routers) e os demais níveis são compostos por Roteadores Intermediários (Intermediary Routers). Os Roteadores Folha
são conectados aos elementos de processamento enquanto que os Roteadores Intermediários são
conectados a outros roteadores. A topologia Árvore Obesa é mostrada na Figura 3.5.
Figura 3.5: Topologia Árvore Obesa.
CAPÍTULO 3. PROJETO BASEADO EM PLATAFORMA
15
Uma característica importante desta topologia é o fato de que todos os roteadores filhos de
um mesmo pai são completamente interconectados. Isto evita a criação de gargalo entre os
roteadores filhos e o roteador pai, uma vez que, todo o tráfego entre nós de nível mais baixo fica
restrito aos roteadores filhos. Por utilizar o número mínimo de roteadores, esta topologia tem
baixa latência de comunicação.
Capítulo 4
SPARC V8
O SPARC (Scalable Processor ARChitecture - Arquitetura de Processadores Escaláveis) é uma
arquitetura de microprocessador RISC de propósito geral desenvolvida pela Sun Microsystems
no período de 1984 a 1987. O objetivo do SPARC é facilitar o desenvolvimento de pipeline,
obter alta performance, baixo custo e implementação multi-tecnológica.
O SPARC formulado pela Sun foi baseado nas máquinas RISC I, RISC II e SOAR desenvolvidas na Universidade da Califórnia em Berkeley ( UC Berkeley). As máquinas RISC I e RISC II
foram simples projetos que continham apenas dois e três estágios de pipeline, respectivamente.
Entretanto, introduziram conceitos importantes como janela de registradores e execução de desvios atrasados. Já o SOAR foi uma reimplementação da máquina RISC para rodar o SMALLTALK. O SOAR extende a máquina RISC I, adaptando o conjunto de instruções as necessidades
do SMALLTALK e adicionado instruções necessárias para o suporte da programação orientada
a objetos como tratamento de interrupções dentre outras.
O SPARC herdou do RISC I e II a organização dos registradores em janela e a execução de
desvios atrasados, e do SOAR, herdou as instruções para suporte à linguagem orientada a objetos. A principal diferença entre o projeto SPARC e os projetos RISCs realizados em Berkely
é que o SPARC permite alta flexibilidade para o compilador na alocação de registradores para
as variáveis de programa. Esta flexibilidade advém do fato de que o gerenciamento da janela
de registradores não é amarrado a instruções de chamada e retorno de função, como ocorre nas
máquinas RISCs da Berkeley. Além disso, o SPARC inclui instruções adicionais para ambiente multiprocessados, utilização de co-processador e unidades de ponto flutuante que não eram
previstas nos projetos RISC I, RISC II e SOAR.
O SPARC tem alta flexibilidade e desempenho podendo ser utilizado em diversas áreas como
na computação militar, fotografia digital, computação aeroespacial, processamento de imagens,
CAPÍTULO 4. SPARC V8
17
computação empresarial, notebooks e desktops, telecomunicações, redes, eletro-eletrônicos etc.
Em 1989, a Sun Microsystem transferiu a posse das especificações de SPARC a uma organização independente, a SPARC internacional, que administra, licencia a tecnologia e realiza testes
de conformidade e outros serviços para seus membros. Esta iniciativa da Sun visava estimular as
empresas a criarem a sua própria arquitetura SPARC.
Neste capítulo, será apresentada uma implementação da arquitetura SPARC V8 para a plataforma STORM. Será descrito: o conjunto de instruções e registradores, o modelo de memória, os
modos de operação e endereçamento do processador, tratamento de interrupções e as decisões de
projeto adotadas nesta implementação em particular e outros detalhes relevantes ao projeto. Por
fim, será apresentado o modelo de sistema de cache desenvolvido para o SPARC. Este sistema de
cache foi desenvolvido para apresentar a maior flexibilidade possível. Tendo vários algoritmos
de substituição e modos de mapeamento.
4.1
A Arquitetura SPARC V8
A arquitetura de um processador pode ser definida por meio de seu conjunto de instruções e pela
organização do seu conjunto de registradores. Assim, não há uma implementação de hardware
específica, vários projetos de hardware podem implementar a mesma arquitetura.
A arquitetura SPARC define o conjunto de instruções, a estrutura dos registradores e os tipos
de dados para um unidade inteira e para uma unidade de ponto-flutuante de acordo com o padrão
IEEE 754 [19]. Características como utilização ou não de barramento, gerência de memória, uso
ou não de cache interna, número de estágios do pipeline, tipo de lógica de controle e tecnologia
de implementação não são definidas e ficam dependente da implementação.
Entretanto, vale a pena ressaltar que a compatibilidade binária é mantida pela definição da
arquitetura. Isto permite a execução de um mesmo código em sistemas de portes bem variados e
independente da tecnologia utilizada no desenvolvimento.
A arquitetura do SPARC V8 é um exemplo de RISC (Reduced Instruction-Set Computer) de
32 bits. O SPARC é organizado logicamente em três unidades distintas: a IU (integer unit), a
FPU (floating-point unit) e o co-processador (CP), cada uma com os seus próprios registradores,
permitindo máxima concorrência na execução de instruções das três unidades. A Figura 4.1
mostra essas três unidades e a D-Cache, cache para dados, a I-Cache, cache para instruções, e
ainda uma RAM local.
O SPARC utiliza o modelo de execução registrador-para-registrador, ou seja, todos os acessos à memória são feitos via registradores e todas as instruções envolvem registradores. Ou
CAPÍTULO 4. SPARC V8
18
Figura 4.1: Visão geral da Arquitetura SPARC V8.
seja, neste modelo de execução nenhuma unidade envia ou recebe informações para memória
diretamente via algum barramento ou rede de conexão externa.
A IU controla toda as operações do processador. Ela executa instruções lógicas e aritméticas
com números inteiros, instruções de acesso à memória, atualiza o contador de programa (PC)
e ainda controla a execução da FPU e do co-processador. Para auxiliar na execução de todas
essas tarefas, a IU conta com um total de 40-520 registradores, dependendo da implementação.
A Figura 4.2 mostra a IU.
Figura 4.2: Visão geral do SPARC.
CAPÍTULO 4. SPARC V8
19
Embora o pipeline de instruções de cinco estágios não seja uma característica obrigatória em
um implementação de um processador SPARC V8, a maioria delas apresenta-o em cinco estágios: Busca (B), Decodificação (D), Execução (E), Memória (M) e Escrita (W). Durante a Busca,
instruções são movidas da memória para o processador. No estágio de Decodificação, o processador lê operandos do conjunto de registradores, decodifica instruções e detecta dependências
entre instruções.
Os operandos entram na ULA (unidade lógica e aritmética) ou na unidade de deslocamento
(shift) no estágio de Execução. Instruções de load e store buscam operandos na memória no
estágio de Memória. No estágio de escrita, o processador escreve o resultado da ULA ou o
dado da memória no conjunto de registradores. Assim que uma instrução entra no pipeline, ela
é executada em 5 ciclos. Se o pipeline estiver cheio, uma nova instrução é terminada em cada
ciclo do clock.
A FPU tem 32 registradores de 32 bits. Valores que necessitam de maior precisão podem ocupar mais de um registrador. Os formatos e dados de ponto flutuante estão de acordo com o padrão
ANSI/IEEE 754-1985 [19]. Entretanto, o SPARC não requer que todos os aspectos desse padrão
sejam implementados em hardware, podendo ser emuladas por software as funcionalidades não
presentes no hardware.
Nos casos em que a FPU não esteja presente na implementação ou não esteja habilitada, o bit
enable floating (EF) no registrador de estado do processador (Processor Status Register - PSR) é
zero. Qualquer tentativa de executar uma instrução de ponto flutuante irá gerar uma interrupção
de ponto flutuante - fp_disabled. Nos outros cacos, o software deve emular uma instrução de
interrupção de ponto flutuante.
A arquitetura SPARC V8 suporta um único co-processador. Ele tem o seu próprio conjunto
de registradores, geralmente são registradores de 32 bits. Para mover dados dos registradores
entre o co-processador (CP) e a memória, há instruções de load/store.
Se o co-processador não está presente na implementação ou não está habilitado, o bit enable_coprocessor (EC) no PSR é zero, a interrupção cp_disabled deve ser gerada caso haja uma
tentativa de executar instruções que envolva o co-processador. Os registradores da FPU e do
co-processador são acessados, unicamente, através das instruções de load e store. Não existe
nenhum caminho direto entre a IU e a FPU ou entre a IU e o CP, que permita este acesso.
4.1.1
Formato de Instruções
As instruções do processador SPARC V8 são codificadas em três formatos de 32 bits. Os operandos aparecem em posições fixas para permitir acesso rápido aos registradores. Na Figura 4.3,
CAPÍTULO 4. SPARC V8
20
pode-se ver que o formato 1 é usado somente pela instrução Call. Este formato permite um deslocamento de 30 bits em relação ao PC, gerando um deslocamento arbitrário em apenas uma instrução. O formato 2 é usado para as instruções Sethi e Branches (Bicc - desvio condicional, FBfcc
- desvio sob condição de ponto flutuante e CBccc - Desvio sob condição do co-processador). A
instrução Sethi é um instrução especial usada principalmente para armazenamento de um valor
de 32 bits em registrador. Já o formato 3 suporta as outras instruções. O formato 3 com op = 3
dá suporte às instruções de memória, e com op = 2, às instruções aritméticas, lógicas, shift e as
restantes.
Figura 4.3: Formatos de instruções
4.1.2
Conjunto de Instruções
O conjunto de instruções do SPARC pode ser dividido em seis categorias: instruções de load/store,
instruções lógicas, aritméticas e shift, instruções de transferência de controle, instruções de
controle de leitura e escrita em registradores, operações de ponto flutuante e operações de coprocessador. A Tabela 4.1 mostra essas categorias.
A maioria das instruções do SPARC usa apenas operandos em registradores. Tais Instruções
podem ser expressas da seguinte forma:
Rd ← Rs1 op S2
Onde Rd e Rs1 são referências a registradores; S2 pode referenciar um registrador ou ope-
CAPÍTULO 4. SPARC V8
Categoria
Instruções Load/Store
Instruções
Aritméticas/Lógicas/
Shift
Instruções de
transferência de controle
Instruções de controle de
leitura e escrita
em registradores
Instruções de ponto flutuante
Instruções de co-processador
21
Descrição
Únicas instruções a acessarem a
memória.
Com exceção da instrução Sethi,
essas instruções computam um
resultado que é uma função de
dois operandos.
Incluem branches, chamadas a
funções (Call), saltos e
interrupções condicionais.
Usadas para a leitura e escrita
do conteúdo de registradores
visíveis ao software.
Realizam cálculos ponto flutuante
Se o CP está presente, essas
instruções são definidas por sua
implementação.
Tabela 4.1: conjunto de instruções do SPARC.
rando imediato de 13 bits. Essa forma é bastante adequada para programas que têm alta proporção de constantes e variáveis locais escalares.
4.1.3
Conjunto de Registradores
O processador SPARC tem dois tipos de registradores: registradores de propósito-geral e registradores de controle e status. A IU contém 32 registradores de propósito geral sempre visíveis ao
programa . Desses, 8 são globais e os outros 24 organizados na forma de janela de registradores.
Uma implementação do processador SPARC pode ter de 2 a 32 dessas janelas, variando de 40 a
520 o número de registradores.
Uma janela de registradores consiste em três grupos de três registradores, chamados in, out
e local. Os registradores do tipo in e out são usados para passagem de parâmetros de funções e
receber resultados delas. Os registradores do tipo local são utilizados para variáveis automáticas.
A cada momento, somente uma janela está visível, determinado pelo CWP (current window
point) que é parte do PSR (processor status register). O CWP é um valor de 5 bits que pode ser
decrementado pela instrução SAVE e incrementado pela instrução RESTORE. Essas instruções
são para salvar e recuperar o estado do processador, respectivamente, sendo geralmente executas
em chamadas a funções e retorno dessas. Assim, o grupo de registradores in contém os parâmetros de entrada, o grupo local, os registradores usados dentro da função e o grupo out, os
CAPÍTULO 4. SPARC V8
22
resultados de saída.
As janelas de registradores se sobrepõem parcialmente. Dada uma janela de registradores
atual, se uma instrução RESTORE for executada, CWP será incrementado e o grupo de registradores in da janela atual será o grupo out da próxima janela. Caso contrário, se a instrução SAVE
for executada, CWP será decrementado e o grupo de registradores out da janela atual passa a ser
o grupo in dessa próxima janela. Para ilustrar esse procedimento, considere a Figura 4.4.
Figura 4.4: Janela de Registradores.
Múltiplas janelas provêem maior agilidade nas chamadas de funções e trocas de contexto,
uma vez que, elas evitam a necessidade de salvar o estado atual do processador na memória durante estas operações. Isto reduz o trafego off-chip1 e é particularmente eficiente em linguagens
orientadas a objetos como C++ e Java, pois a programação orientadas a objetos, freqüentemente,
resulta em programas com um grande número de pequenas chamadas a funções.
As variáveis de estado são salvas na janela atual, e uma nova janela é aberta para uma nova
função. Note que a passagem de parâmetros é feita sem movimentação física de dados.
1
O Tráfego off-chip é o tráfego entre o processador e qualquer unidade externa
CAPÍTULO 4. SPARC V8
23
Há também os registradores para controle e status da IU que incluem PSR (Processor State
Register), WIN (Window Invalid Mask), TBR (Trap Base Register), PC e nPC (Program Counters).
O registrador PSR contém vários campos para o controle do processador e para armazenar
informações sobre o seu status. Já o WIN é controlado pelo software supervisor e usado pelo
hardware para determinar se houve uma interrupção de overflow ou de underflow causada por
uma instrução Save, Restore ou Rett. O registrador TBR armazena um endereço para o qual
o controle é transferido em caso de ocorrência de interrupção. O PC contém o endereço da
instrução que está sendo executada no momento e o nPC, o endereço da próximo instrução a ser
executada.
A organização em janelas de registradores possui várias vantagens em relação ao conjunto
fixo de registradores. A principal vantagem é a redução do número de instruções load/store
necessárias para a execução do programa. Isto implica em uma redução na taxa de falta da cache
de dados.
Para programas longos em C, estima-se que 20% das instruções sejam instruções de load/store,
incluindo o overhead de processamento dos overflow/underflow das janelas. Em arquiteturas
RISCs sem janelas de registradores, este número sobe para algo entre 30% a 40% das instruções
[8].
4.1.4
Formatos de Dados
A arquitetura SPARC reconhece três tipos fundamentais de dados
• Inteiro com sinal - 8, 16, 32 e 64 bits.
• Inteiro sem sinal - 8, 16, 32 e 64 bits.
• Ponto flutuante - 32, 64 e 128 bits.
O tamanho dos formatos são:
• Byte - 8 bits.
• Halfword - 16 bits.
• Word - 32 bits.
• Tagged Word - 32 bits.
CAPÍTULO 4. SPARC V8
24
• Doubleword - 64 bits.
• Quadword - 128 bits.
Os formatos de inteiro com sinal codificam apenas números inteiros em complemento de
dois. Os formatos de inteiro sem sinal são formatos de propósito geral e não codificam nenhum
tipo de dado em particular. Eles podem ser usados para representar string, valores booleanos,
números inteiros, frações e etc. Os formatos com tag definem palavras nas quais os dois bits
menos significativos são utilizados como tag. Finalmente, os formatos de ponto flutuante são
definidos de acordo com o padrão ANSI/IEEE 754-1985 [19].
4.1.5
Modo Usuário e Modo Supervisor
A arquitetura SPARC suporta dois modos de operações: o modo supervisor, que é o modo de
operação do sistema operacional e tem acesso a todo conjunto de instruções; e o modo usuário,
que é o modo de funcionamento das aplicações do usuário. Qualquer tentativa de executar uma
operação de modo supervisor em uma aplicação de modo usuário causa uma interrupção. Os
modos de operação delimitam não apenas um conjunto de instruções diferenciados, mas também
espaços de endereçamento de memória diferenciados.
A existência deste dois modos de operação é fundamental para a colocação de um sistema
operacional na STORM.
4.1.6
Modelo de Memória
O modelo de memória do SPARC define a semântica das operações tais como load e store, e
especifica como a ordem em que estas operações são emitidas por um processador é relacionada
com ordem em que são executados pela memória. Especifica também como as instrução buscadas
pelo SPARC são sincronizados com as operações de memória.
O modelo de memória padrão do SPARC é conhecido como Total Store Order (TSO). Este
modelo pode aplicado tanto em ambientes uniprocessados como em ambientes multiprocessados
com memória global compartilhada, como é o caso da STORM.
O modelo garante que as operações de store, FLUSH e atomic load-store de todos os processadores são executadas pela memória de modo serial e na mesma ordem em que foram emitidas
pelo processador.
Para o SPARC, a memória é uma coleção de endereços acessados via instruções load/store.
Esta coleção de endereços inclui a memória tradicional, os registradores de entrada e saída e
CAPÍTULO 4. SPARC V8
25
registradores especiais do SPARC. Dentro desta coleção, define-se uma região especial chamada
de memória principal ou real que contém a área de instruções e dados do usuário e do sistema
operacional. Esta área é livre de efeitos colaterais; isto é, um load, store ou atomic load-store em
um endereço dentro desta área não tem nenhum efeito visível exceto nesta posição.
O SPARC utiliza entrada e saída mapeadas na memória. Neste esquema, cada registrador de
controle de dispositivos de E/S é associado de maneira unívoca a um endereço de memória. O
modelo de memória do SPARC define que os registradores de E/S não estão na memória real.
O acesso a estes registradores pode ser feito através de instruções load/store, instruções de coprocessador e instruções de leitura e escrita nos ASR (Ancillary State Register). Os ASRs são
registradors de controle e de status da IU.
4.1.7
Modos de Endereçamento
Os modos de endereçamento do SPARC são: endereçamento de registrador e modo de deslocamento. No primeiro modo, o campo de endereço refere-se a um registrador. Enquanto que no
segundo modo de endereçamento, o campo de endereço consiste em um deslocamento relativo a
um endereço contido em um registrador [18]:
EA = (Rs1 ) + S2
ou EA = (Rs1 ) + (Rs2 )
Dependendo se o segundo operando é um valor imediato ou uma referência a registrador. Onde
Rs1 e Rs2 são referências a registradores, e S2 é um operando imediato de 13 bits. O modo de
endereçamento via deslocamento é muito flexível e pode emular outros modo de endereçamento
como mostra tabela a seguir:
Modo
Algoritmo
Equivalente SPARC
Imediato
operando = A
S2
Direto
EA = A
R 0 + S2
Registrador
EA = R
Rs1 ,Rs2
Indireto
EA = (R)
Rs1 + 0
Deslocamento EA = (R) + A
Rs1 + S2
Tabela 4.2: Equivalente SPARC de outros modos de endereçamento.
Onde A é conteúdo do campo de endereço da instrução, R é o conteúdo de campo de endereço
que referencia um registrador. EA é endereço real e (R) indica o conteúdo da posição dada por
R.
CAPÍTULO 4. SPARC V8
4.1.8
26
Tratamento de Interrupções
O fluxo de execução do SPARC é baseado no modelo seqüencial, mas uma implementação da
arquitetura SPARC com pipeline de instruções pode modificar o estado do processo em uma
ordem diferente da definida pelo modelo seqüencial. Em decorrência disto, a ocorrência de uma
interrupção pode deixar o hardware em um estado que não é consistente com nenhum valor
especificado pelo contador de programa [15].
Quando uma interrupção ocorre, o estado do processo é salvo pelo hardware ou pelo software.
Neste trabalho, o contexto é salvo pelo hardware. As interrupções podem ser precisas, imprecisas
ou externas. Uma interrupção é dita precisa se obedece às seguintes propriedades:
• Todas as instruções anteriores à instrução apontada pelo contador de programa foram completamente executadas e modificaram o estado do processo corretamente.
• Todas as instruções após a instrução apontada pelo contador de programa não foram executadas e não modificaram o estado do processo.
• Se uma interrupção é causada por uma exceção em uma instrução do programa, o contador
de programa salvo aponta para a instrução interrompida. E esta instrução deve ter sido
completada ou não iniciada.
Se o estado do processo salvo é inconsistente com o modelo seqüencial da arquitetura e não obedece a alguma das condições acima, então a interrupção é dita imprecisa. Por fim, as interrupções
externas são exceções que não tem relacionamento com a execução de nenhum instruções anterior, como interrupções de I/O ou time.
A arquitetura SPARC determina que todas as interrupções devem ser precisas com 4 exceções: exceções de Ponto-Flutuante e de co-processador, exceções ocorridas devido a erro de
hardware, exceções devido a interrupções externas e exceções causadas após o primeiro acesso
de uma instrução de acesso múltiplo a memória, como load/store double, atomic load store ou
SWAP.
As interrupções são controladas principalmente por dois registradores: o PSR e o FSR (FPU
Status Register). O campo ET (Enable Trap) PSR habilita as interrupções da IU e o campo
TEM (FSR Trap Enable Mask) do FSR habilita as interrupções da FPU. As prioridades das
interrupções são estabelecidas pelo campo PIL (Processor Interrupt Level) no PSR.
O SPARC utiliza uma esquema de transferência de controle para o sistema operacional baseado em uma tabela. Esta tabela, denominada de tabela de interrupções, contém as quatro
primeiras instruções das rotinas de tratamento das interrupções. O endereço de início da tabela
CAPÍTULO 4. SPARC V8
27
é armazenado no TBR ( Table Base Register). O TBR contém um campo denominado tt (Trap
Type) que identifica unicamente cada interrupção. Este campo é usado para indexar a tabela de
interrupções no processo de transferência de controle.
Quando ocorre uma interrupção de qualquer natureza e as mesmas estão habilitas, as seguinte
ações ocorrem: As interrupções são desabilitadas, ou seja, ET ← 0; O modo de operação
do processador é salvo; o processador entra no modo supervisor; uma nova janela é aberta; o
contexto do processador é salvo; o campo tt é gravado pelo hardware no TBR e o controle é
transferido para a o endereço que tabela de interrupções aponta.
Caso as interrupções estejam desabilitadas e uma interrupção precisa ocorre, o processador
suspende a execução da instrução corrente. O tratamento de interrupções imprecisas é dependente da implementação. O presente trabalho prevê o tratamento de interrupções precisas e
externas. O tratamento de interrupções imprecisas não foi abordado, pois ainda não existem
módulos executando paralelamente a unidade inteira. Desta maneira, a existência de interrupções imprecisas só ocorreriam devido a erros de hardware, entretanto estes problemas não são
simulados.
4.1.9
Instruções de LDSTUB e SWAP
Em ambientes mono-processados multi-tarefas ou de processamento paralelo há a necessidade
de evitar a ocorrência de condições de corrida (race condition)2 e gerenciar o sincronismo entre
processos.
A habilidade fundamental para realizar a sincronização em ambientes multiprocessados é a
capacidade de ler e escrever de forma atômica em uma posição de memória. Sem tal recurso, o
custo de construir primitivas de sincronização aumentaria com o aumento do número de processadores [10].
A STORM necessita de um mecanismo de Test-and-Set para evitar as condições de corrida
e realizar o sincronismo entre processos. O mecanismo de Test-and-Set é implementado no
SPARC usando-se as instruções LDSTUB (Atomic Load-Store) e SWAP. A primeira realiza uma
leitura e em seguida uma escrita de forma átomica, enquanto que a segunda troca o conteúdo
de registrador e de uma posição de memória de forma atômica. Quando um processo deseja
entrar em uma determinada região crítica, ele executa a instrução LDSTUB. Tal instrução lê uma
posição da memória e, em caso esta seja ’0’, modifica seu valor para ’-1’. Caso contrário não
faz nada. Quando o processo desejar deixar a região crítica, ele executa a instrução SWAP que
2
Condições de corrida são situações em que dois ou mais processos estão acessando dados compartilhados e o
resultado depende da ordem de execução dos mesmos.
CAPÍTULO 4. SPARC V8
28
escrever novamente ’0’ na posição de memória para indicar que a região está livre. Note que
esta solução deixa a cargo do programador a definição das regiões críticas da aplicação através
do uso de monitores ou semáforos.
4.1.10
Sincronismo das Instruções
A arquitetura SPARC é aberta e não define o caminho de dados do pipeline que implementa o
conjunto de instruções. Isto implica em decisões de projeto que são visíveis ao nível de software.
O principal efeito da implementação do pipeline é o número de ciclos necessário para execução
das instruções. A Tabela 4.3 mostra estes valores para esta implementação.
Instrução
Número de Ciclos
Load single, taken ticc, JMPL, RETT
2
Load double, store single, untaken Ticc
3
Store double, LDSTUB, SWAP
4
Todas as outras instruções
1
Tabela 4.3: Número de ciclos gasto para execução de instruções.
Na primeira linha da Tabela 4.3 temos o tempo em número de ciclos para realizar carga de
uma palavra na memória, tomada de saltos condicionais sob condições inteiras e para saltos e
retorno de funções. Na segunda linha temos o número de ciclos gastos para realizar carga dupla,
armazenar uma palavra e executar um salto condicional não tomado. Na penúltima linha, temos
o tempo para armazenar uma palavra dupla e realizar as instruções de test-and-set. Todas as
outras instruções da IU gastam 1 ciclo para executar.
4.1.11
Mecanismos de bypassing
Bolhas no pipeline também podem ser causadas devido à ocorrência de uma instrução que necessite de dados que estão prontos mas ainda não estão disponíveis nos registradores. Por exemplo,
considere um pipeline de cinco estágios e a seguinte sequência de instruções:
ADD %g1, %g2, %g3
SU B %g4, %g1, %g5
Na situação acima, imagine que a primeira instrução tem sua execução iniciada no instante
t0 e que a segunda instrução inicie no tempo t1 . Note que, a segunda instrução necessita do
CAPÍTULO 4. SPARC V8
29
resultado da primeira instrução na sua fase de decodificação no instante t2 . Entretanto a primeira
instrução grava o resultado no seu estágio de escrita no instante t4 . A situação apresentada
provoca uma bolha no pipeline.
Para evitar a ocorrência deste tipo de bolha a arquitetura proposta conta com um mecanismo
de bypassing entre os estágios de decodificação, execução e memória. Este mecanismo funciona
da seguinte maneira:
1. O resultado das unidades de decodificação, execução e memória são encaminhados à entrada da unidade anterior no pipeline e realimenta a própria unidade.
2. Se o hardware de bypassing detectar que a instrução executada anteriormente na unidade
alterou algum registrador de origem da instrução atual, a lógica de controle seleciona o
resultado encaminhado como entrada da unidade e não o valor lido dos registradores.
A Figura 4.5 ilustra o mecanismo de bypassing.
Figura 4.5: Mecanismo de bypassing.
4.1.12
Previsão de Desvios
Para evitar bolhas no pipeline devido à hazards de desvios, uma instrução é buscada a cada
ciclo de clock para manter o pipeline cheio. No caso de instruções de desvios, considera-se que
o desvio não foi tomado, assim a execução continua seqüencial. Se o desvio for tomado, as
instruções que estão no pipeline são descartadas automaticamente.
CAPÍTULO 4. SPARC V8
30
Nas arquiteturas SPARC, os desvios representam cerca de 20% das instruções executadas
[14]. Logo diminuir a penalidade no caso de uma previsão errada significa um melhor desempenho da arquitetura. Uma técnica para conseguir esta redução é mover a avaliação e execução
do desvio para o estágio de decodificação. Isto permite que o atraso na execução de desvios
tomados seja de apenas um ciclo.
4.1.13
Unidade de Controle Distribuída
A unidade de controle da arquitetura é distribuída pelos estágios. Desta maneira, cada estágio do
pipeline coordena a suas atividades e se comunica via sinais com os outros estágios. Os controles
embutidos nos estágios de busca e decodificação realizam o gerenciamento e o despacho de
instruções para o estágio de execução.
Entretanto, a parte principal do controle está na máquina de estados finitos localizada no
estágio de execução. Esta máquina de estados controla todas as ações necessárias para a execução das instruções, produz os sinais de controle para os outros estágios e determina o modo de
operação do processador.
4.2
O Sistema de Caches
A cache é o nome dado ao primeiro nível de hierarquia de memória encontrado assim que o
endereço deixa o processador [10]. A memória cache é uma pequena memória estática de alto
desempenho, cujo finalidade é aumentar o desempenho do processador realizando uma busca
antecipada na memória RAM com base nos princípios da localidade temporal e espacial. O uso
de memória cache é feito desde que o acesso à memória principal tornou-se muito custoso por
causa da diferença entre os períodos de relógio do processador e da memória [21].
O princípio da localidade temporal nos diz que o dado usado mais recentemente tem grande
probabilidade de ser acessado novamente num futuro próximo. Já o princípio da localidade
espacial nos diz que os dados adjacentes ao dado requisitado tem alta probabilidade de serem
utilizados no futuro.
O SPARC possui uma arquitetura de cache Harvard [17] com barramento de endereços e
dados separados, conectados a dois controladores de cache separados. Esta divisão na cache é
comum à maioria das arquiteturas pipeline atuais pois possibilita acessos simultâneos a instruções e dados.
A Cache de Instruções é dedicada a armazenar as instruções executadas pelo processador
mais recentemente. A Cache de Instruções é acessada exclusivamente pelo módulo de Busca do
CAPÍTULO 4. SPARC V8
31
processador. Tal cache não tem permissão de escrita nos dados armazenados por ela.
A Cache de Dados é destinada ao armazenamento dos dados mais recentemente acessados
pelo SPARC. A cache de dados possui suporte ao mecanismo de coerência de cache da plataforma STORM [16]. Este mecanismo exige que a mesma tenha para cada linha da cache, um
bit de permissão de escrita, que indicam se uma operação de escrita pode ser feita sobre uma
dada linha. Além disso, a cache deve ser capaz de atender as requisições de invalidação e enviar
blocos editados para o diterório associado a ela.
As caches possuem endereçamento real de 32 bits. Para endereçamento extra, o processador
provê um identificador de espaço de endereçamento de 8 bits (do inglês, ASI - Address Space
Identifier), produzindo até 256 diferentes espaços de endereçamento de 32-bits.
Durante o modo normal de operação o processador trabalhar acessando instruções e dados
utilizando um ASI de 0x08 a 0xB como definido no padrão SPARC. Utilizando instruções LDA
(Load Word from Alternate space) e STA (Store Word into Alternate space), os espaços de endereçamento extras podem ser utilizados. Na Tabela 4.4 temos a divisão do espaço de endereçamento do SPARC.
ASI
Espaço de Endereçamento
0x00 - 0x07 Dependente da implementação
0x08
Instruções do modo usuário
0x09
Instruções do modo supervisor
0x0A
Dados do modo usuário
0x0B
Dados do supervisor
0x0C - 0xFF Dependente da implementação
Tabela 4.4: Identificadores de espaço de endereçamento.
Os espaços de endereçamento acessados via as instruções LDA e STA podem ser usado pelo
software supervisor para acessar registradores especiais, como MMU, controladores de caches,
registradores de espaço de endereçamento dentre outros.
A cache proposta neste trabalho foi projetada para ser altamente parametrizável permitindo
escolher o modo de mapeamento, configurar o tamanho do bloco, o tamanho da linha e o tamanho
da cache. O único parâmetro fixo é a política de atualização da cache que segue o padrão definido
durante a concepção do projeto STORM. A seguir, apresentamos uma breve explicação sobre
cada parâmetro da cache.
CAPÍTULO 4. SPARC V8
4.2.1
32
Mapeamento
Dado que o número de linhas da cache é menor do que o número de linhas da memória é necessário um algoritmo para mapear as linhas da memória em blocos da cache. Esta função de
mapeamento determina como a memória cache é organizada. Existem três técnicas básicas para
fazer este mapeamento: O mapeamento direto, mapeamento completamente associativo e o mapeamento associativo por conjunto. A seguir temos uma breve descrição de cada técnica citada.
• Mapeamento Direto: Neste tipo de mapeamento um linha da memória principal é mapeado em uma único bloco da cache. Pode-se expressar este mapeamento através da seguinte
expressão:
i = j modulo m
Onde i é o número da linha da cache, j é o número da linha da memória e m é o tamanho
da cache. É um esquema simples e de baixo custo de implementação. Entretanto, se
um programa fizer referência a duas linhas distintas da memória principal mapeadas na
mesma linha da cache, haverá uma menor taxa de acerto na cache, uma vez que, elas serão
constantemente substituídas.
• Mapeamento Completamente Associativo: O mapeamento completamente associativo
permite que uma linha da memória seja mapeada em qualquer posição da cache. Isto implica em maior flexibilidade. Porém, este tipo de mapeamento necessita varrer toda as
linhas da cache, o que pode degradar o desempenho da mesma. Em algumas implementações, adiciona-se um complexo hardware para realizar todas as comparações em paralelo.
Entretanto isto aumenta o custo e a complexidade da cache.
• Mapeamento Associativo por Conjunto: Neste tipo de mapeamento, a memória é dividida em v conjuntos cada um com k linhas. Desta maneira, uma linha da memória é
mapeada em um conjunto e depois inserida na cache em qualquer linha deste conjunto.
Este mapeamento pode ser expresso pelas funções:
m = vxk
i = j mod v
Uma das diretrizes do projeto baseado em plataforma é utilizar componentes altamente parametrizáveis. Devido a este fato, a cache proposta implementa o mapeamento associativo por
conjunto. Este tipo de mapeamento permite emular os outros dois tipos de mapeamento. Note
CAPÍTULO 4. SPARC V8
33
que se o número de linhas de cada conjunto for igual a um e o número de conjunto for igual ao
número de linhas da cache, temos o mapeamento direto. E se o número de conjuntos for igual
a um e o número de linhas de desse conjunto for igual ao número de linhas da cache, temos um
mapeamento completamente associativo.
4.2.2
Política de Substituição
Quando a cache enche e ocorre uma falha, o controlador da cache deve escolher um bloco para
ser substituído pelo bloco desejado. Caso a cache seja diretamente mapeada não é necessário
nenhum algoritmo específico para determinar qual bloco substituir pois o próprio mapeamento
determina o bloco a ser retirado. Por outro lado, em caches completamente associativas ou
associativas por conjunto, há vários blocos que são candidatos a sair da cache. É evidente que se
deseja uma política que maximize a taxa de acerto da cache (hit rate).
O sistema de cache proposto neste trabalho possui vários algoritmos de substituição que
foram desenvolvidos juntamente com a aluna Tássia Aparecida Vieira de Freitas, aluna deste
mesmo departamento. A seguir temos uma breve descrição sobre cada algoritmo implementado.
4.2.2.1
LFU (Least Frequently Used):
Esta política utiliza o histórico de acesso para prever a probabilidade de uma referência subseqüente. Desta maneira, o algoritmo LRU substitui a linha menos freqüentemente utilizada.
Para isto, o LFU mantém um contador de acesso para cada linha da cache.
Infelizmente, linhas muito freqüentemente utilizadas em um passado próximo e que não serão utilizadas novamente tendem a permanecerem na cache, impedindo que blocos mais novos
tenham freqüências suficientes para permanecerem na cache. Este fenômeno é conhecido como
poluição da cache. Tal fenômeno provoca um aumento da taxa de falta da cache devido ao
número de dados inicializados.
4.2.2.2
LRU (Least Recently Used):
Esta política explora o princípio da localidade temporal e substitui a linha menos recentemente
utilizada na suposição que esta linha não será utilizada em um futuro próximo, ou seja, a política
LRU utiliza apenas o intervalo de tempo desde o último acesso as linhas da cache e não considera
a freqüência de acesso a tais linhas ao fazer a decisão de realocação.
Esta política é eficiente, porém cara para cache grandes, devido a necessidade de mater o
histórico de acesso das linhas da cache. Além disso, para caches grandes, avaliar todos os blocos
CAPÍTULO 4. SPARC V8
34
para escolher aquele que deve ser retirado da cache, pode consumir muito tempo, o que aumenta
o tempo de resposta da cache.
Devido ao alto desempenho deste algoritmo, ele é largamente utilizado em gerenciamento de
buffers de banco de dados, sistemas de arquivos, gerenciamento de memória virtual, proxy de
internet dentre outras aplicações.
4.2.2.3
Pseudo-LRU:
O algoritmo LRU tradicional é de fácil implementação para caches pequenas mas torna-se computacionalmente caro para caches grandes. O algoritmo Pseudo-LRU é uma aproximação do
algoritmo LRU de implementação computacionalmente mais barata.
O algoritmo Pseudo-LRU funciona da seguinte maneira: Constrói-se uma árvore binária de
decisão para cada conjunto da cache. Nas folhas de tal árvore estão as linhas e nos nós intermediários os pontos de decisão. Nos nós não-folha, o valor 1 indica que o filho esquerdo
foi referenciado mais recentemente do que o direito. E o valor 0 indica que o filho direito foi
referenciado mais recentemente do que o esquerdo.
Durante o processo de substituição percorre-se a árvore procurando o elemento menos recentemente utilizado. Para atualizar a árvore durante um acerto em linha da cache, basta percorrer
o caminho que leva a linha em questão, e durante a travessia, alterar a flag de cada nó não folha para indicar a direção oposta a atual. A Figura 4.6 ilustra está abordagem para uma cache
conjunto-associativo com fator de associatividade 4.
Figura 4.6: Árvore de decisão do pseudo-LRU.
CAPÍTULO 4. SPARC V8
35
Note que são necessários apenas n-1 bits para uma cache de associatividade n. Quando uma
falta ocorre, os bits de estado permanecem inalterados e a decisão sobre qual linha deve ser
retirada da cache ocorre com na base no estado atual da árvore. A Tabela 4.2.2.3 mostra os
possíveis estados para a árvore da Figura 4.6 e a linha a ser substituída em cada caso.
Estado Atual Substituir
00x
linha 0
01x
linha 1
1x0
linha 2
1x1
linha 3
Tabela 4.5: Representação da árvore binária em forma de string de bits.
Na tabela acima, o símbolo “x” representa o valor “don’t care”. Tabela 4.2.2.3 mostra como
ocorre o processo de atualização dos bits de estado quando ocorre um acerto na cache.
Estado Atual Próximo Estado
linha 0
11_
linha 1
10_
linha 2
0_1
linha 3
0_0
Tabela 4.6: Atualização dos bits de estados.
Note que quando as linhas 0 e 1 são acessadas, o bit 0 é colocado em 1 e o bit 3 permanece
inalterado. O segundo bit decide se o acesso é para linha 0 ou para a linha 1. Na tabela acima, o
símbolo “_” indica que o bit permanece inalterado.
4.2.2.4
SLRU (Segmented Least Frequently Used):
O algoritmo SLRU considera tanto a freqüência quanto a recenticidade de um bloco durante o
processo de substituição. O SLRU divide a cache em dois segmentos: Um segmento protegido
para armazenar dados que são acessados freqüentemente e um segmento não-protegido para dados acessados apenas uma única vez. As linhas em cada segmento são ordenadas de acordo com
a política LRU. Ou seja, da linha mais acessada para a menos acessada recentemente. Quando um
objeto é acessado pela primeira vez, o mesmo é adicionado no segmento não-protegido. Quando
ocorre um acerto em uma linha da cache, a mesma é movida para o segmento protegido.
A migração de uma linha do segmento não protegido para o segmento protegido deve forçar
a migração da linha menos usada recentemente do segmento protegido para o segmento nãoprotegido. Desta maneira, a linha removida do segmento protegido terá uma nova chance de
CAPÍTULO 4. SPARC V8
36
ser acessada antes de ser substituída. Durante o processo de substituição somente as linhas que
estão no segmento não-protegido podem ser escolhidas. A Figura 4.7 mostra o fluxo lógico de
migração das linhas da cache.
Figura 4.7: Fluxo lógico de uma cache SLRU.
Este algoritmo protege a cache de padrões de acesso que podem inundar as caches LRU com
dados que não serão reusados, o que pode provocar o descarte de linhas que tem alta probabilidade de serem reusadas. Por exemplo, em operações de backup ou em acessos a longos arquivos
de dados seqüenciais, vários dados serão utilizados apenas uma única vez [12]. O problema se
agrava quando as linhas dentro deste padrão de acesso representam uma fração significativa da
carga de trabalho e o tamanho da cache é pequeno.
Isto ocorre porque o LRU não considera a freqüência de uso dos dados. Este problema é
amenizado pelo algoritmo SLRU, pois ele leva em consideração a freqüência e a recenticidade
do bloco durante o processo de substituição. Desta maneira, o SLRU reconhece as linhas que
podem ser acessadas múltiplas vezes e as linhas que podem ser acessadas apenas uma única vez.
CAPÍTULO 4. SPARC V8
4.2.2.5
37
FIFO (First-In-First-Out):
Este algoritmo consiste em substituir o bloco que foi carregado há mais tempo na cache. É
uma política de fácil implementação e de baixo custo. Entretanto, por não considerar se a linha
substituída estava sendo muito utilizado ou não, um aumento no tamanho da cache pode provocar
uma aumento na taxa de falta da cache (miss hate). Esta deficiência do algoritmo é denominada
anomalia de Belady [3].
4.2.2.6
GreedyDual:
Este algoritmo é focado para sistemas onde o tamanho do dado a ser buscado é fixo, mas o
custo de buscá-lo é diferente. No caso da STORM, se a instância da plataforma possuir vários
diretórios, o custo de ser buscar um dado vai depender da distância entre o processador e o
diretório e da taxa de ocupação do mesmo.
O GreedyDual considera o custo e o quão recentemente este bloco foi utilizado para tomar
a decisão de substituição. O algoritmo associa um valor, denominado H, para cada linha l da
cache. Quando uma linha é carregada na cache, a H é atribuído o custo de trazer esta linha para
a cache. Quando uma substituição é necessária, a página com o menor H é escolhida para sair
e todas as outras linhas reduzem seus valores de H por Hmin . Onde Hmin é a linha com menor
custo. Quando uma ocorre um acerto em uma linha da cache, seu o valor de H é restaurado para
o custo de trazer a mesma para a cache.
Note que seria necessário K subtrações quando uma substituição é feita, onde K é o número
de linha da cache. Para evitar isso, utilizamos um valor de inflação L. Este valor irá deslocar
todos os futuros valores de H. A seguir temos o pseudo-código desta implementação:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
procedure G REEDY D UAL
while true do
if p está na cache then
H(s, p) ← L(s, p) + c(s, p)
else
L(s) ← minq∈M H(q)
carregue p na cache
c(s, p) ← custo de buscar p
H(s, p) ← L(s, p) + c(s, p)
end if
end while
end procedure
CAPÍTULO 4. SPARC V8
4.2.3
38
Política de Atualização
A política de atualização da cache determina quando uma alteração local será espelhada na memória principal. A cache utiliza a política de atualização de write-back. Tal política funciona
da seguinte maneira: As atualizações feitas em blocos da cache são gravadas apenas na própria cache. O bloco da cache modificado será gravado na memória principal apenas quando for
substituído da cache. Para diminuir o número de gravações na memória principal durante a substituição de um bloco, utiliza-se um bit de status que indica se o bloco em questão foi modificado
ou não. Este bit é comumente chamado de bit sujo (dirty). A idéia é que apenas blocos sujos precisam ser gravados na memória principal, pois os blocos não modificados, ditos limpos, possuem
uma cópia do dado na memória principal.
O write-back têm várias vantagens. Com o write-back, as gravações ocorrem na velocidade
da memória cache, pois não é necessário esperar que o bloco seja espelhado na memória principal. Além disso, com o write-back, várias gravações em um mesmo bloco geralmente exigem
apenas uma escrita na memória principal. Uma vez que, nem todos as gravações vão para a
memória principal, a política em questão utiliza menos largura de banda de memória. Utilizar
menos a NoC ou o barramento significa poupar energia e reduzir o tráfego off-chip.
As características citadas acima, tornam o write-back atraente em ambiente embutidos e multiprocessados como a STORM. A plataforma STORM utiliza uma política de escrita write-back
com alocação. Ou seja, quando ocorre uma falta durante um pedido de escrita de um bloco, este
bloco é alocado na cache.
4.2.4
Tamanho do Bloco
Outro parâmetro importante da cache é o tamanho dos blocos. Segundo o princípio da localidade
de referências, a vizinhança de uma palavra que acabou de ser usada tem grande probabilidade de
ser utilizada em um futuro próximo. Desta maneira, quando uma palavra é requerida pela cache
à memória principal, não apenas esta palavra é trazida, mas também um conjunto de palavras
adjacentes a palavra requerida.
Inicialmente, quando maior o tamanho do bloco, maior é a taxa de acerto na memória cache
devido ao princípio da localidade. Entretanto, a taxa de acerto na cache tende a diminuir se o
tamanho do bloco se tornar tão grande que a probabilidade de utilizar os dados buscados recentemente se tornar menor do que a probabilidade de reutilizar os dados que foram substituídos [21].
A relação entre o tamanho da cache e a taxa de acerto é complexa. Segundo Smith (1987 apud
[21]), um tamanho de bloco entre dois a oito parece estar próximo do ótimo.
Capítulo 5
Experimentos Computacionais
Este capítulo apresenta as aplicações desenvolvidas para validar o processador SPARC V8, os
módulos de caches e a metodologia de programação da STORM. Além disso, um breve estudo
sobre como o tamanho da cache, associatividade e o algoritmo de substituição afetam a taxa de
acerto da cache é apresentado.
5.1
Simulações
As simulações realizadas variam em complexidade e em propósito, o que permite uma análise
do desempenho e da aplicabilidade da plataforma em aplicações de pequeno e médio porte. As
aplicações começam em um simples cálculo do fatorial de um número, indo até uma complexa
compressão JPEG. Os resultados das simulações serão exibidos em tabelas semelhantes à esta:
Módulo
Descrição
Instruções Executadas
Quantidade de Ciclos
Ciclos por Instrução
Processador
Tempo de Execução
Ciclos/Segundos
Número de Operações
Cache de Instruções Taxa de Acerto
Ciclos de Espera
Número de Operações
Cache de Dados
Taxa de Acerto
Ciclos de Espera
Valor
xx
xx
xx
xx
xx
x
x%
x
x
x%
x
Tabela 5.1: Template das tabelas de resultados.
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
40
A primeira linha das tabelas é destinada aos dados do processador. Primeiramente, temos
“Instruções Executadas”, ou seja, o número de instruções executadas pelo SPARC. Em seguida,
“Quantidade de Ciclos” que informa a quantidade de ciclos gastos para completar a execução
da aplicação em questão. “Ciclos por instruções” ou CPI é número de ciclos gasto para realizar
cada instrução. Esta razão é dada pela seguinte fórmula matemática:
Quantidade de Ciclos
N úmero de Instrucões
Por sua vez, “Tempo de Execução” denota o tempo gasto para realizar a simulação em um
computador Pentium IV 3.0 HT com 512 MB de RAM. E por fim, “Ciclos/Segundos” é o de
número de ciclos realizados por cada segundo.
A segunda e a terceira linhas são destinadas a cache de instruções e dados respectivamente.
Tais linhas contém: “Número de operações”, Número de pedidos de leitura e escrita realizados
pela aplicação; “Taxa de Acerto”, proporção de acertos para todas as requisições; “Ciclos de Espera”, Número de ciclos que o processador para devido a faltas de leituras e escritas e operações
de coerência de cache.
Todas simulações foram realizadas com 1 processador SPARC e 1 módulo de memória interligados por uma árvore obesa. Já o sistema de cache utilizado foi composto por caches de
tamanho 8K, associatividade 1 e algoritmo de substituição FIFO. A seguir, apresenta-se cada
aplicação em ordem crescente de complexidade.
CP I =
5.1.1
Fatorial
O fatorial de um número é dado pela seguinte expressão matemática:
n! =
n
Y
k
∀n ≥ 0
k=1
Este algoritmo serviu para o teste de instruções mais simples do SPARC, como comparações,
saltos e estrutura de controles essenciais para a construções de aplicativos em linguagem de alto
nível.
Primeiramente, esta aplicação foi desenvolvida puramente em assembler SPARC. O objetivo
deste teste era verificar o processador isoladamente. Pela Tabela 5.2, nota-se que esta implementação não realizou acessos a cache de dados, pois os dados foram armazenados no próprio
conjunto de registradores do SPARC.
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
Módulo
Descrição
Instruções Executadas
Quantidade de Ciclos
Processador
Ciclos por Instrução
Tempo de Execução
Ciclos/Segundos
Número de Operações
Cache de Instruções Taxa de Acerto
Ciclos de Espera
Número de Operações
Taxa de Acerto
Cache de Dados
Ciclos de Espera
41
Valor
43
275
6,4
0’7"
39
45
95,56%
58
0
0%
0
Tabela 5.2: Resultados do Fatorial em assembler.
A tabela 5.2 exibe os resultados obtidos para o cálculo do fatorial de 1 até 10. Já a Tabela 5.3
apresenta a mesma aplicação, agora desenvolvida em C e compilada com o GCC. Esta segunda
simulação do fatorial permitiu verificar a integração do processador SPARC com a metodologia
de programação da STORM.
Uma comparação direta entre as duas versões do fatorial indica que o código escrito diretamente em assembly SPARC é bem mais eficiente do que o gerado pelo GCC. Por fim, pode-se
notar que esta segunda versão possui uma maior taxa de acerto na cache de instruções, entretanto
o número de instruções mais que triplicou.
Módulo
Descrição
Instruções Executadas
Quantidade de Ciclos
Ciclos por Instrução
Processador
Tempo de Execução
Ciclos/Segundos
Número de Operações
Cache de Instruções Taxa de Acerto
Ciclos de Espera
Número de Operações
Cache de Dados
Taxa de Acerto
Ciclos de Espera
Valor
145
941
6,49
0’17"
58,81
148
97,98 %
87
64
98,43 %
30
Tabela 5.3: Resultados do Fatorial desenvolvido em C.
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
5.1.2
42
Seqüência de Fibonacci
A seqüência de Fibonacci consiste em uma seqüência de números, tais que, definindo os dois
primeiros números da seqüência como sendo 0 e 1, os números seguintes são obtidos através
da soma dos seus dois antecessores. Matematicamente a seqüência de Fibonacci é definida pela
seguinte fórmula de recorrência:


se n = 0
 0
F (n) =
1
se n = 1


F (n − 1) + F (n − 2) outros casos
Este algoritmo foi implementado de forma recursiva e serviu para verificar as instruções de
chamada e retorno de funções, passagem de parâmetros e a verificar a alocação da pilha utilizada
durante a chamada de função. A Tabela 5.4 mostra os dados obtidos na simulação deste algoritmo
para o vigésimo primeiro elemento da seqüência de Fibonacci. Tal tabela mostra que o algoritmo
teve um bom desempenho, tendo taxa de acerto superior a 98% em ambas as caches. A execução
correta deste algoritmo validou as questões relativas a chamadas e retornos de funções.
Módulo
Descrição
Instruções Executadas
Quantidade de Ciclos
Processador
Ciclos por Instrução
Tempo de Execução
Ciclos/Segundos
Número de Operações
Cache de Instruções Taxa de Acerto
Ciclos de Espera
Número de Operações
Cache de Dados
Taxa de Acerto
Ciclos de Espera
Valor
558
3.581
6,42
0’ 13"
275,46
565
98,76%
203
331
99,03%
117
Tabela 5.4: Resultados do Fibonacci.
5.1.3
Run-length encoding - RLE
O Run-length é um simples algoritmo de compressão de dados, em que as seqüências de dados
com o mesmo valor são armazenadas com um contador e único valor. Essa técnica é muito
utilizada em dados que contém muitas seqüências de dados repetidos. Este tipo de padrão pode
ser encontrado em gráficos simples de imagens como ícones e logotipos.
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
43
Por exemplos, considere que temos uma linha de contendo texto plano preto em uma plano de
fundo branco. Ela terá uma longa seqüência de pixels brancos nos espaços em brancos e alguns
pixels pretos no texto. Podemos representar tal linha da seguinte forma:
W W W W W W W W W W W W BW W W W W W W W W W W W BBBW W W W W W W W W W
Se aplicarmos a compressão RLE na seqüência acima obtemos:
12W B12W 3B10W
Note que na seqüência original temos 40 caracteres contra 12 da versão comprimida, ou seja,
a versão comprimida é cerca de 3 vezes menor do que a original. O processo de descompactação
é imediato e consiste expandir a seqüência de caracteres de acordo com o valor do contador. Esta
simulação consistiu em compactar um pequeno ícone que continha 300 elementos. Os resultados
são relatados na Tabela 5.5.
Módulo
Descrição
Instruções Executadas
Quantidade de Ciclos
Processador
Ciclos por Instrução
Tempo de Execução
Ciclos/Segundos
Número de Operações
Cache de Instruções Taxa de Acerto
Ciclos de Espera
Número de Operações
Taxa de Acerto
Cache de Dados
Ciclos de Espera
Valor
29.099
162.955
5,6
0’ 26"
6.267,5
29.116
99,9%
493
8.849
99,5%
1.249
Tabela 5.5: Resultados do RLE.
Está simulação serviu para verificar a utilização de vetores na plataforma. Operações como
indexação, leitura e atribuição foram validadas ao final desta simulação. A taxa de compressão
foi de 16:1. Para carregar a imagem na plataforma, utilizou-se um programa auxiliar que coloca
a imagem em um vetor de inteiros. Este vetor é incluído no código fonte da aplicação e então
carregado na memória. Como mostra a Tabela 5.5, a cache teve uma taxa de acerto maior do que
99%.
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
5.1.4
44
Cifra de César
A cifra de César é um dos mais simples e conhecido algoritmo de encriptação de mensagens. O
nome do método faz referência ao imperador Júlio César que utilizava uma técnica semelhante
para se comunicar com os seus generais.
Trata-se de uma cifra de substituição em que cada letra do texto é substituída pela outra, que
está situada na ordem do alfabeto a um número fixo de posições. Por exemplo, com uma troca
de 3 posições a letra “A” seria trocada pela letra “D”, a letra “B” seria trocada pela letra “E”,
a letra “Z” pela letra “C”, e assim sucessivamente. Note que este algoritmo mantém mesmo
mapeamento durante toda a mensagem.
O processo de encriptação pode ser representado através de aritmética modular, primeiro
transforma-se as letras em número. Em seguida, aplica-se a seguinte equação matemática:
En (x) = (x + n)
mod S
De modo semelhante, a decifração é representada como:
Dn (x) = (x − n)
mod S
Onde S é o tamanho da alfabeto considerado, x é número que representa a letra e n é um deslocamento fixo. Este trabalho utilizou a tabela ASCII para converter letras em números.
Como a plataforma não suporta o tipo de dado caractere, utilizou-se um algoritmo preliminar
que transforma a mensagem do usuário em números inteiros de 32 bits. A Tabela 5.6 mostra os
resultados obtidos aplicando-se o algoritmo descrito em uma texto contendo 2.169 caracteres.
Módulo
Descrição
Instruções Executadas
Quantidade de Ciclos
Ciclos por Instrução
Processador
Tempo de Execução
Ciclos/Segundos
Número de Operações
Cache de Instruções Taxa de Acerto
Ciclos de Espera
Número de Operações
Taxa de Acerto
Cache de Dados
Ciclos de Espera
Valor
195.399
1.114.370
5,7
0’ 31"
35.947,41
195.417
99,32 %
522
58.398
99,06 %
16.078
Tabela 5.6: Resultados do algoritmo cifra de César.
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
45
A cifra de César foi a primeira aplicação com quantidade de ciclos e instruções consideráveis.
Os resultados mostram que foram executadas 195.399 instruções em 1.114.370 ciclos. Além
disso, nota-se na Tabela 5.6 que o simulador rodou a uma taxa de 35.947 ciclos/segundo.
5.1.5
Busca Binária
A busca binária é um eficiente algoritmo de busca em vetores ordenados. A idéia do algoritmo
é realizar sucessivas divisões do espaço de busca, comparando o elemento buscado (chave) com
o elemento no meio do vetor. Se o elemento do meio do vetor for a chave, a busca termina com
sucesso. Caso contrário, se o elemento do meio vier antes do elemento buscado, então a busca
continua na metade posterior do vetor. E finalmente, se o elemento do meio vier depois da chave,
a busca continua na metade anterior do vetor.
A complexidade desse algoritmo é da ordem de log2 n, onde n é o tamanho do vetor de busca.
A seguir temos o pseudo-código do mesmo. Onde A é o vetor de entrada, X é chave a ser buscada
e N é o tamanho do vetor.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure B USCA B INARIA(A,X,N )
menor ← 0
Alto ← N − 1
while (menor ≤ maior) do
meio = (menor+maior)
2
if A[meio] < X then
baixo ← meio + 1
else if X < A[meio] then
alto ← meio − 1
else
return meio
end if
end while
return − 1
end procedure
O teste deste algoritmo consistiu em buscar o elemento central de uma lista de 500 elementos.
Os resultados da simulação são exibidos na Tabela 5.7. Os dados coletados nesta simulação
mostraram que o número de ciclos com o processador parado é insignificante quando comparado
com a quantidade total de ciclos simulados.
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
Módulo
Descrição
Instruções Executadas
Quantidade de Ciclos
Processador
Ciclos por Instrução
Tempo de Execução
Ciclos/Segundos
Número de Operações
Cache de Instruções Taxa de Acerto
Ciclos de Espera
Número de Operações
Taxa de Acerto
Cache de Dados
Ciclos de Espera
46
Valor
7.807
47.596
6,1
0’ 22"
663,45
7.818
99,85%
347
3.125
97,85%
2.037
Tabela 5.7: Resultados da Busca Binária.
5.1.6
MergeSort
O Mergesort, ou ordenação por mistura, é um algoritmo de ordenação baseado na estratégia de
dividir para conquistar. É um algoritmo estável que executa em O(n ∗ log n). Um algoritmo de
ordenação é dito estável quando ele preservar a ordem de entrada de elementos iguais na saída
produzida pelo mesmo.
A idéia da abordagem dividir-para-conquistar é dividir o problema em vários subproblemas
semelhantes mas menores em tamanho, resolver os subproblemas recursivamente e depois combinar essas soluções com o objetivo de produzir uma solução para o problema original. Essa
técnica aplica três passos a cada nível de recursão que são: dividir, conquistar e combinar.
Os três passos dessa estratégia aplicados ao Mergesort são:
1. Dividir: A seqüência de entrada de n elementos é dividida em duas subseqüências de n/2
elementos cada.
2. Conquistar: Ordena as duas subseqüência recursivamente através de chamadas recursivas
a mergesort.
3. Combinar: Faz a intercalação das duas seqüências ordenadas, de modo a produzir a resposta ordenada.
A Tabela 5.8 apresenta os dados da simulação. Esta simulação consistiu em ordenar 1.000 elementos de um vetor formado aleatoriamente e depois verificar se estes elementos estão realmente
ordenados. Esta segunda etapa se faz necessária porque não existem rotinas de I/O para inspeção
do vetor. Além disso, como a plataforma STORM não possui suporte as bibliotecas de C, não
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
47
foi possível utilizar a função rand do C. Para contornar este problema, foi implementado um
conjunto de funções que geram números aleatórios para a STORM.
Módulo
Descrição
Instruções Executadas
Quantidade de Ciclos
Ciclos por Instrução
Processador
Tempo de Execução
Ciclos/Segundos
Número de Operações
Cache de Instruções Taxa de Acerto
Ciclos de Espera
Número de Operações
Cache de Dados
Taxa de Acerto
Ciclos de Espera
Valor
740.537
4.341.641
5,86
1’08"
63.847,26
740.573
99,9%
1.094
322.882
99,9%
8.250
Tabela 5.8: Resultados do Mergesort.
O objetivo deste teste era submeter o SPARC a uma carga maior de operações para verificar
o seu comportamento, visando iniciar o desenvolvimento aplicações mais complexas. Observase na Tabela 5.8 a simulação com sucesso de mais de quatro milhões de ciclos. Novamente,
destaca-se o excelente desempenho do sistema de cache que atingiu uma taxa de acerto superior
a 99%.
5.1.7
Algoritmo de Prim
O algoritmo de Prim é um algoritmo em teoria dos grafos que produz uma árvore geradora
mínima a partir de um grafo conexo ponderado. Uma árvore geradora mínima é uma árvore que
inclui todos os vértices e cujo a soma dos pesos de todas as arestas que estão na árvore é mínimo.
O algoritmo funciona da seguinte maneira: Cria-se uma árvore contendo um único vértice
arbitrário e a cada passo, adiciona-se uma aresta mínima que conecte uma vértice presente na
árvore a um não presente a árvore.
Considere um grafo G = (N, M, D), onde N denota o conjunto de vértices, M denota o
conjunto de arcos e D = [dij ] o conjunto dos pesos associados às arestas de G. E os conjuntos B
e T tal que T ⊆ M e B ⊆ N . O seguinte pseudo-código descreve os passos do algoritmo em
questão.
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
48
procedure P RIM(G = (N, M, D))
B=i
V =V \i
while (B! = N ) do
Encontrar a menor aresta (j,k) ∈ M tal quej ∈ B, k ∈ V
B =B∪k
V =V \i
T = T ∪ (j, k)
end while
end procedure
O algoritmo descrito acima é da ordem de θ(M log N ). Outra característica importante deste
algoritmo é fato de pertencer a classe dos algoritmos gulosos. A Tabela 5.9 exibe os resultados
da aplicação do algoritmo Prim aplicado a uma árvore de 100 nós. Com base nesta tabela, podese inferir que apenas 1,2% da quantidade de ciclos total foram gastos em operações de acesso a
dados na cache.
Módulo
Descrição
Instruções Executadas
Processador
Quantidade de Ciclos
Ciclos por Instrução
Tempo de Execução
Ciclos/Segundos
Número de Operações
Cache de Instruções Taxa de Acerto
Ciclos de Espera
Número de Operações
Cache de Dados
Taxa de Acerto
Ciclos de Espera
Valor
521.336
2.964.642
5,69
1’ 24"
35.293,35
521.363
99,9%
837
143.758
98,88%
35.611
Tabela 5.9: Resultados do Prim.
5.1.8
Cifra de Hill
A cifra de Hill é uma clássica cifra de substituição polialfabética baseado em álgebra linear.
Inventada por Lester S. Hill em 1929, este método consiste em fazer m combinações lineares dos
m caracteres que compõem o texto original, produzindo m caracteres criptografados.
O processo de encriptação da cifra de Hill funciona da seguinte maneira: todas as letras da
mensagem são tratadas como dígitos na base 26, onde A = 0, B = 1, ..., Z = 25. A mensagem
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
49
é dividida em blocos de n letras que formando um vetor de n dimensões. Cada bloco é então
multiplicado por uma matriz quadrada de ordem n módulo n. O resultado representa o texto
cifrado. Os elementos da matriz quadrada de ordem n constituem a chave e devem formar uma
matriz inversível em Zn26 .
Em resumo, para um n = 2, um dado texto P = ( p1, p2 ) será levado para um texto criptografado C = ( c1, c2 ), onde c1 é uma combinação linear de p1 e p2 descrita por uma chave K (uma
matriz n x n).
Considere a mensagem “ACT” e a chave:
"
6 24 1
13 16 10
#
Desde que ’A’ seja 0, ’C’ seja 2 e ’T’ seja 19, a mensagem é dada pelo seguinte vetor:

0


 2 
19

Assim o vetor criptográfico é dado por:
"
6 24 1
13 16 10
#

 
 
15
67
0

 
 

 2  ≡  222  ≡  14 
7
319
19

mod 26
O vetor acima corresponde a mensagem cifrada “POH”.
O processo de decifração é feito em dois passo. Primeiro, transformamos o texto cifrado em
um vetor de n dimensões. Em seguida, multiplicamos este vetor pela matriz inversa da matriz
chave. A inversa da matrix do exemplo anterior é dada por:


8 5 10


 21 8 21 
21 12 8
Logo, para descriptografar a seqüência “POH” procedemos da seguinte maneira:


 
 

8 5 10
15
260
0


 
 

 21 8 21   14  ≡  574  ≡  2 
21 12 8
7
539
19
mod 26
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
50
Desta maneira conseguimos o texto original “ACT”.
A implementação utilizada neste trabalho extendeu o alfabeto de entrada para 29 letras e
utilizou 5000 caracteres contidos nas duas primeiras cenas do primeiro ato do livro "THE TRAGEDY OF OTHELLO" de William Shakespeare. A Tabela 5.10 resume os dados obtidos após a
simulação. Nesta simulação foram executadas 530.023 instruções em 3.054.248 de ciclos, logo
o simulador executou uma instrução a cada 6 ciclos aproximadamente.
Módulo
Descrição
Instruções Executadas
Quantidade de Ciclos
Processador
Ciclos por Instrução
Tempo de Execução
Ciclos/Segundos
Número de Operações
Cache de Instruções Taxa de Acerto
Ciclos de Espera
Número de Operações
Cache de Dados
Taxa de Acerto
Ciclos de Espera
Valor
530.023
3.054.248
5,76
1’02"
49.262
530.040
99,9%
5.305,16
179.163
99,47%
26.733
Tabela 5.10: Resultados da simulação do algoritmo Hill.
5.1.9
JPEG
O JPEG é um formato de compressão de imagens com perda de dados. JPEG é a sigla de Joint
Photographers Experts Group, nome do comitê que desenvolveu o formato. Em 1994, o JPEG
foi aprovado como ISO 10918-1, tornando-se o primeiro padrão internacional de compressão de
imagens.
O JPEG é o formato ideal para imagens que precisam ter tamanho reduzido, como imagens
para serem usadas em sites da web, ou para serem enviadas por email, etc. O tamanho das
imagens (em bytes) torna-se bastante reduzido , pois sua compressão pode chegar a até 90%. Mas
é claro que com um poder de compressão tão alto, existe uma perda na qualidade da imagem.
E vale ressaltar que, uma vez perdida, esta qualidade não pode ser recuperada. Devido a esta
característica, o JPEG é denominado um padrão ’lossy’, ou seja, ocorre perda de qualidade na
compressão da imagem. Por sua vez, outros padrões de compressão podem ter sua qualidade
recuperada. Sendo então caracterizados como ’lossless’ – sem perda da qualidade de imagem no
processo de compressão.
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
51
O processo de compressão do padrão JPEG funciona, em linhas gerais, da seguinte forma:
Primeiramente, o formato de representação de cores pode ser alterado de RGB para YUV. Essa
transformação melhora o desempenho do JPEG, pois nos espaços de cores do tipo luminância e
crominância, os componentes são mais descorrelacionados do que no formato RGB, potencializando a eliminação de informações menos importantes para o olho humano.
Com a imagem no espaço de cores YUV, é efetuada uma operação denominada de downsampling. Esta operação reduz a taxa de amostragem dos componentes de crominância, associando
a vários pixels a informação de crominância de um único pixel amostrado. O downsampling é
baseada na constatação que a informação de luminância é a mais importante para a percepção do
olho humano do que as informações de crominância.
Após a operação de downsampling, a imagem é organizada em blocos de 8x8 pixels e em
cada um destes blocos é calculada a transformada discreta do cosseno ( DCT - discrete cossine
transform). A função da DCT é converter as informações no domínio do tempo para o domínio
da freqüência. Em seguida, os coeficientes gerados pela DCT são quantizados e alguns coeficientes são até eliminados. O processo de quantização1 é o maior responsável pelo o grau de
compactação conseguido pelo JPEG. Por fim, um algoritmo de compressão lossless, chamado de
codificação de entropia, é aplicada a imagem.
O algoritmo implementado neste trabalho usa imagens com 8-bit de cores, quantização padrão e não realiza a transformação do espaço de cores e operações de downsampling. A Tabela
5.11 mostra os resultados obtidos aplicando-se uma imagem bitmap de 176x144 pixels ao algoritmo JPEG.
Módulo
Descrição
Instruções Executadas
Quantidade de Ciclos
Processador
Ciclos por Instrução
Tempo de Execução
Ciclos/Segundos
Número de Operações
Cache de Instruções Taxa de Acerto
Ciclos de Espera
Número de Operações
Cache de Dados
Taxa de Acerto
Ciclos de Espera
Valor
9.772.020
57.708.135
5,91
12’23"
77.669
15.268.402
98,88%
5.003.279
2.672.212
96.18%
3.785.874
Tabela 5.11: Resultados da simulação do JPEG.
1
quantização é o processo de discretização de uma variável contínua.
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
52
O JPEG foi o algoritmo mais complexo desta bateria de testes. Foram executadas 9.772.020
instruções em 743 segundos, ou seja, foram executadas, aproximadamente, 13.153 instruções por
segundo. A taxa de acerto da cache de dados foi superior a 96%. A seguir, temos a figura utilizada
nesta simulação. Novamente, um arquivo de pre-processamento foi utilizado para carregar a
imagem na plataforma.
Figura 5.1: Figura utilizada na simulação do JPEG.
5.2
Análise dos Parâmetros da Cache
A crescente distância entre a velocidade da CPU e a da memória principal incentivou os projetistas a procurarem maximizar o desempenho da cache. Em ambientes multi-processados, o custo
de se buscar um dado na memória é geralmente muito mais elevado do que o custo de se buscar
o mesmo dado em ambientes uniprocessados, devido a concorrência pelo acesso a memória e o
overhead dos mecanismo de coerência de cache.
Entretanto, como foi dito anteriormente, o mercado de embarcados compete em custo e em
potência, desta maneira, a relação custo/benefício é fundamental importância para o projeto.
A principal métrica de desempenho da cache, é a taxa de acerto. Existem três importantes
parâmetros que afetam diretamente a taxa de acerto da cache. O tamanho da cache, a associatividade e o tamanho do bloco. O efeito da mudança do tamanho do bloco não será analisado
neste trabalho. Analisaremos, portanto, os efeitos do tamanho da cache e da associatividade da
cache. Para realizar está análise, utilizou-se um algoritmo GRASP para o problema de redes de
distribuição de gás desenvolvido em [7].
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
53
Figura 5.2: Associatividade versus Tamanho da Cache.
O gráfico da Figura 5.2 mostra que a taxa de acerto da cache cresce com o aumento de seu
tamanho. Entretanto, este crescimento ocorre até um certo ponto. Além disso, o custo, área
ocupada e o consumo de energia também aumentam com o aumento do tamanho da cache.
O gráfico também mostra que um aumento na associatividade provoca um aumento na taxa
de acerto da cache. Por outro lado, nota-se que o ganho com o aumento da associatividade
diminui com o aumento do tamanho da cache. Entretanto, aumentar a associatividade implica em
aumentar a complexidade da cache, pois o número de blocos a serem considerados no processo
de substituição também aumenta. O aumento da complexidade, por sua vez, eleva o custo e o
tempo de acesso da cache.
Desta maneira, conclui-se que o projeto da cache visa balancear o custo e o desempenho. A
questão a ser respondida é: Qual deve ser o tamanho e a complexidade da cache para se obter
uma taxa de acerto aceitável a um custo também aceitável?.
É evidente que a resposta para esta questão é dependente das restrições, do tipo e do propósito
do sistema. Cabe a equipe de projetistas encontrar o ponto ótimo para o sistema em questão.
5.3
Análise dos Algoritmos de Substituição
O algoritmo de substituição tem um profundo impacto na taxa de acerto da cache e conseqüentemente influi diretamente no desempenho e indiretamente no tamanho da cache. Pois, um bom
desempenho do algoritmo de substituição pode permitir a utilização de cache menores.
CAPÍTULO 5. EXPERIMENTOS COMPUTACIONAIS
54
Para validar dos algoritmos apresentados na Seção 4.2.2, utilizaremos o mesmo algoritmo do
teste anterior e caches de tamanho 4 KB e 8 KB com associatividade 4. Estas configurações foram escolhidas porque apresentaram os melhores resultados nos testes exibidos na seção anterior.
A Tabela 5.12 resume os dados coletados durante as simulações.
Tamanho Algoritmo
FIFO
LFU
LRU
4 KB
Pseudo LRU
SLRU
GreedyDual
FIFO
LFU
LRU
8 KB
Pseudo LRU
SLRU
GreedyDual
Taxa de Acerto
94,02 %
90,74 %
94,18 %
93,25 %
94,5 %
88,44 %
95,36 %
97,01%
97,14 %
94,97 %
97,8 %
95,6 %
Tabela 5.12: Tamanho versus Algoritmo de Substituição versus Taxa de acerto.
Os resultados da Tabela 5.12 mostram que o algoritmo SLRU teve o melhor desempenho nos
testes. Este resultado demonstra que combinar os mais recentes com os mais freqüentes pode
evitar os problemas inerentes a cada uma dessas abordagens quando utilizadas isoladamente.
Por outro lado, os testes indicam que mesmo quando utilizadas isoladamente ambas as estratégias conseguem bons resultados. Além disso, a tabela mostra que não há diferença significativa
entre as políticas LRU e LFU quando o tamanho da cache aumenta.
Os resultados indicaram que o algoritmo Pseudo-LRU fornece uma boa aproximação do
LRU. A diferença entre os dois algoritmos ficou em torno de 2%. Entretanto, essa diferença
tende a aumentar com o aumento da associatividade da cache.
Por fim, o razoável desempenho apresentado pelo algoritmo GreedyDual ocorreu devido ao
ambiente de simulação utilizado que era composto por um processador, uma memória e uma
NoC. O GreddyDual é voltado para ambientes onde os custos de falhas na cache não são uniformes, entretanto no ambiente utilizado, os custos de falhas na cache são uniformes. É evidente
que uma análise mais profunda do desempenho deste algoritmo se faz necessária. Porém, tal
análise foge do escopo específico deste trabalho.
Capítulo 6
CONCLUSÃO
O presente trabalho abordou o desenvolvimento de uma implementação da arquitetura SPARC e
de módulos de cache L1 para a plataforma STORM. O desafio era suprir a falta de uma unidade
de processamento e ao mesmo tempo, prepara a plataforma para ser utilizada na área do P&G.
O SPARC desenvolvido no âmbito do trabalho é um processador comercial de alto desempenho com suporte a ambientes multiprocessados, tratamento de interrupções, suporte a dispositivos de I/O e ao compilador GCC. O suporte ao compilador GCC é particularmente interessante
para o desenvolvimento de aplicações em linguagens de alto nível como a linguagem C.
A nível de arquitetura, foram abordados aspectos comuns a toda implementação SPARC
e aspectos específicos desta implementação. Os resultados obtidos com a modelagem, design e
implementação demonstraram que de acordo com as decisões de microarquitetura, o processador
pode ser incorporado em diferentes níveis de design de sistemas embarcados. Esta característica
da arquitetura SPARC, permite o desenvolvimento de sistemas embarcados com uma grande
variedade de preço e de desempenho.
Os módulos de cache L1 desenvolvidos foram planejados para oferecer alto grau de personalização. O sistema de cache permite configurar o modo de mapeamento e a política de
substituição, como também o tamanho das caches, da linha da cache, do bloco da cache.
Além disso, o sistema de caches suporta os três modos de mapeamento tradicionais: mapeamento direto, completamente associativo e associativo por conjunto. Além de 6 algoritmos de
substituição: FIFO, LFU, LRU, Pseudo-LRU, SLRU e GreedyDual.
Todos os módulos foram feitos em SystemC e validados com um rica suite de aplicações. Os
testes verificaram o comportamento do processador tanto isoladamente quanto integrado com a
STORM.
CAPÍTULO 6. CONCLUSÃO
56
A conclusão deste trabalho possibilitou a execução de aplicações reais na plataforma. Seja
aplicações voltadas para área de P&G, como as desenvolvidas em [7], seja para grafos, compressão de imagens ou dados, criptografia e etc.
Por fim, a integração do SPARC a STORM é mais um passo na concepção e avaliação de
sistemas MP-SoC. O processador permitiu a execução de aplicações reais na plataforma. Através
destas execuções, foi possível estimar a complexidade e o desempenho deste tipo de sistema.
Além de possibilitar a realização de diversos estudos sobre os mecanismos de coerência de cache,
sincronização e escalonamento de processos, Entrada/Saída, interconexão, dentre outros.
6.1
Trabalho Futuros
Vários trabalhos futuros podem ser apontados ao final deste trabalho. O primeiro é o desenvolvimento de módulos de Entrada/Saída. Sua implementação é de particular interesse da área
do petróleo e gás natural, pois permitirá à plataforma ter comunicação com o meio na qual está
inserida. A nível acadêmico, os módulos de Entrada/Saída para ambiente MP-SoC interligados
por NoC é um campo aberto para pesquisas.
A implementação de um sistema operacional para prover a gerência de recursos e permitir
a multiprogramação é outro trabalho de grande importância acadêmica. A nível de arquitetura,
pode-se realizar várias melhorias no SPARC como: desenvolvimento de técnicas de previsão de
desvio, unidades de ponto-flutuante ou de co-processadores, tratamento de interrupções imprecisas, dentre outros. A abrangência das possibilidades é bastante grande e esse trabalho abre
margem para sua exploração.
Referências Bibliográficas
[1] Angiovanni-Vincentelli, A.; Martin G.; Platform-based design and software design
methodology for embedded systems. Design & Test of Computers, IEEE Volume 18, Issue
6, pp. 23-33, Nov.-Dec. 2001.
[2] Bautista, T.; Núñez, A. Design of Efficient SPARC cores for embedded systems. In: Euromicro Conference, 25, 1999. Proceedings... Milan: 1999, vol. 1, p. 1236-1239.
[3] Belady, L. A.; Nelson, R. A.; Shedler, G. S. An anomaly in space-time characteristics
of certain programs running in a paging machine. Commun. ACM 12, 1969. Montvale:
1969. p. 349-353.
[4] Cao, P.; Irani, S. Cost-aware WWW proxy caching algorithms. In: USENIX Symp. on Internet Technologies and Systems. Proceedings... Monterey, CA: 1997, p. 193-206.
[5] Carro, L.; Wagner, F. Capítulo 2 das Jornadas de Atualização em Informática. In: XXII
JAI 2003. (Org.). Sistemas Computacionais Embarcados. Campinas: Sociedade Brasileira
de Computação, 2003, v. 1, p. 45-94.
[6] de Micheli, G.; Benini, L. Networks-on-Chip: A New Paradigm for Systems-on-Chip Design. In: Design, Automation and Test in Europe Conference and Exhibition. Proceedings...
Paris: 2002, p. 418-419.
[7] Freitas, Tássia A. Vieira. Desenvolvimento de Aplicações da Indústria do Petróleo e Gás
em uma plataforma MP-SoC. 2006. Relatório Final de Graduação ( Bacharel em Ciências
da Computação) - Curso de Ciências da Computação, Universidade Federal do Rio Grande
do Norte, Natal, 2006.
[8] Garner, B. et al. The Scalable Processor Architecture (SPARC). In Proceedings of the IEEE
COMPCON 88, New York, NY, IEEE, pp 278-283, 1988.
REFERÊNCIAS BIBLIOGRÁFICAS
58
[9] GNU Compiler Collection. Disponível em: http://gcc.gnu.org/. Acessado em 20/11/2006.
[10] Hennessy, J. L.; Patterson, D. A. Arquitetura de Computadores: Uma Abordagem Quantitativa. 3.ed. Rio de Janeiro: Campus Editora, 2003. 927p.
[11] ITRS (2001). International Technology Roadmap for Semiconductors, versão 2001. Disponível em http://public.itrs.net/.
[12] Karedla, R.; Love, J. S.; Wherry, B. G. Caching Strategies to Improve Disk System
Performance. IEEE Computer, Vol.27, No. 3, p. 38-46.
[13] Kilburn, T. et al. One-level storage system. IRE Trans. on Electronic Computers, pages
223-235, April 1962.
[14] Namjoo, Masood et al. CMOS Gate Array Implementation of the SPARC Architecture. In:
COMPCON Conference. Proceedings... San Franciso: 1988. p. 10-13.
[15] Smith, J.; Pleszkun, A. R. Implementing Precise Interrupts in Pipelined Processors. In: Annual International Symposium on Computer Architecture, 12, 1985. Proceedings... Boston:
1985 p. 36-44.
[16] Rego, Rodrigo Soares de Lima Sá. Projeto e Implementação de uma Plataforma MPSoC usando SystemC. 2006. 134p. Dissertação (Mestrado em Sistemas e Computação) Curso de Pós-graduação em Sistemas e Computação, Universidade Federal do Rio Grande
do Norte, Natal, 2006.
[17] SPARC International, Inc. The SPARC Manual Architecture Manual Version 8. Upper
Saddle River, NJ, USA: Prentice Hall, 1992.
[18] Stallings, W. Arquitetura e Organização de Compuratores: Projeto para o Desempenho.
5.ed. São Paulo: Prentice Hall, 2002. 786p.
[19] Standard for Binary Floating-Point Arithmetic.
per.ieee.org/groups/754/. Acessado em 04/12/2006.
Disponível
em:
grou-
[20] SystemC User’s Guide. Version 2.0. Update for SystemC 2.0.1. 2003. 216p.
[21] Tanenbaum, A. S. Organização Estruturada de Computadores. 4 ed. LTC Editora, 1999.
[22] Thomas, José Eduardo. Fundamentos de Engenharia de Petróleo. 2.ed. Rio de Janeiro:
Interciência, 2004. 287p.

Documentos relacionados