Microarquitetura - Microarchitecture

Diagrama da microarquitetura Intel Core 2

Na engenharia da computação , a microarquitetura , também chamada de organização do computador e às vezes abreviada como µarch ou uarch , é a maneira como uma dada arquitetura de conjunto de instruções (ISA) é implementada em um processador específico . Um determinado ISA pode ser implementado com diferentes microarquitetura; as implementações podem variar devido a objetivos diferentes de um determinado design ou devido a mudanças na tecnologia.

A arquitetura do computador é a combinação da microarquitetura e da arquitetura do conjunto de instruções.

Relação com a arquitetura do conjunto de instruções

Uma microarquitetura organizada em torno de um único barramento

O ISA é praticamente o mesmo que o modelo de programação de um processador visto por um programador de linguagem assembly ou redator de compilador. O ISA inclui as instruções , modelo de execução , registros do processador , endereço e formatos de dados, entre outras coisas. A microarquitetura inclui as partes constituintes do processador e como elas se interconectam e interoperam para implementar o ISA.

A microarquitetura de uma máquina é geralmente representada como diagramas (mais ou menos detalhados) que descrevem as interconexões dos vários elementos da microarquitetura da máquina, que podem ser qualquer coisa, desde portas e registros simples a unidades lógicas aritméticas completas (ALUs) e até maiores elementos Esses diagramas geralmente separam o caminho de dados (onde os dados são colocados) e o caminho de controle (que pode ser dito para direcionar os dados).

A pessoa que projeta um sistema geralmente desenha a microarquitetura específica como uma espécie de diagrama de fluxo de dados . Como um diagrama de blocos , o diagrama da microarquitetura mostra os elementos da microarquitetura, como a unidade aritmética e lógica e o arquivo de registro como um único símbolo esquemático. Normalmente, o diagrama conecta esses elementos com setas, linhas grossas e linhas finas para distinguir entre barramentos de três estados (que requerem um buffer de três estados para cada dispositivo que aciona o barramento), barramentos unidirecionais (sempre impulsionados por uma única fonte, como como a forma como o barramento de endereço em computadores mais simples é sempre conduzido pelo registrador de endereço de memória ) e linhas de controle individuais. Computadores muito simples têm uma única organização de barramento de dados  - eles têm um único barramento de três estados . O diagrama de computadores mais complexos geralmente mostra vários barramentos de três estados, que ajudam a máquina a fazer mais operações simultaneamente.

Cada elemento da microarquitetura, por sua vez, é representado por um esquema que descreve as interconexões das portas lógicas usadas para implementá-lo. Cada porta lógica é, por sua vez, representada por um diagrama de circuito que descreve as conexões dos transistores usados ​​para implementá-la em alguma família lógica particular . Máquinas com microarquiteturas diferentes podem ter a mesma arquitetura de conjunto de instruções e, portanto, ser capazes de executar os mesmos programas. Novas microarquiteturas e / ou soluções de circuitos, junto com os avanços na fabricação de semicondutores, são o que permite que as novas gerações de processadores alcancem um desempenho superior usando o mesmo ISA.

Em princípio, uma única microarquitetura poderia executar vários ISAs diferentes com apenas pequenas alterações no microcódigo .

Aspects

Intel 80286 microarquitetura

O caminho de dados em pipeline é o design de caminho de dados mais comumente usado na microarquitetura hoje. Essa técnica é usada na maioria dos microprocessadores, microcontroladores e DSPs modernos . A arquitetura em pipeline permite que várias instruções se sobreponham na execução, como em uma linha de montagem. O pipeline inclui vários estágios diferentes que são fundamentais em projetos de microarquitetura. Alguns desses estágios incluem busca de instrução, decodificação de instrução, execução e gravação de volta. Algumas arquiteturas incluem outros estágios, como acesso à memória. O projeto de pipelines é uma das tarefas centrais da microarquitetura.

As unidades de execução também são essenciais para a microarquitetura. As unidades de execução incluem unidades lógicas aritméticas (ALU), unidades de ponto flutuante (FPU), unidades de carga / armazenamento, previsão de ramificação e SIMD . Essas unidades executam as operações ou cálculos do processador. A escolha do número de unidades de execução, sua latência e rendimento é uma tarefa central do projeto da microarquitetura. O tamanho, latência, taxa de transferência e conectividade das memórias dentro do sistema também são decisões de microarquitetura.

