Este trabalho apresenta as principais características do processador AMD-K6. Um estudo das técnicas utilizadas por este processador, bem como seu poder de processamento através de técnicas antes só vistas em processadores RISC.
This work describes the AMD-K6?s main features. Provide one study of the used techniques in this processor, and its power processing by features before found in RISC processors only.
A técnica de pipeline consiste em dividir a execução
de tarefas em estágios, de forma análoga à construção
de automóveis em série. Teríamos então, várias
instruções sendo executadas simultaneamente, mas somente
uma será concluída por vez [KIT96].
A hierarquia de memória foi desenvolvida para tentar aproximar
a velocidade alta dos processadores a da memória, que ainda é
muito lenta. Uma vez que o processador busca as instruções
em memória e, sendo esta lenta, temos que a memória não
consegue acompanhar o ritmo do processador, ficando este, muitas vezes
ocioso. Resolve-se este problema colocando memórias mais rápidas
próximas ao processador (denominadas cache) e provendo mecanismo
de busca e armazenamento das instruções [KIT96, FER92].
Este recurso, no entanto, trouxe outros problemas, como por exemplo, os desvios. Não adianta nada trazer para a cache um conjunto de 20 instruções se a primeira delas é um desvio. As outras 19 não serão executadas após a primeira. Para resolver este problema desenvolveu-se mecanismos de execução especulativa, que tenta descobrir estes desvios e tentar trazer para a cache o fluxo de instruções corretos [FER92].
Com o advento de processadores Super Escalares, ou seja, capazes de executar mais de uma instrução simultaneamente, possibilitou-se explorar o paralelismo a nível de instruções. Outros problemas precisavam ser resolvidos, como as dependências de dados. Mesmo que duas instruções possam ser executadas simultaneamente (porque o hardware permite) elas não poderão ser se uma depende da outra, ou seja, o resultado da primeira será usado na segunda. Técnicas de execução fora de ordem e renomeação de registradores foram desenvolvidas para resolver estes e outros problemas de dependência de dados [FER92].
Já aproveitando muitas dessas técnicas e ainda mantendo um custo de produção baixíssimo, o AMD-K6 aparece como uma boa opção de processador para equipar computadores pessoais. Neste texto será apresentado uma visão deste processador, começando por suas principais características. Uma análise mais concreta será feita de seus decodificadores internos, de suas unidades funcionais, bem como de sua unidade Central de Escalonamento de Instruções. No final, um rápido comentário sobre seu desempenho e algumas conclusões será apresentado.
O AMD-K6 é, antes de tudo, um processador Super Escalar compatível com o conjunto de instruções x86 e com suporte a instruções Multimídia, denominada MMX. No entanto sua arquitetura interna é construída em cima de instruções RISC86. Isso é possível porque ele possui decodificadores que geram instruções RISC a partir das x86. Possui 7 unidades funcionais de execução divididas em estágios de pipeline. Sua cache interna é de 64Kb possuindo também mecanismos de execução especulativa e técnicas de resolução de dependência de dados e de controle [FER92]. Para melhorar o grau de aproveitamento de suas unidades funcionais, possui também mecanismos de execução de instruções fora de ordem. Com esses recursos, o AMD é capaz de executar até seis instruções RISC por clock.
Possui 48 registradores, sendo que 24 deles são para uso geral e os outros 24 exclusivos para serem usados na renomeação (usado para resolver alguns casos de dependência de dados). Dos 24 de uso geral, 8 são os mesmos encontrados nas arquiteturas x86 (EAX, EBX, ECX, EDX, EBP, ESP, ESI e EDI).

Conforme apresentado na figura 2.1, a execução de uma instrução começa pela sua busca na memória principal pela unidade predecode. Esta calcula o tamanho da instrução corrente armazenando-a na cache de instruções. As instruções ficam então disponíveis ao decodificador, que irá transformá-las em instruções RISC, disponibilizando-as ao Escalonador Central. O Escalonador, então, envia as instruções, agora RISC, da maneira mais eficiente possível para as respectivas Unidades de Execução. Todo este percurso é feito sem nenhum custo extra de tempo.
Um dos maiores problemas das instruções x86 é quanto ao seu tamanho. Estas instruções não tem um tamanho fixo, podendo variar de 1 até 15 bytes, enquanto que as RISC possuem um tamanho fixo. O AMD-K6 considera três tipos de instruções x86: curtas, longas e vetoriais. As curtas (short) são aquelas que não ultrapassam sete bytes de tamanho; as longas (long) são as maiores que sete bytes e menores ou iguais a onze; instruções maiores que 11 bytes são denominadas vetoriais (vector).
A arquitetura do AMD-K6, isto é, aquilo que é visível
aos softwares que serão executados em máquinas que
o utilizarem, é baseada no conjunto de instruções
x86. Porém, sua micro-arquitetura, isto é, como realmente
ele processa as instruções, é baseada no conjunto
de instruções RISC 86. É necessário, então,
que seja feita uma decodificação de cada instrução
a ser executada para seu(s) equivalente(s) em RISC. Cada instrução
x86 curta ou longa pode resultar em até quatro instruções
RISC (ver exemplo na tabela 1).

