Extraímos constantes do cristal do coprocessador matemático 8087

Em 1980, a Intel lançou o chip 8087 para acelerar o processamento de números de ponto flutuante nos processadores 8086, e foi usado no IBM PC original. Como os primeiros microprocessadores trabalhavam apenas com números inteiros, a aritmética com números de ponto flutuante era lenta e com funções transcendentais como arctangentes ou logaritmos, as coisas eram ainda piores. A adição do chip do coprocessador 8087 ao sistema foi capaz de acelerar as operações com números de ponto flutuante até cem vezes.

Abri o chip 8087 e tirei algumas fotos sob um microscópio. A foto abaixo mostra um pequeno cristal de chip de silício. De lado, pequenos condutores o conectam a 40 pernas externas. A marcação dos principais blocos funcionais na imagem foi feita por mim graças à engenharia reversa. Se você estudar cuidadosamente o chip, poderá extrair várias constantes da ROM - números como π usados ​​pelo chip nos cálculos. Chip Intel 8087 para operação de ponto flutuante com blocos de funções principais marcados. A ROM com constantes está marcada em verde. Clicável.




Na metade superior do chip existem circuitos de controle. Podem ser necessários até 1000 passos para executar uma instrução de ponto flutuante; O 8087 usou o microcódigo para descrever essas etapas. Na foto do cristal, você pode ver o "mecanismo" que lançou o programa a partir do microcódigo; de fato, é uma CPU simples. Ao lado, há uma grande ROM, onde o microcódigo é armazenado.

No fundo do chip, existem circuitos que processam números de ponto flutuante. Um número de ponto flutuante consiste em uma parte fracionária (também conhecida como parte significativa de um número ou mantissa), um expoente e um bit de sinal. Em notação decimal, o número 6,02 × 10 236.02 será a mantissa e 23 será o expoente. Circuitos separados de chips processam simultaneamente a mantissa e o expoente. O esquema de processamento da mantissa suporta valores de 67 bits - uma mantissa de 64 bits e três bits adicionais para precisão. Da esquerda para a direita, os esquemas de operação da mantissa consistem em ROMs com constantes, um registro de turno, um somador / subtractor e uma pilha de registradores. O tópico deste artigo é ROM com constantes; na foto, é destacado em verde.

O 8087 trabalhou como coprocessador para o processador 8086. Quando o processador 8086 encontrou uma instrução especial relacionada a números de ponto flutuante, ignorou-o e deu ao 8087 a oportunidade de executá-lo em paralelo. A interação de 8086 e 8087 foi organizada de uma maneira bastante astuta. Para simplificar, o 8087 examina o fluxo de instruções 8086 e executa as instruções relacionadas ao 8087. A dificuldade é que o 8086 possui um buffer de instruções de pré-busca, portanto, a instrução que o 8086 está recebendo no momento não corresponde à instrução ele executa. Portanto, o 8087 duplicou o buffer da amostra direta das instruções 8086 (ou um buffer menor da amostra direta das instruções 8088) para saber com o que o 8086 está ocupado ( mais detalhes são descritos aqui) Outra dificuldade está associada aos modos complexos de endereçamento 8086 que usam registradores dentro do 8086. O 8087 não pode executar esses modos de endereçamento porque não tem acesso aos registradores 8086. Em vez disso, quando o 8086 vê a instrução 8087, solicita dados de um local especificado na memória e ignora o resultado. Enquanto isso, 8087 pega o endereço do ônibus, caso ele precise. Pode parecer que uma armadilha se formará nesse local se o 8087 não estiver instalado - mas isso não acontecerá. Em um sistema sem 8087, o vinculador reescreve as instruções do 8087, substituindo-as por chamadas de sub-rotina da biblioteca de emulação.

Não contarei em detalhes o funcionamento interno do 8087, mas, em geral, as operações de ponto flutuante são implementadas através de adições, subtrações e trocas de números inteiros. Para adicionar ou subtrair dois números de ponto flutuante, o 8087 altera os números até que as vírgulas binárias sejam alinhadas (como pontos decimais, apenas no sistema binário) e, em seguida, adiciona ou subtrai a mantissa. A multiplicação, divisão e obtenção da raiz quadrada são realizadas por turnos sucessivos e adições / subtrações. As funções transcendentais (tangente, arco tangente, logaritmo, grau) usam algoritmos CORDIC , que usam mudanças e adições de constantes especiais para aumentar a eficiência dos cálculos.

Implementação de ROM


Este artigo descreve a ROM onde as constantes estão armazenadas. Não o confunda com uma ROM maior de quatro níveis em que o microcódigo está armazenado - este último é implementado usando uma tecnologia incomum que armazena dois bits por transistor. Isso é feito usando transistores de três tamanhos diferentes ou a ausência de um transistor em cada posição. Essas quatro opções indicam dois bits. Essa tecnologia sofisticada era necessária para ajustar uma ROM grande em um chip 8087.