As decisões de design no nível do sistema, como incluir ou não periféricos , como controladores de memória , podem ser consideradas parte do processo de design da microarquitetura. Isso inclui decisões sobre o nível de desempenho e conectividade desses periféricos.

Ao contrário do projeto de arquitetura, em que o objetivo principal é atingir um nível de desempenho específico, o projeto de microarquitetura presta mais atenção a outras restrições. Como as decisões de projeto de microarquitetura afetam diretamente o que entra em um sistema, deve-se prestar atenção a questões como área / custo do chip, consumo de energia, complexidade lógica, facilidade de conectividade, capacidade de fabricação, facilidade de depuração e testabilidade.

Conceitos de microarquitetura

Ciclos de instrução

Para executar programas, todas as CPUs com um ou vários chips:

  1. Leia uma instrução e decodifique-a
  2. Encontre todos os dados associados necessários para processar a instrução
  3. Processe a instrução
  4. Escreva os resultados

O ciclo de instrução é repetido continuamente até que a energia seja desligada.

Microarquitetura multiciclo

Historicamente, os primeiros computadores eram designs multiciclos. Os menores e mais baratos computadores freqüentemente ainda usam essa técnica. As arquiteturas multiciclo geralmente usam o menor número total de elementos lógicos e quantidades razoáveis ​​de energia. Eles podem ser projetados para ter temporização determinística e alta confiabilidade. Em particular, eles não têm pipeline para parar ao obter desvios ou interrupções condicionais. No entanto, outras microarquiteturas geralmente executam mais instruções por unidade de tempo, usando a mesma família lógica. Ao discutir "desempenho aprimorado", uma melhoria geralmente é relativa a um projeto multiciclo.

Em um computador multiciclo, o computador executa as quatro etapas em sequência, ao longo de vários ciclos do relógio. Alguns projetos podem executar a sequência em dois ciclos de clock, completando estágios sucessivos em bordas de clock alternadas, possivelmente com operações mais longas ocorrendo fora do ciclo principal. Por exemplo, o estágio um na borda ascendente do primeiro ciclo, o estágio dois na borda descendente do primeiro ciclo, etc.

Na lógica de controle, a combinação do contador de ciclo, estado do ciclo (alto ou baixo) e os bits do registro de decodificação da instrução determinam exatamente o que cada parte do computador deve estar fazendo. Para projetar a lógica de controle, pode-se criar uma tabela de bits que descreve os sinais de controle para cada parte do computador em cada ciclo de cada instrução. Então, essa tabela lógica pode ser testada em uma simulação de software executando o código de teste. Se a tabela lógica for colocada em uma memória e usada para realmente operar um computador real, ela é chamada de microprograma . Em alguns projetos de computador, a tabela lógica é otimizada na forma de lógica combinatória feita a partir de portas lógicas, geralmente usando um programa de computador que otimiza a lógica. Os primeiros computadores usavam design lógico ad-hoc para controle até Maurice Wilkes inventar essa abordagem tabular e chamá-la de microprogramação.

Aumentando a velocidade de execução

Para complicar essa série de etapas de aparência simples, está o fato de que a hierarquia da memória, que inclui cache , memória principal e armazenamento não volátil como discos rígidos (onde residem as instruções do programa e os dados), sempre foi mais lenta do que o próprio processador. A etapa (2) geralmente apresenta um atraso longo (em termos de CPU) enquanto os dados chegam pelo barramento do computador . Uma quantidade considerável de pesquisa foi colocada em projetos que evitem esses atrasos tanto quanto possível. Ao longo dos anos, um objetivo central era executar mais instruções em paralelo, aumentando assim a velocidade de execução efetiva de um programa. Esses esforços introduziram estruturas lógicas e de circuito complicadas. Inicialmente, essas técnicas só podiam ser implementadas em mainframes ou supercomputadores caros devido à quantidade de circuitos necessários para essas técnicas. À medida que a fabricação de semicondutores progredia, mais e mais dessas técnicas podiam ser implementadas em um único chip semicondutor. Veja a lei de Moore .

Escolha do conjunto de instruções

