Arquitetura Risc

Propaganda
Universidade Estadual de Maringá
Centro de Tecnologia
Departamento de Informática
ESTUDO SOBRE A ARQUITETURA RISC
Carlos Sica, 1999
1. Arquitetura RISC (Reduced Instruction Set Computing)
1.1. Histórico
Inicialmente os computadores tinham poucas instruções e um ou dois modos de
endereçamento
Num segundo passo, surgiram os computadores microprogramados, com um conjunto de
instruções extremamente complexo no nível de máquina, essa linguagem de máquina era
interpretada por microprograma que ficam em ROM, o que implica em não modificar,
apesar de ser um programa. Esta tecnologia levou a criação de computadores (ex. VAX)
com 200 instruções e 12 modos de endereçamento.
A linguagem de alto nível começou a predominar e a distância semântica (semantic gap)
complicou a construção de compiladores. Instruções de alto nível do tipo: if, while, case,
etc., devem ser traduzidas para instruções de baixo nível tipo: mov, add e jump. A solução
para reduzir esta distância foi elevar o nível da linguagem de máquina, o que era analisado
positivamente por alguns autores, que desejavam instruções de máquina com mais campos
e menos registradores.
Também, em outros tempos, a velocidade da RAM era muito mais baixa que a da CPU,
além disso, 10 vezes mais baixa que a ROM, o que criou o desejo de que todos as
instruções fossem resolvidas em microcódigos ao invés de programação normal.
1.2. Regras
Sacrifique tudo para reduzir o tempo de ciclo da via de dados.
Microcódigo não é mágico.
1.3. Filosofia básica
1. Analisar as aplicações para encontrar as operações chave e elaborar uma máquina
ótima para as realizadas pelos programas alvo. Segundo Tanenbaum - 1992, quase
50% das instruções de um programa são comandos de atribuição, 23% de comandos
de seleção, 15% de chamadas à funções, 6% de laços de repetição e, 10%, de outros
comandos.
2. Projetar uma via de dados que seja ótima para as operações chave. Este é o coração
de uma máquina RISC. Composto pelos registradores, pela ULA e pelos barramento
internos que os conectam. Em um único ciclo, os operandos devem ser lidos dos
registradores, operados pela ULA e o resultado armazenado em um registrador.
Operando1
Resultado
Operando2
3. Projetar as instruções que executem as operações chaves, estas devem utilizar de
forma ótima as vias de dados, ou seja, cada instrução deve utilizar um único ciclo da
via de dados.
4. Adicionar novas instruções somente se elas não diminuírem a velocidades da
máquina
5. Repetir este processo para outros recursos
1.4. Instruções por ciclo de via de dados
A característica mais importante de uma máquina RISC é que as instruções são
completadas em um único ciclo de via de dados. Se isso não ocorre, ela não pode fazer
parte do conjunto de instruções. Isto acarreta em não ser possível ter instruções como de
multiplicação, o que é resolvido por uma série de operações de soma e deslocamento.
Um instrução RISC é muito parecida com uma microinstrução. Uma operação de alto nível
precisa de muitas instruções para ser completada, por outro lado, uma instrução CISC pode
levar, muitos ciclos para ser completada devido a interpretação pelo microprograma.
1.5. Registradores
Os compiladores escritos para máquinas RISC fazem uso intenso de registradores, com
intenção de reduzir o tráfego na via de dados em comunicação com a memória.
Um processador RISC não tendo microcódigo, não ocupa área de memória para tal tipo de
operação, portanto, pode construir um grande número de registradores utilizando esse
espaço.
1.5.1. Organização dos registradores
Os registradores são organizados na forma de janelas sobrepostas. Apesar da CPU possuir
muitos registradores, em média 512, nesta técnica apenas um conjunto de registadores, em
geral de 32 registradores de 32 bits, é visível para o programa a cada momento. Este
conjunto é ainda dividido em subconjuntos conforme mostra a figura abaixo.
R0..R7
32 bits
Variáveis globais e ponteiros
R8..R15
Parâmetros de entrada
R16..R23
Variáveis locais
R24..R31
Parâmetros de saída
Utilizados por todos os procedimentos, o
compilador decide o que colocar aqui.
Evita o uso de pilha na memória, que é utilizada
apenas em caso de exceder 8 parâmetros.
Em geral 8 variáveis são suficientes para um
procedimento, excesso vai na pilha.
Parâmetros para os procedimentos chamados
(entrada para eles).
Por este formato, facilmente podemos concluir que os registradores de variáveis globais
podem ser os mesmos para todos os procedimentos, assim, não há necessidade de se ter
fisicamente um conjunto para cada.
Os parâmetros de saída, que são entradas para o procedimento chamado, também podem
ser sobrepostos economizando espaço.
ProcA
Globais
Entrada
Locais
Saída
ProcB
Globais
Entrada
Locais
Saída
ProcC
Globais
Entrada
Locais
Saída
ProcD
Globais
Entrada
Locais
Saída
Quando o procedimento A chama o procedimento B passando parâmetros para ele, a área é
comum, este subconjunto de registradores são sobrepostos.
1.5.2. Estudo comparativo: REGISTRADORES x CACHE
Na arquitetura RISC, os registradores são organizados por janelas sobrepostas, e servem
para armazenar as variáveis e parâmetros que são acessadas mais rapidamente. Esta
filosofia coincide com a filosofia da memória cache utilizada pela maioria das arquiteturas
conhecidas atualmente.
1.5.2.1.
Variáveis locais
No RISC todas as variáveis locais, com as exceções discutidas no item 1.5.1, são
armazenadas em registradores. Já, no caso da cache, isto é feito apenas com as variáveis
mais recentemente utilizadas.
A vantagem da cache aparece quando se discute a transferência de funções ou trechos de
programas para ela, o que seria impossível para os registradores. Porém, uma desvantagem
aparece justamente neste ponto, pois, a transferência é feita por blocos e, quando se trata de
variáveis, algumas que são carregadas na chache são serão utilizadas.
1.5.2.2.
Variáveis globais
Semelhante à técnica anterior. Estudos mostram que existe um bom número de variáveis
globais, porém, nem todos são fortemente utilizadas. A cache, como guarda as mais
recentemente utilizadas, com o tempo, terá a vantagem de guardar apenas aquelas mais
necessárias.
1.5.2.3.
Endereçamento de memória
No caso de procedimentos ou funções, nos registradores, os dados são movimentados entre
eles e a memória com baixa freqüência e, como a cache, em geral é pequena e de uso geral,
outras informações podem sobrepor os blocos já carregados, incorrendo no atraso de
execução.
Para um registrador ser acessado basta conhecer o seu número e o da janela. Atividade
simples e rápida. Porém, para acessar a memória cache, um endereço completo deve ser
calculado e a complexidade deste cálculo é diretamente proporcional à complexidade do
modo de endereçamento e, sabemos que na arquitetura CISC, isto pode ser muito
complexo. A cache é realmente tão rápida quanto um registrador, porém, o acesso a ela é
demasiadamente lento.
1.6. Acesso à memória
É impossível acessar a memória em um único ciclo. Neste caso a arquitetura RISC tem que
abrir mão da regra básica e aceitar pelo menos duas instruções maiores: leitura e escrita na
memória.
Instruções comuns continuam tendo apenas registradores como operandos, o que limita os
modos de endereçamento, excluindo por exemplo o direto, o indexado e o indireto.
Assim, apenas duas instruções estabelecem a comunicação da CPU com a memória, ainda
assim, devem utilizar registradores específicos.
Há que se analisar também a questão de instruções como as necessárias para trabalhar com
memória virtual, multiprocessamento e assim por diante. Talvez estas tenham sido o grande
problema de se manter a ideologia da arquitetura RISC proposta, então o conjunto foi
incrementado com novas instruções para executar tais tarefas.
1.7. Pipelining
Pensemos no seguinte exemplo: um homem sozinho assenta os azulejos de uma cozinha.
Ele precisa buscar cada peça na pilha, acomodar a massa, colocar o ladrilho. Se ele utilizar
os serviços de um ajudante, pode eliminar a tarefa de buscar os azulejos e se concentrar nop
assentamento. Simples, duas pessoas trabalhando termina o serviço mais rápido.
A técnica do pipelining é muito semelhante ao exemplo acima e também à uma linha de
montagem de carros. Cada funcionário faz sua tarefa e no final o carro está pronto mais
rápido que se cada pessoa montasse um deles.
Uma CPU pipelined deve permitir a execução total da instrução por estágios, por exemplo,
busca da instrução na memória; execução da instrução e referências memória (quando
houver). Se utilizando esta técnica uma instrução for iniciada a cada ciclo, mesmo que ela
demore mais de uma para ser finalizada, em média a regra estaria cumprida. Em cinco
ciclos, cinco instruções foram iniciadas.
Busca da instrução
Execução da instrução
Referência a memória
1
A
2
B
A
3
C
B
4
D
C
B
5
E
D
A instrução A é buscada no primeiro ciclo e executada no segundo. Já a instrução B utiliza
dois ciclos para terminar sua operação, porém, não interfere na busca e execução da
instrução C, e mais, se a instrução C não utilizar o registrador que está sendo atualizado
pela instrução C, ela pode terminar sua operação sem problemas e a máquina continua
trabalhando em velocidade total.
Caso isto não aconteça, é necessário inserir uma instrução NOP para esperar o término
daquela instrução de dois ciclos, o que, naturalmente atrasa o processamento geral.
Busca da instrução
Execução da instrução
Referência a memória
1
A
2
B
A
3
C
B
4
NOP
NOP
5
D
C
B
Para amenizar este tipo de problema, e muitas vezes realmente solucioná-lo, o compilador
deve ser bom o suficiente para garantir que a próxima instrução, não vai utilizar o dado que
está sendo trazido da memória. Isto pode ser feito com uma instrução que não seja a que
esteja na seqüência escrita pelo programador. O compilador deve organizar a execução das
instruções visando o resultado final, tapando os "buracos" que surgirem por execução de
instruções de mais de um ciclo, com "coisas úteis" ao ínves de NOPS's.
Outras instruções além da que acessam a memória podem atrapalhar o processamento. Um
JUMP condicional, onde o compilador não pode prever o resultado, obriga algumas vezes o
esvaziamento do pipeline para executar o desvio.
Nestes casos as técnicas utilizadas se chamam, repectivamente, carga atrasada e desvio
atrasado, ambas resolvidas pelo compilador.
1.8. Ausência do microcódigo
As instruções geradas por um compilador para uma máquina RISC, executam diretamente
no hardware. A eliminação do nível de interpretação, é o fato que influencia diretamente na
velocidade do computador.
Um programa compilado para CISC tem menos instruções assembly que para um RISC, o
que é vantajoso na economia de memória, porém, não na velocidade de execução.
1.9. Formato das instruções
Como as instruções são decodificadas pelo hardware a necessidade de se criar um formato
fixo para elas se torna claro. Cada bit que forma uma instrução entra diretamente no
decodificar ou até mesmo em outras partes do hardware.
opcode
c destino fonte
i
offset
Neste exemplo o mnemônico é composto pelo código de operação, um sinalizador para
instruções condicionais, um campo para endereçar o registrador destino e um para o fonte,
outro sinalizador para o modo de endereçamento imediato ou não e finalmente o offset do
endereço do operando.
1.10.
Modos de endereçamento
1.10.1.
Modo imediato (i = 1)
Para instruções com um operando que faz parte da instrução, o segundo operando é uma
constante descrita no offset.
1.10.2.
Modo direto
Para operandos em registrador (i = 0), o primeiro operando seria o conteúdo do registrador
fonte e, o segundo, endereçado pelos bits menos significativos do offset, consequentemente,
o resultado armazenado no registrador destino.
1.10.3.
Modo indexado
Para instruções de leitura e escrita na memória, o endereço seria composto pelo offset
somado ao registrador fonte, criando o modo indexado.
1.10.4.
Modo indireto por registrador
O decodificador de instruções quando encontra o offset igual a zero, traduz o endereço
como indireto por registrador, pois, o endereço do operando seria o contido no registrador
fonte.
1.10.5.
Outros modos
O compilador pode criar outros tipos de modos, traduzindo-os para os básicos, por
exemplo, no projeto RISCII, criou-se um JUMP condicional relativo ao ponteiro de
instruções ou contador de programa (IP ou PC), concatenando os três campos de baixa
ordema para formar um offset de 19 bits com sinal, podendo assim, se deslocar para cima
ou para baixo.
1.10.6.
Conclusão
O crescimento do número de modos de endereçamento em uma máquina, implica na perda
de velocidade e também no aumento da complexidade. Porém, apesar do nome, uma
máquina RISC poderia ter muitas instruções, contanto que elas executassem em um único
ciclo de via de dados e tivessem o formato fixo. O comprometimento nesse caso, seria o de
construir uma unidade de decodificação bastante complexa, já que ele cresceria
exponencialmente com o número de instruções.
2. Compiladores
2.1. Compiladores x hardware
Todo esse estudo conduz para um hardware mais simples quanto possível, não é necessário
muito esforço para concluir que a complexidade do compilador cresce proporcionalmente à
simplicidade do conjunto de instruções, que no RISC esta diretamente ligado ao hardware.
Instrução em alto nível
compilador
Código de máquina
Quando chega-se justamente ao ponto mais controverso no debate entre CISC x RISC, o
desenho do compilador.
Os defensores do CISC alegam que a distância semântica conduz a ineficiência de
execução, programas excessivamente grandes e compiladores complexos e argumentam
que a disponibilidade de instruções de alto nível e a habilidade de especificar múltiplos
operandos baseados na memória, simplifica o desenho do compilador. Naturalmente, isto
leva diretamente para um conjunto de instruções grande, dezenas de modos de
endereçamento e muitas declarações da linguagem de alto nível implementadas em
firmware.
Surgem divergências entre as estruturas estudadas e as implementadas, como exemplo
pode-se citar a instrução LOOP utilizada já no PC-xt para controle de laço de repetição.
Esta instrução repete um bloco de instruções por um número fixo de vezes como o "parafaça", mas faz isto, pelo menos uma vez como o "repita-até".
mov cx, 32
Aqui:
;estabelece o critério de parada
....
....
loop aqui
;decrementa cx, e desvia para aqui se cx > 0
Este bloco poderia facilmente ser traduzido com a utilização de decrementos, comparação e
desvio condicional, porém, nota-se aqui que a arquitetura CISC não economiza instruções.
Fica então a pergunta: qual é a arquitetura que melhora o desenho do compilador? Sabendose que este compilador deve ser um compilador otimizador, irá produzir códigos de
execução mais rápidos. Uma vez que as instruções devem ocupar um ciclo em média, o
compilador deve reorganizar a seqüência das instruções, de forma a tapar os "buracos"
gerados pelas de maior tempo.
2.2. Otimização dos compiladores
Um programa escrito em linguagem de alto nível, não explicita os registradores que serão
utilizados, ao invés disso, faz referências simbólicas aos valores através das variáveis
criadas. Além disso, não explicita se o valor associado à variável será guardado num
registrador ou na memória. Como sabe-se que os registradores são mais rápidos que a
memória, é desejável que sejam largamente utilizados.
Cada variável passível de ser guardada em um registrador, recebe um tratamento especial.
O compilador pode criar um número ilimitado "registradores virtuais" para armazená-las e,
a partir daí, compartilhar o registrador real de acordo com alguma técnica específica. Claro,
isto é feito dentro da limitação da CPU e muitas variáveis vão obrigatoriamente para a
memória.
Os compiladores mantém esta filosofia de forma transparente para o programador, mas
alguns, como é o caso da linguagem C, oferecem a possibilidade do programador decidir
quais variáveis devem, sempre que possível, serem armazenadas em registradores, para
tanto, ao declarar uma variável, ao invés de escrever: int soma; escreve-se: register
int soma; obrigando então, o compilador a priorizar os registradores para aquela variável.
As arquiteturas RISC utilizam, freqüentemente, a técnica dos grafos coloridos para
otimizar o uso de registradores pelas variáveis. Está técnica não é discutida nesta
publicação.
3. Estudo comparativo: RISC x CISC
3.1. Histórico
A tecnologia RISC foi desenvolvida pela IBM nos anos 70 e o primeiro chip surgiu em
1980. Sua proposta baseou-se em um conjunto reduzido de instruções, sendo definidas
apenas as mais freqüentemente utilizadas e se evitando o uso de microcódigos. As
instruções também seriam simplificadas, trabalhando com apenas um operando.
As operações enfatizavam o uso de registradores, sendo o acesso à memória limitado a
instruções tipo leitura e escrita na memória (load/store). Assim, o processador gastaria
apenas um ciclo por instrução. Porém, o que sucedeu não foi tão simples assim, pois havia
muita dificuldade em se escrever programas complexos utilizando um conjunto muito
reduzido de instruções. Então este conjunto foi incrementado com novas instruções, como
as necessárias para trabalhar com memória virtual, multiprocessamento e assim por diante.
A tecnologia RISC começou a ser promovida no mercado com o surgimento das estações
de trabalho científicas, pois sua atividade básica é "CPU bound". Os chips CISC (Complex
Instrution Set Computing) de aplicação mais geral - típicas de ambientes comerciais - não
ofereciam a velocidade necessária aos trabalhos com extensas manipulação de números e
visualização gráfica. Em ambiente comercial, por seu lado, é necessário considerar todo o
conjunto que compõe o sistema, como CPU, memória, velocidade de discos, sistema
operacional e software de aplicação.
Uma comparação levando em conta apenas o processador e sua técnica, não é correta.
Muitos dos fatores que aumentam a velocidade de um processador RISC, não são inerentes
a esta tecnologia (como uso de cache, pipeline de instruções e grande número de
registradores na CPU), sendo que estes recursos estão disponíveis a qualquer projeto de
computador, sendo usados também em máquinas CISC.
A análise dos processadores do mercado mostra que nos aspectos de mips ou operações
aritméticas com números inteiros (SPEC Integer), o desempenho dos chips RISC e CISC
são similares; em ponto flutuante (SPEC Floating Point) os RISC tendem a apresentar
resultados melhores, embora o Pentium lhes seja equivalente.
3.2. A evolução da tecnologia conduz para a igualdade
Cada vez mais as tecnologias RISC e CISC estão se aproximando: processadores RISC
estão aumentando seu conjunto de instruções e os CISC estão adotando técnicas
originalmente implementadas nos RISC. Por exemplo, o número de ciclos por instrução é
bastante similar em ambos. O resultado prático é que o "path length" destes processadores
para executar uma tarefa é praticamente igual.
As razões para isso são simples. Em aplicações comerciais, a CPU trabalha cerca de 30%
do tempo com instruções de movimentação de cadeias de caracteres de um lugar a outro na
memória; em programação Cobol é interessante dispor de instruções de aritmética decimal
e trabalhar com operandos "não alinhados". Desta forma, será necessário adicionar-se
instruções tipicamente CISC para trabalhar adequadamente com estas tarefas.
O Pentium, segundo a Intel, utiliza tecnologia CRISC, acoplamento das duas técnicas. Na
verdade algumas máquinas RISC utilizam poucas de suas técnicas básicas, ao mesmo
tempo que implementam conceitos típicos dos projetos CISC; entretanto, adotam o jargão
RISC por questão de marketing.
Um ambiente comercial é caracterizado por processamento transacional, com muita
manipulação de cadeias e inteiros além de alto fluxo de entrada/saída. Já o científico se
caracteriza por grande número de instruções de ponto flutuante. A conclusão lógica é que
as máquinas dos dois tipos tem diferentes concepções para diferentes utilizações.
3.3. Oito diferenças críticas
1
2
3
4
5
6
7
8
Instruções simples levando um ciclo
Apenas LOAD/STORE referenciam a memória
Altamente pipelined
Instruções executadas pelo hardware
Instruções com formato fixo
Poucas instruções e modos
A complexidade está no compilador
Múltiplos conjuntos de registradores
Instruções complexas levando múltiplos ciclos
Qualquer instrução pode referenciar a memória
Não tem pipeline ou tem pouco
Instruções interpretadas pelo microprograma
Instruções com vários formatos
Muitas instruções e modos de endereçamento
A complexidade está no microprograma
Conjunto único de registradores
4. Exercícios Resolvidos
i.
Historicamente, quais necessidades levaram a criação do RISC? e do CISC?
Os primeiros computadores digitais eram extremamente simples, possuíam poucas
instruções e somente um ou dois modos de endereçamento (detalhe: as instruções eram
executadas diretamente pelo hardware). A mudança veio com a introdução da série
IBM360. Todos os modelos desta série eram microprogramados.
Os microprogramas executados apresentavam um conjunto de instruções no nível de
máquina, chamada de linguagem de máquina (exemplo: ADD, MOVE, etc.). A grande
evolução das linguagens de programação de alto nível acarretou no problema da distância
semântica (semantic gap) entre estas linguagens e a linguagem de máquina, o que tornou a
construção de compiladores uma tarefa bastante complexa.
Na tentativa de reduzir a distância semântica, optou-se por elevar o nível da linguagem de
máquina. Uma forma encontrada para realizar isto foi introduzir o conceito de microcódigo.
O microcódigo é um software bastante primitivo, que controla diretamente os dispositivos
de hardware. Este software é composto por um conjunto de microprogramas, usualmente
armazenado em ROM, mais rápida do que a RAM. Ele é na verdade um interpretador que
busca as instruções de máquina na memória principal gerando um conjunto de sinais de
controle necessários para a execução de tais instruções pelo hardware. Para executar uma
instrução ADD, por exemplo, o microprograma específico precisa determinar onde os
valores a serem adicionados estão armazenados, buscá-los na memória, adicioná-los e
armazenar o resultado em um registrador ou na própria memória. Desta forma, foram
adicionadas novas instruções na linguagem de máquina, assim como outros modos de
endereçamento.
À medida que o nível da linguagem de máquina eleva-se (oferece mais instruções
complexas), o seu interpretador torna-se maior, mais complexo e mais lento e, um maior
número de instruções, implica em um maior tempo gasto na decodificação dos opcodes.
Com o aumento da velocidade da RAM, diminuindo a diferença com a velocidade da
ROM, e a crescente complexidade do microcódigo (devido à grande quantidade de
microprogramas acrescentados) o desempenho desta arquitetura já não era tão
extraordinário. Além disso, apesar da arquitetura CISC oferecer um grande conjunto de
instruções e vários modos de endereçamento, apenas uma pequena porção destas instruções
são realmente utilizados. O restante são utilizados eventualmente. Deste modo, constatouse que a velocidade da máquina era abreviada devido à adição de instruções e modos que
raramente são utilizados.
A partir disto, percebeu-se que era possível aumentar a velocidade de um computador
eliminando-se o interpretador de instruções complexas, reduzindo o conjunto de instruções,
eliminado todas as instruções que não podem ser completadas em um único ciclo da via de
dados, com exceção de LOAD/STORE. Os programas de usuários, desta forma, são
compilados para seqüências destas instruções e então executadas diretamente pelo
hardware.
APLICATIVOS
S.0.
LINGUAGEM DE MÁQUINA
MICROCÓDIGO
DISPOSITIVOS FÍSICOS
ii.
Um sistema de computador que utiliza o conceito
de microcódigo. Este, serve de intermediário entre
a linguagem de máquina e os dispositivos físicos,
ou seja, serve como um interpretador.
Qual o número máximo de instruções que um processador deve ter para ser
considerado RISC?
No princípio, a base da arquitetura RISC pretendia que esta possibilitasse instruções
simples e que fossem as mais freqüentemente utilizadas, construindo um conjunto
otimizado de instruções. Um aspecto importante era permitir a otimização da
implementação de pipeline nesta arquitetura, não o número de instruções que ela
disponibilizaria. Algumas operações exigem a implementação de operações que não podem
ser feitas em um único ciclo, exigindo que a arquitetura RISC tivesse ao menos algumas
instruções mais complexas, como por exemplo para lidar com gerenciamento de memória
virtual, multiprocessamento, etc. A partir daí, várias máquinas lançadas no mercado vêm
apresentando número variável de instruções, o que deu margem a várias informações
desencontradas sobre o que vem a ser uma máquina RISC e uma máquina CISC. Por
motivo de marketing muitas máquinas com características de funcionamento de arquiteturas
CISC são denominadas RISC pelo simples fato de apresentarem menos de 100 instruções.
O máximo que se pode conseguir, é basear este número em máquinas conhecidas: a
Motorola 88000 apresenta 51 instruções, já a MIPS R4000 possui 94 instruções. Apesar de
ter sido cogitado no principio a criação de uma máquina com uma única instrução
[FALTOU REFERÊNCIA], parece que seguimos o caminho contrário, e as máquinas RISC
aumentam seu número de instruções a cada versão.
Segundo um popular jornal de computação [FALTOU REFERÊNCIA], processadores com
menos que 100 instruções são considerados RISC. Porém não existe nenhuma restrição
formal quanto ao número máximo de instruções de um processador RISC, desde que cada
instrução seja executada em um ciclo da via de dados. O único problema real é que a
complexidade do bloco decodificador, OP, cresce exponencialmente com o número de
instruções e assim consome proporcionalmente crescentes áreas da pastilha.
iii.
Discorra sobre papel do compilador para um RISC (pode usar comparações
como o CISC)
FILOSOFIA DO PROJETO RISC: Deixar tanto trabalho quanto for possível a cargo do
compilador.
De certa forma, o trabalho para se alcançar os objetivos dos projetistas ao criar arquitetura
RISC, simplificar o conjunto de instruções e otimizar o funcionamento do processador,
recaiu sobre o compilador. Pelo fato de não mais se utilizar microcódigo para fazer a
interpretação da linguagem de máquina o trabalho do compilador se tornou um pouco mais
complicado. Agora, além de gerar microcódigo para programas de usuários, ele deve
administrar toda a seqüência de pipeline do programa, e garantir seu funcionamento
otimizado, de forma a não permitir ciclos vazios, além de possibilitar que operações com
dados da memória possam ser feitas em média em um ciclo de via de dados. Logo, a tarefa
executada pelo microcódigo da arquitetura CISC passa a ser do compilador.
A tecnologia do compilador é um fator crítico do projeto RISC. Compiladores otimizados
devem transportar toda a complexidade do hardware para a fase de compilação.
Para manter a simplicidade do hardware, o compilador é projetado para lidar com
características intrincadas da arquitetura RISC, como cargas, armazenamento e desvios
atrasados, que aumentam consideravelmente a complexidade do compilador.
O compilador deve fazer uso intensivo de registradores para reduzir o tráfego de memória,
para evitar instruções que demoram mais do que um ciclo da via de dados para serem
completados. Consequentemente, é essencial que o compilador RISC seja capaz de otimizar
da melhor maneira possível o uso de registradores, levando em consideração que as
instruções comuns não podem utilizar operandos de memória. Para viabilizar esta
otimização são utilizados algoritmos de alocação de registradores sofisticados. Apesar
destes algoritmos melhorarem o código colocando mais variáveis em um número limitado
de registradores, eles também aumentam a complexidade do compilador.
Além disso, o compilador RISC deve, sempre, buscar produzir um código correto e
eficiente, tentando contornar os problemas acarretados pelos saltos atrasados, por exemplo.
A partir destes fatos, constata-se que a arquitetura RISC também possui alguns problemas,
assim como a arquitetura CISC, guardadas as devidas proporções.
iv.
Descreva a passagem de parâmetros entre procedimentos em uma máquina:
a)CISC
A maioria dos procedimentos recebem parâmetros fornecidos pelo procedimento que
chama. Nas máquinas CISC, estes parâmetros são empilhados um de cada vez, pelo
processo que chama, no início da execução da instrução CALL. O procedimento chamado,
busca na pilha os parâmetros esperados. Este processo se baseia 100% na comunicação com
a memória.
b)RISC
O objetivo de toda máquina RISC é executar uma instrução por ciclo, em média. Uma vez
que LOAD e STORE requerem, normalmente, dois ciclos, quanto menos instruções deste
tipo forem utilizados, maior será a “eficiência” da máquina.
Grande parte do tráfego de memória total está relacionada a chamadas de procedimentos.
Parâmetros têm que ser passados, registradores têm que ser salvos, e o endereço de retorno
tem que ser empilhado na chamada e desempilhado no retorno. Todas estas ações geram
alto tráfego de memória.
Uma forma de eliminar parte deste tráfego é utilizar um método chamado janelas
sobrepostas de registradores, adotado por algumas máquinas RISC. Quando janelas
sobrepostas são utilizadas, a CPU contém um grande número de registradores, mas em cada
momento somente um subconjunto deles, 32 registradores de 32 bits, é visível para um
programa. Este conjunto é dividido em quatro grupos distintos com 8 registradores cada.