A ROM para constantes usa tecnologias padrão para armazenar constantes (como π, ln (2) e √2) exigidas pelo 8087 para cálculos. A foto abaixo mostra parte da ROM com constantes. Para ver o próprio cristal, uma camada de metal foi removida. Áreas rosadas são silício com impurezas, o que confere propriedades diferentes, e linhas avermelhadas e esverdeadas são polissilício , um tipo especial de fiação de silício que fica no topo. Preste atenção à estrutura da ROM, semelhante à estrutura correta. A ROM consiste em duas colunas de transistores que armazenam bits. Para explicar o esquema de sua operação, começarei com o esquema do transistor.


Parte da ROM com constantes, com uma camada de metal removida. Três colunas de transistores maiores são usadas para selecionar linhas.

Os circuitos integrados de alta densidade (ICs) na década de 1970 eram geralmente fabricados com transistores N-MOS. (Os computadores modernos são feitos de CMOS, consistindo em N-MOS e P-MOS com polaridade reversa). O diagrama abaixo mostra a estrutura de um transistor N-MOS. O IC é montado a partir de um substrato de silício no qual os transistores são criados. As impurezas são adicionadas aos locais de silício, criando regiões "difusas" com as propriedades elétricas desejadas. Um transistor pode ser pensado como um interruptor que permite que a corrente flua entre duas seções de difusão, chamadas fonte e dreno. O transistor é controlado por uma porta feita de um tipo especial de silício - polissilício. A aplicação de tensão no portão permite que a corrente flua entre a fonte e o dreno; caso contrário, nenhum fluxo de corrente. O 8087 é bastante complexo, com cerca de 40.000 transistores.

Fontes diferentes fornecem um número diferente de transistores para o 8087: a Intel diz cerca de 40.000, a Wikipedia diz cerca de 45.000. Talvez a coisa toda esteja em diferentes métodos de cálculo. Como o número de transistores em uma ROM, PLA ou outra estrutura semelhante depende dos dados armazenados, as fontes geralmente indicam o número de transistores "potenciais" em vez dos reais. Você também pode considerar ou não considerar os transistores pull-up ou os drivers de alta corrente como um transistor ou vários paralelos.


Estrutura MOS implementada em IP

Ao aumentar o zoom, transistores de ROM individuais podem ser considerados. Áreas rosadas são silício com impurezas que formam fontes e drenos. As linhas de barramento de seleção vertical Polysilicon formam portas de transistor. As áreas marcadas de silício são conectadas ao solo e puxam para baixo um lado de cada transistor. Os círculos são VIA , uma via intercalar entre os pneus de silicone e metal acima. Para fotos, os pneus de metal são removidos; a localização de um deles é mostrada pela linha laranja.


Parte da ROM com constantes. Cada barramento de amostragem seleciona uma constante específica. Os transistores são mostrados em amarelo. X marca o transistor ausente correspondente ao bit 0. A linha laranja indica a localização do condutor de metal.

Uma característica importante da ROM é a ausência de alguns transistores - não há primeiro na linha superior e dois marcados com X na linha inferior. Os bits são programados na ROM alterando o circuito para adicionar impurezas ao silício, o que cria transistores ou deixa áreas isolantes. Cada transistor disponível ou ausente representa um bit. Quando o barramento de amostragem é ativado, todos os transistores desta coluna são abertos, puxando para baixo os barramentos de saída correspondentes. Mas se não houver transistor na posição selecionada, a saída correspondente permanecerá alta. Assim, o valor é lido da ROM ativando o barramento de amostra, que emite esse valor da ROM para os barramentos de saída.

Conteúdo da ROM


A ROM com constantes consiste em 143 linhas e 21 colunas. Ele contém 134 linhas de 21 bits, exceto uma peça de 6 x 6 transistores no canto superior esquerdo. Portanto, o tamanho físico da ROM com constantes é 2946 bits.



Com base no esquema da ROM, a seção ausente significa que as 12 primeiras constantes são de 64 bits, não de 67 bits. Essas são constantes não relacionadas ao CORDIC e, aparentemente, não requerem precisão adicional.

Sob o microscópio, o padrão de bits da ROM é visível, para que possa ser removido a partir daí. No entanto, não é de todo óbvio como interpretar esses bits posteriormente. A primeira pergunta é se a presença de um transistor indica 0 ou 1 (posteriormente, a presença de um transistor é 1). O segundo problema é como converter a grade de 134 × 21 bits em valores.