Os conjuntos de instruções mudaram ao longo dos anos, de originalmente muito simples para às vezes muito complexos (em vários aspectos). Nos últimos anos, as arquiteturas load – store , tipos VLIW e EPIC estiveram na moda. As arquiteturas que lidam com paralelismo de dados incluem SIMD e vetores . Alguns rótulos usados ​​para denotar classes de arquiteturas de CPU não são particularmente descritivos, especialmente o rótulo CISC; muitos projetos anteriores denotados retroativamente como " CISC " são, na verdade, significativamente mais simples do que os processadores RISC modernos (em vários aspectos).

No entanto, a escolha da arquitetura do conjunto de instruções pode afetar muito a complexidade da implementação de dispositivos de alto desempenho. A estratégia proeminente, usada para desenvolver os primeiros processadores RISC, era simplificar as instruções para um mínimo de complexidade semântica individual combinada com alta regularidade e simplicidade de codificação. Essas instruções uniformes foram facilmente buscadas, decodificadas e executadas de forma pipeline e uma estratégia simples para reduzir o número de níveis lógicos a fim de atingir altas frequências de operação; as memórias de cache de instrução compensaram a frequência operacional mais alta e a densidade de código inerentemente baixa , enquanto grandes conjuntos de registros foram usados ​​para fatorar o máximo possível dos acessos (lentos) à memória.

Pipelining de instrução

Uma das primeiras e mais poderosas técnicas para melhorar o desempenho é o uso de pipelining de instruções . Os primeiros projetos de processador realizariam todas as etapas acima para uma instrução antes de passar para a próxima. Grandes partes do circuito foram deixadas ociosas em qualquer etapa; por exemplo, o circuito de decodificação de instruções ficaria ocioso durante a execução e assim por diante.

O pipelining melhora o desempenho, permitindo que várias instruções percorram o processador ao mesmo tempo. No mesmo exemplo básico, o processador começaria a decodificar (etapa 1) uma nova instrução enquanto a última estava esperando pelos resultados. Isso permitiria que até quatro instruções estivessem "em vôo" ao mesmo tempo, fazendo com que o processador parecesse quatro vezes mais rápido. Embora qualquer instrução leve o mesmo tempo para ser concluída (ainda há quatro etapas), a CPU como um todo "retira" as instruções muito mais rápido.

O RISC torna os pipelines menores e muito mais fáceis de construir, separando claramente cada estágio do processo de instrução e fazendo com que demorem a mesma quantidade de tempo - um ciclo. O processador como um todo opera em linha de montagem , com as instruções vindo de um lado e os resultados saindo do outro. Devido à complexidade reduzida do pipeline RISC clássico , o núcleo com pipeline e um cache de instruções podem ser colocados no mesmo tamanho de dado que, de outra forma, caberia apenas no núcleo em um projeto CISC. Esse foi o verdadeiro motivo do RISC ser mais rápido. Os primeiros designs, como SPARC e MIPS, geralmente funcionavam 10 vezes mais rápido que as soluções CISC da Intel e da Motorola com a mesma velocidade de clock e preço.

Pipelines não são de forma alguma limitados a projetos RISC. Em 1986, a implementação VAX topo de linha ( VAX 8800 ) era um projeto com muitas tubulações, ligeiramente anterior aos primeiros projetos comerciais MIPS e SPARC. A maioria das CPUs modernas (até mesmo CPUs integradas) agora são pipeline, e CPUs microcodificadas sem pipelining são vistas apenas na maioria dos processadores incorporados com restrição de área. Grandes máquinas CISC, do VAX 8800 ao moderno Pentium 4 e Athlon, são implementadas com microcódigo e pipelines. Aprimoramentos em pipelining e cache são os dois principais avanços da microarquitetura que permitiram que o desempenho do processador acompanhasse a tecnologia de circuito em que se baseiam.

Cache

Não demorou muito para que as melhorias na fabricação de chips permitissem que ainda mais circuitos fossem colocados na matriz, e os projetistas começaram a procurar maneiras de usá-los. Uma das mais comuns era adicionar uma quantidade cada vez maior de memória cache na matriz. Cache é uma memória muito rápida e cara. Ele pode ser acessado em alguns ciclos, ao contrário de muitos ciclos necessários para "falar" com a memória principal. A CPU inclui um controlador de cache que automatiza a leitura e gravação do cache. Se os dados já estiverem no cache, eles serão acessados ​​de lá - com considerável economia de tempo, ao passo que, se não estiverem, o processador estará "paralisado" enquanto o controlador do cache os lê.

