Pipeline ARM de 5 Estágios Explicado
Pipeline ARM de 5 Estágios Explicado
Todos os processadores têm que se desenvolver para atender à demanda por um desempenho mais alto. O pipeline de 3 estágios utilizado em
os núcleos ARM até o ARM? é muito econômico, mas um desempenho mais alto exige o processador
organização a ser repensada. O tempo, T, necessário para executar um determinado programa é dado por: onde Ninst é
o número de instruções ARM executadas durante o programa, CPI é a média do número de
ciclos de relógio por instrução e fclk é a frequência de clock do processador. Como Ninst é constante para um dado
programa (compilado com um determinado compilador usando um determinado conjunto de otimizações, e assim por diante) existem apenas
duas maneiras de aumentar o desempenho: • Aumentar a taxa de clock, fclk. Isso requer a lógica em cada pipeline
a etapa a ser simplificada e, portanto, o número de etapas do pipeline a ser aumentado.•Reduzir a média
número de ciclos de clock por instrução, CPI. Isso requer que instruções que ocupam mais do que
um slot de pipeline em um pipeline de 3 estágios ARM é reimplementado para ocupar menos slots, ou aquele pipeline
as interrupções causadas por dependências entre instruções são reduzidas, ou uma combinação de ambos.
Gargalo de memória:O problema fundamental de reduzir o IPC em relação a um núcleo de 3 estágios está relacionado a
o gargalo de von Neumann - qualquer computador de programa armazenado com uma única memória de instrução e dados irá
ter seu desempenho limitado pela largura de banda de memória disponível. Um núcleo ARM de 3 estágios acessa a memória em
(quase) cada ciclo de clock, seja para buscar uma instrução ou para transferir dados. Simplesmente apertando um pouco os poucos
ciclos onde a memória não é utilizada gerarão apenas um pequeno ganho de desempenho. Para obter um desempenho significativamente melhor
O sistema de memória CPI deve fornecer mais de um valor em cada ciclo de clock, seja entregando mais do que
32 bits por ciclo a partir de uma única memória ou tendo memórias separadas para acessos a instruções e dados.
Como resultado das questões acima, núcleos ARM de maior desempenho utilizam um pipeline de 5 estágios e possuem separadas
memórias de instrução e de dados. Dividindo a execução de instruções em cinco componentes em vez de três
reduz o trabalho máximo que deve ser concluído em um ciclo de relógio e, portanto, permite uma frequência de relógio mais alta
frequência a ser utilizada (desde que outros componentes do sistema, e particularmente a memória de instrução, também estejam
redesenhadas para operar nessa taxa de relógio mais alta). As memórias de instrução e dados separadas (que podem ser
caches separadas conectadas a uma memória principal unificada de instrução e dados) permitem uma redução significativa na
CPI do núcleo.
Um típico pipeline ARM de 5 estágios é aquele empregado no ARM9TDMI. A organização
do ARM9TDMI é ilustrado na Figura 4.4 na página 81
Pipeline de 5 Estágios.
Os processadores ARM que utilizam um pipeline de 5 estágios têm os seguintes estágios de pipeline:
Geração de PC O comportamento do r15, como visto pelo programador e descrito em 'comportamento do PC' na página 78, é
com base nas características operacionais do pipeline ARM de 3 estágios. O pipeline de 5 estágios lê a instrução
operandos um estágio antes no pipeline e, naturalmente, obteriam um valor diferente (PC+4 em vez de PC+8).
Como isso levaria a incompatibilidades de código inaceitáveis, no entanto, todos os ARMs de pipeline de 5 estágios
emular o comportamento dos antigos designs de 3 estágios. Referindo-se à Figura 4.4, o valor de PC incrementado a partir de
a fase de busca é alimentada diretamente no arquivo de registradores na fase de decodificação, contornando o registrador de pipeline entre o
duas etapas. PC+4 para a próxima instrução é igual a PC+8 para a instrução atual, então o valor correto de r15
é obtido sem hardware adicional.
A execução de uma instrução ARM pode ser melhor compreendida em referência à organização do caminho de dados como
apresentado na Figura 4.1 na página 76. Usaremos uma versão anotada deste diagrama, omitindo o controle
seção lógica, e destacando os ônibus ativos para mostrar o movimento dos operandos entre as várias unidades em
o processador. Começamos com uma simples instrução de processamento de dados.
Instrução de processamento de dados: Uma instrução de processamento de dados requer dois operandos, um dos quais é sempre um
o registrador e o outro é ou um segundo registrador ou um valor imediato. O segundo operando é passado por
o deslocador de barril onde está sujeito a uma operação de deslocamento geral, então é combinado com o primeiro operando em
ALU usando uma operação geral de ALU. Finalmente, o resultado da ALU é gravado de volta no destino
o registrador (e o registrador de código de condição podem ser atualizados). Todas essas operações ocorrem em um único ciclo.
ciclo conforme mostrado na Figura 4.5 na página 83. Note também como o valor do PC no registrador de endereço é incrementado e
copiado de volta para ambos os registradores de endereço e r15 no banco de registradores, e a próxima instrução, mas uma, é
carregado na parte inferior do pipeline de instruções (i. pipe). O valor imediato, quando necessário, é extraído
a partir da instrução atual no topo do pipeline de instruções. Para instruções de processamento de dados apenas o
os oito bits inferiores (bits [7:0]) da instrução são usados no valor imediato
Instruções de transferência de dados: Uma instrução de transferência de dados (carregar ou armazenar) calcula um endereço de memória de uma maneira
muito semelhante à maneira como uma instrução de processamento de dados calcula seu resultado. Um registrador é usado como o endereço base,
ao qual é adicionado (ou do qual é subtraído) um deslocamento que, por sua vez, pode ser outro registrador ou um imediato
valor. Desta vez, no entanto, um valor imediato de 12 bits é usado sem uma operação de deslocamento, em vez de um valor de 8 bits deslocado.
valor. O endereço é enviado para o registro de endereço, e em um segundo ciclo ocorre a transferência de dados. Em vez disso
do que deixar o caminho de dados amplamente ocioso durante o ciclo de transferência de dados, a ULA mantém os componentes do endereço de
o primeiro ciclo e está disponível para computar uma modificação de auto-indexação ao registrador base se isso for necessário.
(Se a auto-indexação não for necessária, o valor calculado não é gravado de volta na base)
registre-se no segundo ciclo.)
A operação do caminho de dados para os dois ciclos de uma instrução de armazenamento de dados (SIR) com um deslocamento imediato estão mostradas
na Figura 4.6 na página 84. Note como o valor do PC incrementado é armazenado no banco de registradores no final do
primeiro ciclo para que o registrador de endereço esteja livre para aceitar o endereço de transferência de dados para o segundo ciclo, então em
no final do segundo ciclo, o PC é realimentado para o registrador de endereço para permitir que a pré-busca de instruções continue.
Talvez seja importante observar nesta fase que o valor enviado para o registrador de endereço em um ciclo é o valor usado
para o acesso à memória no ciclo seguinte. O registro de endereço é, na verdade, um registro de pipeline entre o
caminho de dados do processador e a memória externa.
(O registrador de endereço pode gerar o endereço de memória para o próximo ciclo um pouco antes do final do atual)
ciclo, movendo a responsabilidade pelo atraso do pipeline para a memória quando isso é desejado. Isso pode permitir
alguns dispositivos de memória para operar em alto desempenho, mas esse detalhe pode ser adiado por enquanto.
Por agora, veremos o registrador de endereços como um registrador de pipeline para a memória.) Quando a instrução especifica o
armazenamento de um tipo de dado byte, o bloco 'dados de saída' extrai o byte inferior do registro e o replica quatro vezes
tempos através do barramento de dados de 32 bits. A lógica de controle de memória externa pode então usar os dois bits inferiores do endereço
bussola para ativar o byte apropriado dentro do sistema de memória. Instruções de carregamento seguem um padrão semelhante
exceto que os dados da memória chegam apenas até o registrador 'dados de entrada' no segundo ciclo e um terceiro ciclo
é necessário transferir os dados de lá para o registro de destino.
Fig 4.6
Instruções de ramificação: As instruções de ramificação calculam o endereço de destino no primeiro ciclo, conforme mostrado na Figura 4.7.
na página 85. Um campo imediato de 24 bits é extraído da instrução e, em seguida, deslocado duas posições à esquerda para
dê um deslocamento alinhado a palavras que é adicionado ao PC. O resultado é emitido como um endereço de busca de instrução, e
Enquanto o pipeline de instrução é reabastecido, o endereço de retorno é copiado para o registrador de link (r14) se isso for necessário.
(isto é, se a instrução for um 'ramo com link'). O terceiro ciclo, que é necessário para completar o pipeline
reabastecimento, também é usado para fazer uma pequena correção no valor armazenado no registrador de link para que aponte
diretamente na instrução que segue o ramo. Isso é necessário porque r15 contém pc + 8 enquanto o
o endereço da próxima instrução é pc + 4 (veja 'comportamento do PC' na página 78). Outras instruções ARM operam em um
maneira semelhante àquelas descritas acima. Agora iremos olhar com mais detalhes como o caminho dos dados
realiza essas operações.
Fig 4.7
Comportamento do PC
Uma consequência do modelo de execução em pipeline utilizado no ARM é que o contador de programa,
que é visível para o usuário como r!5, deve ser executado antes da instrução atual. Se, como mencionado acima,
instruções buscam a próxima instrução, mas uma durante seu primeiro ciclo, isso sugere que o PC
deve apontar oito bytes (duas instruções) à frente da instrução atual. Isso é, de fato, o que
acontece, e o programador que tentar acessar o PC diretamente através do r!5 deve levar em consideração
conta da exposição do oleoduto aqui. No entanto, para a maioria dos fins normais, o montador
ou o compilador lida com todos os detalhes. Um comportamento ainda mais complexo é exposto se r!5 for usado depois.
do que o primeiro ciclo de uma instrução, uma vez que a instrução terá incrementado o PC
durante seu primeiro ciclo. Tal uso do PC nem sempre é benéfico, então a arquitetura ARM
a definição especifica o resultado como 'imprevisível' e deve ser evitada, especialmente uma vez que mais tarde
Os ARMs não têm o mesmo comportamento nesses casos.
Coprocessadores
A arquitetura ARM suporta 16 coprocessadores
Cada conjunto de instruções do coprocessador ocupa parte do conjunto de instruções ARM.
Existem três tipos de instrução de coprocessador
Processamento de dados do coprocessador
Transferências de registro de coprocessador (de/para ARM)
Transferências de memória do coprocessador (carregar e armazenar para/de memória)
Macross de montador podem ser usados para transformar mnemônicos de coprocessador personalizados em
mnemônicos genéricos compreendidos pelo processador.
Um coprocessador pode ser implementado
•em hardware
•em software (via a exceção de instrução indefinida)
•em ambos (casos comuns em hardware, o restante em software)
Registro do Coprocessador
Transferências
*Estas duas instruções movem dados entre registradores ARM e
registros de coprocessador
• MRC: Mover para Registrar do Coprocessador
MCR : Mover para Coprocessador a partir do Registro
Uma operação também pode ser realizada nos dados enquanto eles são transferidos
• Por exemplo, uma instrução de Conversão de Ponto Flutuante para Inteiro pode ser
implementado como uma transferência de registro para ARM que também converte os dados
do formato de ponto flutuante para o formato inteiro.
*Sintaxe
• <MRC|MCR>{<cond>} <cp_num>,<opc_1>,Rd,CRn,CRm,<opc_2>
Memória do Coprocessador
Transferências (1)
* Carregar da memória para os registradores do coprocessador
* Armazenar na memória a partir dos registros do coprocessador.
Memória do Coprocessador
Transferências (2)
* A sintaxe disso é semelhante à transferência de palavras entre ARM e memória:
• <LDC|STC>{<cond>}{<L>} <cp_num>,CRd,<endereço>
–Deslocamento relativo de PC gerado se possível, caso contrário causa um erro.
• <LDC|STC>{<cond>}{<L>} <cp_num>,CRd,<[Rn,offset]{!}>
Forma pré-indexada, com gravação opcional do registrador base
• <LDC|STC>{<cond>}{<L>} <cp_num>,CRd,<[Rn],offset>
–Forma pós-indexada
onde
• <L> quando presente faz com que uma transferência "longa" seja realizada (N=1) caso contrário
causa uma transferência "curta" a ser realizada (N=0).
–O efeito disto depende do coprocessador.
Um sistema ARM, como a maioria dos sistemas de computador, tem sua memória organizada como um conjunto linear de endereços lógicos.
O programa C espera ter acesso a uma área fixa da memória do programa (onde a imagem da aplicação reside)
e à memória para suportar duas áreas de dados que crescem dinamicamente e onde o compilador muitas vezes não consegue descobrir
um tamanho máximo. Essas áreas de dados dinâmicas são:
•A pilha.
Sempre que uma função (não trivial) é chamada, um novo quadro de ativação é criado em
a pilha contendo um registro de back trace, variáveis locais (não estáticas) e assim por diante.
Quando uma função retorna, seu espaço de pilha é automaticamente recuperado e será
reutilizado para a próxima chamada de função.
•A pilha.
O heap é uma área de memória usada para atender aos pedidos do programa (malloc ()) por
mais memória para novas estruturas de dados. Um programa que continua a solicitar
a memória ao longo de um longo período de tempo deve ter cuidado para liberar todas as seções que
não são mais necessários, caso contrário, a pilha crescerá até que a memória acabe.