O primeiro grupo (R0 a R7) guarda variáveis globais e ponteiros; esses são utilizados
por todos os procedimentos ao longo do programa, sendo da responsabilidade decidir o
que colocar em cada registrador.

O segundo grupo, R8 a R15, guarda os parâmetros de entrada; evita o uso de pilha, que
é utilizada somente se o número de parâmetros exceder 8, neste caso, o último
registrador contém o endereço da pilha onde se encontra o restante dos parâmetros. Não
colocar os parâmetros na pilha elimina STORE’s quando eles são passados e elimina
LOAD’s quando eles são acessados pelo procedimento chamado.

O terceiro grupo , R16 a R23, estão disponíveis para as variáveis locais, o excedente
também vai para a pilha.

O quarto grupo de registradores, R24 a R31, é utilizado para passar os parâmetros para
os procedimentos chamados, sendo a pilha utilizada somente na falta de registradores
para os parâmetros.
Desta forma, quando um procedimento A chama um procedimento B, A deve passar
os parâmetros para B, colocando-os nos registradores de parâmetros de saída. Os
parâmetros de entrada de B serão os parâmetros de saída de A, sendo assim, os dois
conjuntos trabalham sobrepostos (janelas sobrepostas).
v.
Debata sobre: CACHE x REGISTRADORES
O conjunto de registradores, age com um pequeno e rápido buffer para o armazenamento de
um subconjunto de todas as variáveis que provavelmente serão utilizadas. Deste ponto de
vista, o conjunto de registradores se comporta como uma memória cache, porém existem
diferenças entre estes meios de armazenamento.
A cache tem a vantagem de armazenar não somente dados, como também instruções
recentemente utilizadas, o que seria impossível para os registradores. Além disso ela não
possui uma divisão rígida como a imposta pelo método de janelas sobrepostas.
No RISC todas as variáveis locais e globais, são armazenadas em registradores. Estudos
mostram que existe um bom número de variáveis globais, porém, nem todos são fortemente
utilizadas. A cache, como guarda as mais recentemente utilizadas, com o tempo, terá a
vantagem de guardar apenas aquelas mais necessárias. Constata-se, então, que a cache
possui uma importante característica de se adaptar ao padrão de uso real, sendo
potencialmente eficiente. Porém, toda entrada de cache possui três partes: o bit válido, o tag
e o dado. Somente a última é utilizada para armazenar dados, e as duas primeiras são uma
forma de overhead o que reduz a eficiência da máquina. Além disso, um registrador ser
acessado basta conhecer o seu número e o da janela. Atividade simples e rápida. Já o acesso
à memória cache, é uma tarefa complicada, pois são necessários realizar cálculos
relativamente complexos para encontrar o endereço. A cache é realmente tão rápida quanto
um registrador, porém, o acesso a ela é demasiadamente lento.
REGISTRADORES
CACHE
VARIÁVEIS LOCAIS
Todas as variáveis locais são Armazena as variáveis mais
armazenadas
recentemente utilizadas
VARIÁVEIS GLOBAIS
Todas são armazenadas
ENDEREÇAMENTO DE
MEMÓRIA
Acesso direto a partir de seu Endereçamento complexo que
número e o da janela
deve ser calculado
TRANSFERÊNCIA
Impossível a transferência de Em blocos e permite a
funções
ou
trechos
de transferencia de trechos de
programa
programas/funções
vi.
Armazena somente as mais
recentemente utilizada
Uma Máquina RISC pode (ou deve) ter CACHE?
Uma máquina RISC pode ter cache. Isto dependerá da aplicação para o qual a máquina é
projetada. A cache oferece muitas características que podem ser benéficas para um projeto
RISC, entre elas, a possibilidade de armazenamento de trechos de código, que é impossível
para os registradores. Além disso, os “on-chip caches”, que quando cronometrados se
apresentam tão rápidos quanto o processador.
Conclui-se que a decisão correta, quanto a implementação ou não da memória cache, deve
ser baseada numa ponderação sobre todas características debatidas no item anterior.
vii.
Quais os modos de endereçamento permitidos nas máquinas RISC?
Os modos de endereçamento de máquinas RISC variam de máquina para máquina, dentre
as máquinas mais conhecidas existe uma variação de 1 a 4 modos de endereçamento.
Entretanto, devido para não quebrar a regra primordial da arquitetura RISC: não utilizar
mais de um ciclo de via de dados, máquinas RISC só podem ter como operandos,
registradores, logo, elas não permitem modo de endereçamento para endereçamento direto,
endereçamento indexado, ou endereçamento indireto por registrador ou memória. Ou seja,
referencias à memória devem ser feitas através de instruções especiais de LOAD e STORE
adicionadas à arquitetura. Obviamente não é possível acessar à memória em um único
ciclo, porém, a técnica de pipeline possibilita que um método de execução de instruções
permita que no total n instruções sejam executadas em n ciclos, mantendo a média de uma
instrução por ciclo de via de dados. O compilador do RISCII, entretanto trazia um JUMP
condicional relativo ao ponteiro de instruções ou contador de programa, concatenando os
três campos de baixa ordem poderia-se formar um offset de 19 bits com sinal podendo ser
deslocado para cima ou para baixo.
viii.
Decodificar cada instrução o assembly da SPARC
a)
31
30
29
28
27
26
25
24
23
22
21
20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
1 1 1 0 0 0 1 1 1 0 0 1 0 1 0 1 0 1 1 1 1 0 0 0 0 0 1 1 1 1 0 1
rd
rs1
op
sisconst1a
Verificando o primeiro campo da instrução (da esquerda para direita), poderia-se dizer que
se trata de uma instrução para load ou store. Sendo o bit 13 igual a 1, sabemos que se trata
de uma instrução de store, entretanto, como o campo op (bits 19 a 24) armazena uma
seqüência de valores que não pertence a tabela de códigos de operação de load e store, é
descartada esta possibilidade. O valor do primeiro campo também poderia indicar que a
instrução seja uma instrução geral das máquinas SPARC, porém, o campo dos bits 19 a 24
também não fazem parte da tabela de instruções, podemos concluir que se trata de uma
instrução inválida.
b)
31
30
29
28
27
26
25
24
23
22
21
20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
0 1 1 1 0 0 0 0 1 1 1 1 0 0 0 1 0 1 0 1 1 1 1 0 1 0 1 0 1 1 1 0
Os dois primeiros bits da instrução com valores 0 e 1 indicam uma instrução call. Não
existem demais exigências para comprovação da instrução, os demais bits (0 a 29) formam
o endereço de desvio e, desta forma, estão disponíveis para o contador do programa.
c)
31
30
29
28
27
26
25
24
23
22
21
20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 1 1
Devido aos valores da seqüência de bits 22 a 24 não corresponderem a nenhum valor da
tabela de instruções de desvio condicional ou instruções sethi, descartou-se a possibilidade
de serem este tipo de instrução e, considerando a seqüência dos bits do campo op (22 a 24)
concluiu-se que se trata de uma instrução não implementada com código de campo
correspondente a instruções ilegais.
d)
31
30
29
28
27
26
25
24
23
22
21
20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 1 0 1 0
A instrução acima corresponde a instrução de subtração, caracterizado pelo valor 10 dos
primeiros campos e pela seqüência de bits do campo op (22 a 24) que correspondem a
instrução subcc. O campo rd (25 a 29) corresponde ao campo de registrador de destino, no
caso o %R19, o campo rs corresponde ao registrador origem (14 a 18), um segundo
operando origem pode ser um registrador (0 a 4) ou um valor constante (0 a 12). Na
instrução acima, trata-se de um valor constante no campo siconst (1FOA h).
e)
31
30
29
28
27
26
25
24
23
22
21
20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
0 1 1 1 0 1 0 1 0 1 0 1 0 1 1 0 1 0 1 1 1 0 1 0 0 1 1 0 1 0 1 0
Esta é outra instrução call, foi analisada da mesma forma que a instrução da letra b.
ix.
a)
Escreva o código assembly SPARC para os seguintes módulos
if (delta > 0)
z=0;
else
y=0;
.text
start: set delta, %r1
ld [%r1], %r2
set z, %r1
ld [%r1], %r3
set y, %r1
ld[%r1], %r4
cmp %r2, 0
bg cond
mov %r0, %r4
cond: mov %r0, %r3
b)
conta=0;
while (conta <0){
y=conta;
conta++;
}
! delta é armazenado em %r2
! z é armazenado em %r3
! y é armazenado em %r4
! compara delta e 0
! se delta é maior que zero desvia para cond
! y recebe 0
! instrução de desvio:
.text
start: set conta, %r0
ld [%r1], %r4
set y, %r0
ld [%r1], %r2
test:
mov %r0, %r4
cmp %r4, 0
bg nop
mov %r4, %r2
add %r4, 1, %r4
ba test
! conta é armazenada em %r4
! y é armazenado e %r2
! y=conta;
! compara conta e 0;
5. Bibliografia
TANENBAUM, A., Organização e Arquitetura de computadores, Prentice Hall do Brasil,
1990
STALLINGS, W., Computer Organization and Architeture, Prentice Hall, 1996
5.1. Internet
http://minerva.ufpel.tche.br/~machado/risccisc/pagina.html
http://www.din.uem.br/sica/apostilas
http://www.sunworld.com/sunworldonline/swol-09-1999/swol-09-insidesolaris.html
Download