Os projetos RISC começaram a adicionar cache em meados da década de 1980, geralmente com apenas 4 KB no total. Esse número cresceu com o tempo, e CPUs típicas agora têm pelo menos 512 KB, enquanto CPUs mais potentes vêm com 1 ou 2 ou mesmo 4, 6, 8 ou 12 MB, organizados em vários níveis de uma hierarquia de memória . De modo geral, mais cache significa mais desempenho, devido à redução do travamento.

Caches e pipelines eram uma combinação perfeita um para o outro. Anteriormente, não fazia muito sentido construir um pipeline que pudesse ser executado mais rápido do que a latência de acesso da memória fora do chip. Em vez disso, usar a memória cache on-chip significa que um pipeline pode ser executado na velocidade da latência de acesso do cache, um período de tempo muito menor. Isso permitiu que as frequências de operação dos processadores aumentassem a uma taxa muito mais rápida do que a da memória fora do chip.

Previsão de filial

Uma barreira para obter maior desempenho por meio do paralelismo de nível de instrução decorre de paralisações e liberações de pipeline devido a ramificações. Normalmente, se um desvio condicional será obtido, não se sabe até o final do pipeline, pois os desvios condicionais dependem dos resultados provenientes de um registrador. Desde o momento em que o decodificador de instrução do processador descobriu que encontrou uma instrução de desvio condicional até o momento em que o valor do registro decisivo pode ser lido, o pipeline precisa ser paralisado por vários ciclos, ou se não for e o desvio estiver tomadas, o pipeline precisa ser liberado. À medida que a velocidade do clock aumenta, a profundidade do pipeline também aumenta e alguns processadores modernos podem ter 20 estágios ou mais. Em média, cada quinta instrução executada é um desvio, portanto, sem qualquer intervenção, é uma grande quantidade de paralisação.

Técnicas como previsão de ramificação e execução especulativa são usadas para diminuir essas penalidades de ramificação. A previsão de ramificação é onde o hardware faz suposições informadas sobre se uma ramificação específica será tomada. Na realidade, um lado ou outro do ramal será chamado com muito mais frequência do que o outro. Os projetos modernos têm sistemas de previsão estatística bastante complexos, que observam os resultados das ramificações anteriores para prever o futuro com maior precisão. A estimativa permite que o hardware busque previamente as instruções sem esperar pela leitura do registro. A execução especulativa é um aprimoramento adicional no qual o código ao longo do caminho previsto não é apenas pré-buscado, mas também executado antes que se saiba se a ramificação deve ser tomada ou não. Isso pode resultar em melhor desempenho quando a estimativa for boa, com o risco de uma grande penalidade quando a estimativa for ruim, pois as instruções precisam ser desfeitas.

Superescalar

Mesmo com toda a complexidade adicional e as portas necessárias para dar suporte aos conceitos descritos acima, as melhorias na fabricação de semicondutores logo permitiram que ainda mais portas lógicas fossem usadas.

No esboço acima, o processador processa partes de uma única instrução por vez. Os programas de computador poderiam ser executados mais rapidamente se várias instruções fossem processadas simultaneamente. Isso é o que os processadores superescalares conseguem, replicando unidades funcionais como ALUs. A replicação de unidades funcionais só foi possível quando a área da matriz de um processador de edição única não ultrapassou mais os limites do que poderia ser fabricado de forma confiável. No final da década de 1980, os designs superescalares começaram a entrar no mercado.

Em projetos modernos, é comum encontrar duas unidades de carga, um armazenamento (muitas instruções não têm resultados para armazenar), duas ou mais unidades matemáticas inteiras, duas ou mais unidades de ponto flutuante e, frequentemente, uma unidade SIMD de algum tipo. A lógica de emissão de instruções cresce em complexidade ao ler uma lista enorme de instruções da memória e transferi-las para as diferentes unidades de execução que estão ociosas naquele ponto. Os resultados são coletados e reordenados no final.

Execução fora de ordem