Na figura 3.1 pode ser visto um diagrama simples do funcionamento dos decodificadores. O buffer de instruções (cache nível 1) possui bits de predecodificação que possibilitam ao decodificador a correta classificação das instruções.

Mesmo havendo quatro unidades de decodificação (duas short, uma long e outra vector) só é possível decodificar um tipo de instrução por clock, o que significa que em apenas um ciclo de clock o K6 é capaz de decodificar até duas instruções short ou uma long (as vector precisam ser enviadas para outra unidade). As instruções short geram até duas instruções RISC enquanto que as long até quatro - programas x86 típicos são compostos de 80% de instruções short. Isso possibilita ao sistema de decodificação gerar até quatro instruções RISC por ciclo de clock. Por isso que a saída do decodificador é composta de quatro instruções. Temos também um pequeno inconveniente nesse ponto: a saída deverá ser sempre de quatro instruções. Se por acaso a instrução for do tipo long, mas gerar apenas três instruções RISC, o decodificador gera uma quarta instrução sem efeito algum (NOP) para enviar as quatro instruções necessárias. Temos, então, a possibilidade remota de termos apenas uma instrução válida saindo do decodificador, e as outras três sem efeito algum (NOP).
Na Unidade de decodificação é tomada a primeira providência para tentar amenizar o impacto de desvios do fluxo de instruções. Estes desvios podem ser de dois tipos: desvios condicionais ou incondicionais [FER92]. Estatísticas revelam que um programa típico possui cerca de 10% de desvios incondicionais e de 10 a 20% de desvios condicionais [AMD97]. Os desvios incondicionais mais freqüentes são as chamadas CALL e seu respectivo RET, utilizados para desviar o fluxo para uma subrotina. Neste caso, o AMD provê uma pilha de endereço para retorno, empilhando o endereço da próxima instrução, quando encontra um CALL e desempilhando-o ao encontrar o RET respectivo.
Já os desvios condicionais são mais difíceis de serem previstos. Isso porque sua resolução depende de resultados obtidos por outras instruções. O caso mais comum de desvios condicionais são os usados em instruções de alto nível do tipo "If-Then-Else", "While-DO" ou "For-do", ou seja, dentro de loops. Quando o decodificador encontra um instrução de desvio, ele consulta uma tabela de predição de desvios para decidir se este desvio deve ser considerado como tomado ou não. Este mecanismo atualmente consegue índices de até 95% de acertos enquanto que o Pentium II, por exemplo, atinge 90%. Este índice trata-se do maior que já se conseguiu em processadores.
Após cada decodificação, as instruções, agora RISC, são enviadas à unidade de Escalonamento.
Na figura 4.1 podemos ver o esquema do Escalonador. Ele trabalha com
uma janela de instruções [FER92] de 24 instruções
RISC, o que eqüivale a 12 instruções x86 curtas (short)
ou a 6 longas (long ). Tipicamente o buffer corresponde a
12 instruções x86 (porque 80% de um código é
composto por instruções short).

Na figura 4.2 podemos ver a organização do buffer de instruções usado pelo escalonador. Verifica-se que o buffer recebe sempre seqüências de quatro instruções RISC por vez, mesmo que uma ou mais delas tenham de ser preenchidas por instruções NOP - que não executam nada.