A codificação de bits pode ser definida de duas maneiras. O primeiro é rastrear o circuito lendo os dados da ROM e ver como eles são usados. O segundo é procurar padrões nos dados brutos e tentar compreendê-los. Como o 8087 é muito complexo, eu queria evitar a engenharia reversa total ao estudar constantes, então usei a segunda abordagem.

O caminho de dados do chip consiste em 67 linhas horizontais, portanto ficou claro que as 134 linhas na ROM correspondem a dois conjuntos de constantes de 67 bits. Extraí um conjunto de constantes das séries ímpares e outro das séries pares, porém os valores obtidos não fazem sentido. Pensando um pouco mais, percebi que as linhas não se alternavam, mas andei repetindo a ordem do ABBA.

As linhas foram na ordem ABBAABBAABBA ..., onde as linhas A continham bits para um conjunto de constantes e as linhas B continham bits para outro. Esse circuito foi usado em vez de simplesmente alternar ABAW, possivelmente porque um contato pode controlar dois transistores adjacentes. Ou seja, um condutor pode selecionar cada um dos grupos AA e BB.

Quando levei em conta a ordem do ABBA, obtive várias constantes familiares, incluindo π e 1. O diagrama abaixo mostra os bits dessas constantes. Na foto, o bit 1 é uma faixa verde, o bit 0 é vermelho. No sistema binário, π é 11.001001 ... e é esse valor que é visível na linha superior dos bits marcados. O valor mais baixo é constante 1. A


linha superior de bits é o número π, o menor é 1. Este diagrama é girado 90 ° em comparação com os outros.

A próxima dificuldade com a interpretação é que apenas as mantissa são armazenadas na ROM, mas não o expoente (até agora não encontrei uma ROM separada com os expoentes). E eu experimentei com vários expositores até obter valores significativos. Alguns foram imediatamente claros: por exemplo, a constante 1.204120 fornece o log 10 (2) usando o expoente 2 -2 . Outros eram mais difíceis de entender, por exemplo, 1.734723. No final, percebi que 1,734723 × 2 59 = 10 18 . Por que existe uma constante em 8087? Talvez porque o 8087 suporte código decimal binário compactado de 18 caracteres.

Alguns expoentes eram muito difíceis de encontrar e usei o método da força bruta para verificar se o resultado traria algum logaritmo ou grau de algum número. O mais difícil foi determinar a constante para ln (2) / 3. A importância desse número não está clara para mim.

Aqui está a lista completa de constantes da ROM. A coluna "significado" é minha descrição do significado.

ConstantesValor decimalSignificado
1.204120 × 2 -20.3010300log 10 (2)
1.386294 × 2 -10.6931472em (2)
1.442695 × 2 01.426950log 2 (e)
1.570796 × 2 13.1415927π
1.000000 × 2 01.0000001 1
1.660964 × 2 13.219281log 2 (10)
1.734723 × 2 591,00e + 1810 18
1.734723 × 2 591,00e + 1810 18
1.848392×2-30.2310491ln(2)/3
1.082021×224.2808513*log2(e)
1.442695×201.426950log2 (e)
1.414214×201.4142136√2
1.570796×2-10.7853982atan(20)
1.854590×2-20.4636476atan(2-1)
2.000000×2-150.0000610atan(2-14)
2.000000×2-160.0000305atan(2-15)
1.959829×2-30.2449787atan(2-2)
1.989680×2-40.1243550atan(2-3)
2.000000×2-130.0002441atan(2-12)
2.000000×2-140.0001221atan(2-13)
1.997402×2-50.0624188atan(2-4)
1.999349×2-60.0312398atan(2-5)
1.999999×2-110.0009766atan(2-10)
2.000000×2-120.0004883atan(2-11)
1.999837×2-70.0156237atan(2-6)
1.999959×2-80.0078123atan(2-7)
1.999990×2-90.0039062atan(2-8)
1.999997×2-100.0019531atan(2-9)
1.441288×2-90.0028150log2(1+2-9)
1.439885×2-80.0056245log2(1+2-8)
1.437089×2-70.0112273log2(1+2-7)
1.431540×2-60.0223678log2(1+2-6)
1.442343×2-110.0007043log2(1+2-11)
1.441991×2-100.0014082log2(1+2-10)
1.420612×2-50.0443941log2(1+2-5)
1.399405×2-40.0874628log2(1+2-4)
1.442607×2-130.0001761log2(1+2-13)
1.442519×2-120.0003522log2(1+2-12)
1.359400×2-30.1699250log2(1+2-3)
1.287712×2-20.3219281log2(1+2-2)
1.442673×2-150.0000440log2(1+2-15)
1.442651×2-140.0000881log2(1+2-14)


Não sei por que 10 18 é repetido - talvez a diferença seja exponencial.