A adição de caches reduz a frequência ou duração das paralisações devido à espera dos dados a serem buscados na hierarquia de memória, mas não elimina totalmente essas paralisações. Em projetos anteriores, uma falha de cache forçaria o controlador de cache a paralisar o processador e esperar. É claro que pode haver alguma outra instrução no programa cujos dados estejam disponíveis no cache nesse ponto. A execução fora de ordem permite que a instrução pronta seja processada enquanto uma instrução mais antiga espera no cache e, em seguida, reordena os resultados para fazer parecer que tudo aconteceu na ordem programada. Essa técnica também é usada para evitar outras paralisações de dependência de operando, como uma instrução aguardando um resultado de uma operação de ponto flutuante de longa latência ou outras operações de múltiplos ciclos.

Registrar renomeando

A renomeação de registro refere-se a uma técnica usada para evitar a execução serializada desnecessária de instruções de programa devido à reutilização dos mesmos registros por essas instruções. Suponha que temos dois grupos de instruções que usarão o mesmo registrador . Um conjunto de instruções é executado primeiro para deixar o registro para o outro conjunto, mas se o outro conjunto for atribuído a um registro semelhante diferente, ambos os conjuntos de instruções podem ser executados em paralelo (ou) em série.

Multiprocessamento e multithreading

Os arquitetos de computador ficaram bloqueados pela crescente incompatibilidade nas frequências de operação da CPU e nos tempos de acesso da DRAM . Nenhuma das técnicas que exploravam o paralelismo de nível de instrução (ILP) dentro de um programa poderia compensar as longas paralisações que ocorriam quando os dados tinham que ser buscados na memória principal. Além disso, as grandes contagens de transistores e as altas frequências de operação necessárias para as técnicas de ILP mais avançadas exigiam níveis de dissipação de energia que não podiam mais ser resfriados de forma barata. Por essas razões, as novas gerações de computadores começaram a explorar níveis mais altos de paralelismo que existem fora de um único programa ou thread de programa .

Essa tendência às vezes é conhecida como computação de taxa de transferência . Essa ideia se originou no mercado de mainframe, onde o processamento de transações online enfatizava não apenas a velocidade de execução de uma transação, mas a capacidade de lidar com um grande número de transações. Com os aplicativos baseados em transações, como roteamento de rede e serviço de web-site, que aumentaram muito na última década, a indústria de computadores voltou a enfatizar os problemas de capacidade e taxa de transferência.

Uma técnica de como esse paralelismo é alcançado é por meio de sistemas de multiprocessamento , sistemas de computador com múltiplas CPUs. Antes reservados para mainframes e supercomputadores de alta tecnologia , os servidores multiprocessadores de pequena escala (2–8) se tornaram comuns para o mercado de pequenas empresas. Para grandes corporações, multiprocessadores de grande escala (16–256) são comuns. Até mesmo computadores pessoais com múltiplas CPUs surgiram desde a década de 1990.

Com novas reduções no tamanho do transistor disponibilizadas com os avanços da tecnologia de semicondutores, surgiram CPUs multi-core onde múltiplas CPUs são implementadas no mesmo chip de silício. Inicialmente usado em chips voltados para mercados embarcados, onde CPUs mais simples e menores permitiriam múltiplas instanciações para caber em um único pedaço de silício. Em 2005, a tecnologia de semicondutores permitiu que chips CMP de CPU dual high-end para desktop fossem fabricados em grande volume. Alguns designs, como o UltraSPARC T1 da Sun Microsystems , foram revertidos para designs mais simples (escalares, em ordem) para caber mais processadores em uma peça de silício.

Outra técnica que se tornou mais popular recentemente é o multithreading . No multithreading, quando o processador tem que buscar dados da memória lenta do sistema, em vez de esperar que os dados cheguem, o processador muda para outro programa ou thread de programa que está pronto para ser executado. Embora isso não acelere um programa / thread específico, aumenta a taxa de transferência geral do sistema, reduzindo o tempo em que a CPU fica ociosa.

Conceitualmente, o multithreading é equivalente a uma troca de contexto no nível do sistema operacional. A diferença é que uma CPU multithread pode fazer uma troca de thread em um ciclo da CPU, em vez das centenas ou milhares de ciclos da CPU que uma troca de contexto normalmente requer. Isso é obtido replicando o hardware de estado (como o arquivo de registro e o contador do programa ) para cada thread ativa.

Um outro aprimoramento é o multithreading simultâneo . Esta técnica permite que CPUs superescalares executem instruções de diferentes programas / threads simultaneamente no mesmo ciclo.

Veja também

Referências

Leitura adicional