Como mencionado anteriormente, é o Escalonador Central o responsável para despachar as instruções às suas respectivas Unidades funcionais. Estas unidades são de sete tipos e cada uma delas é, ainda, dividida em estágios de pipeline.
Suas sete unidades funcionais são: store, load, branch, Integer X, Integer Y, Integer Multimidea (MMX) e Floating Point.
As duas primeiras são responsáveis por escrita e leitura de dados na memória e são divididas em dois estágios de pipeline. A unidade Integer X é responsável pela execução das instruções aritméticas básicas, como soma e multiplicação e a única diferença existente entre ela e a unidade Integer Y é que esta última é capaz de trabalhar com dados de 16 e 32 bits. A unidade Integer Multimidea é usada para executar instruções do tipo MMX. Interessante que esta unidade compartilha o controle de pipeline com a unidade Integer X. A unidade Floating Point resolve aritméticas envolvendo ponto flutuante e, por último, a unidade branch foi especialmente desenvolvida para resolver (definitivamente, ou seja, não apenas prever) desvios condicionais. Na figura 2.1 pode ser visto a disposição destas unidades no diagrama em blocos do K6.
O K6 possui 64kb de cache, sendo esta dividida entre cache de instruções e de dados É designado 32kb para armazenar instruções x86 e outros 32kb para dados. Internamente são organizadas em setores, sendo cada setor composto de 64 bytes e cada um desses setores, novamente divididos em duas linhas de 32 bytes cada. A cache utiliza o protocolo MESI de coerência [STA96].
A última informação da cache (tabela 2)
consiste em um bit MESI, que define se o dado contido na linha é
Valido ou Inválido. O protocolo MESI define quatro tipos de estados:
Alterado, Exclusivo, Compartilhado e Invalido (Modified,
Exclusive, Shared e Invalid), mas no caso de
instruções pode ocorrer apenas os estados Exclusive
e Invalid, por isso apenas 1 bit.
Cada entrada dessa cache é associada a uma entrada de
uma tabela TBL [AMD98], usada para converter endereços lineares
em físicos.
Já na cache de dados, não há a informação
predecode, mas necessite de 2 bits de MESI. Isso porque uma
linha pode assumir todos os quatro estados previstos no protocolo MESI
(tabela 3).
Estes estados podem ser:
- Modified - O dado presente na cache foi alterado
e esta diferente da memória;
- Exclusive - significa que este dado está coerente
e não foi alterado.
- Shared - O dado é compartilhado por outras caches.
- Invalid - O dado e invalido (ou instruçao).
O AMD-K6 é o principal concorrente do Pentium II. De fato possui muitas características importantes que merecem certa atenção ao decidir pela compra [TOR98]. Sua principal vantagem é a relação custo-benefício, pois o Pentium II ainda é muito caro para a maioria dos usuários. Recentemente, porém, a Intel lançou uma versão econômica do Pentium II, denominada Celeron, com preços compatíveis ao AMD-K6. No gráfico da figura 6.1 podemos ver uma comparação de performance do AMD-K6 com o Celeron [AMD97]. Observe que mesmo a versão de 200 Mhz da AMD tem um índice melhor que o Celeron de 300Mhz.

Já no gráfico da figura 6.2 vemos uma comparação
de desempenho do processador AMD-K6-2 (inclui recursos 3D) com o Pentium
II [AMD97].

Muitas das técnicas de aumento de performance já incorporam nossos processadores e não são mais exclusividade dos grandes computadores RISC. Entretanto, a arquitetura destes processadores de uso comercial ainda é baseada no conjunto de instruções x86 o que dificulta muito o uso destas técnicas. O principal problema decorre do fato do tamanho das instruções: enquanto as RISC?s possuem tamanho fixo, as x86 podem variar de um byte a dezenas. A solução encontrada pelos fabricantes foi introduzir decodificadores que traduzem cada instrução x86 para as respectivas instruções RISC.
Dentre estes processadores o K6 é, sem dúvida, um forte representante. Principal concorrente do Pentium PRO e Pentium II, possui características interessantes que podem ser fatores decisivos na escolha. Talvez a principal vantagem seja a economia, não só pelo preço do chip em si, mas também pelo fato de não necessitar, o K6, de placa mãe exclusiva para ele. Enquanto o Pentium PRO e o Pentium II requerem placas exclusivas, o K6 pode ser instalado nas placas típicas desenvolvidas para processadores Pentium, desde que possuem configuração de clock adequada [TOR98].
Desde sua implementação, o K6 ficou um pouco desacreditado. Suspeitava-se que, mesmo tecnicamente melhor e mais barato, não haveria condições de ser produzido em larga escala, o que afastou alguns fabricantes de computadores que preferiram criar acordos de "fidelidade" com a Intel e passar a vender micros "Intel Inside". Recentemente, no entanto, alguns fabricantes firmaram acordo com a AMD e passaram a fornecer ao mercado micros equipados com o K6. Dentre os principais fabricantes estão a IBM e COMPAQ. Esta competição já obrigou a Intel a lançar uma versão Light do seu processador Pentium II - chamado de Celeron - e a investir fortemente em publicidade, procurando manter a marca Intel como sinônimo de qualidade e confiança, mas acredito que deverá fazer muito mais do que isso se quiser manter-se na liderança mundial de processadores.
[AMD97] AMD. Site oficial da AMD. http://www.amd.com.
[FER92] FERNANDES, Edil S. T.; SANTOS, Anna Dolesjsi. Arquiteturas Super Escalares: Detecção e Esploração do Paralelismo de Baixo nível. In: VIII Escola de Computação, Gramado-RS. Instituto de Informárica. UFRGS.Porto Alegre, 1992.
[KIT96] KITAJIMA, João Paulo. Arquiteturas de Computadores: Tendências até o final do século. In: IV Escola Regional de Informática, Canoas-RS: Universidade Luterana do Brasil. Anais. 1996. Pg 92-109.
[STA96] STALLINGS, Willian. Computer Organization and Architecture:
Design for Performance. 4 ed. Printece Hall, New Jersey. 1996.
[TOR98] TORRES, Gabriel. K6 - Características básicas.
In Site de hardware. http://www.gabrieltorres.com/k6.html.