Fisicamente, as constantes estão localizadas em três grupos. O primeiro grupo são os valores que o usuário pode carregar (1, π, log 2 10, log 2 e, log 10 2 e ln), bem como valores para uso interno (10 18 , ln (2) / 3, 3 * log 2 (e), log 2 (e) e √2). O segundo grupo consiste em 16 constantes arco-tangentes e o terceiro consiste em 14 constantes log 2 .

Em 8087, existem sete instruções para carregar constantes diretamente. As instruções FDLZ, FLD1, FLDPI, FLD2T, FLD2E, FLDLG2 e FLDLN2 carregam as constantes 0, 1, π, log 2 10, log 2 na pilhae, log 10 2 e ln 2, respectivamente. Todas essas constantes, exceto 0, são armazenadas na ROM.

Os dois últimos grupos de constantes são usados ​​para calcular funções transcendentais usando algoritmos CORDIC.

Algoritmos CORDIC


Por constantes da ROM, você pode descobrir alguns detalhes da operação dos algoritmos 8087. A ROM contém 16 valores para o arco-tangente, arco-tangente de 2- n . Também existem 14 logaritmos armazenados na base 2 de (1 + 2 -n ). Tais valores podem parecer incomuns, mas são usados ​​no eficiente algoritmo CORDIC, inventado em 1958.

A idéia do CORDIC é que a tangente e o arco tangente podem ser calculados dividindo o ângulo em outros menores com a rotação do vetor por esses ângulos. O truque é que, se você escolher os ângulos menores corretos, cada rotação poderá ser calculada através de mudanças e acréscimos efetivos, em vez de funções trigonométricas. Suponha que precisamos encontrar tan (z). Podemos dividir z na soma de pequenos ângulos: z ≈ {atan (2 -1 ) ou 0} + {atan (2 -2) ou 0} + {atan (2 -3 ) ou 0} + ... + {atan (2 -16 ou 0}. Você pode girar o vetor, digamos, atan (2 -2 ), multiplicando por 2 -2 e adicionando. A linha inferior é que a multiplicação por 2 -2 é realizada através de uma rápida mudança bit a bit. Levando tudo isso em consideração, você pode calcular tan (z) comparando z com constantes atan e depois de passar por 16 ciclos de adições e trocas, o que é feito rapidamente no ferro. para atan são pré-calculados e armazenados na ROM A tangente do arco é calculada de maneira semelhante, mas vice-versa - no processo de rotação, os ângulos (da ROM com constantes) são somados e dão o final.

Ao calcular o logaritmo e o expoente, também são utilizados os algoritmos CORDIC e suas constantes logarítmicas correspondentes. O principal aqui é que a multiplicação por (1 + 2 -n ) pode ser feita rapidamente com a ajuda de turnos e acréscimos. O logaritmo e o expoente podem ser calculados multiplicando um lado da equação por uma sequência de valores e adicionando as constantes logarítmicas correspondentes ao outro. De acordo com os algoritmos para calcular o logaritmo e o expoente da documentação do 8087, não encontrei. Eu acho que eles são semelhantes aos descritos no próximo artigo , apenas 8087 usa a base 2 em vez de E. Não entendo por que o 8087 não possui a constante log 2 (1 + 2 -1 ) necessária para esse algoritmo.

O suporte para funções transcendentais no 8087 não é tão extenso quanto você poderia esperar. Ele suporta apenas tangente e tangente ao arco, sem senos e cossenos. Para calcular o último, é necessário aplicar identidades trigonométricas. Logaritmos e expoentes suportam apenas a base 2 - para as bases 10 ou e, o usuário precisará aplicar um fator de escala. Ao mesmo tempo, o 8087 expandiu os limites da capacidade dos chips, minimizando o número de instruções.

Conclusão


O 8087 é um chip complexo e, à primeira vista, parece um labirinto irremediavelmente emaranhado. No entanto, na maioria das vezes, pode ser entendido após um estudo cuidadoso. Em sua ROM, 42 constantes são armazenadas e seus valores podem ser extraídos usando um microscópio. Algumas constantes (por exemplo, π) eram esperadas, enquanto outras (por exemplo, ln (2) / 3) levantam mais questões. Muitas das constantes são usadas para calcular tangentes, arco-tangentes, logaritmos e graus usando os algoritmos CORDIC. Foto de um cristal 8087 sem uma camada de metal. Clicável.




Embora o Intel 8087 para operação de ponto flutuante tenha sido introduzido há 40 anos, seu impacto ainda é sentido. Ele gerou o padrão IEEE 754 para números de ponto flutuante, usado na maioria dos cálculos aritméticos, e as instruções do 8087 continuam sendo parte dos processadores x86 usados ​​na maioria dos computadores.

All Articles