Quando os engenheiros estão projetando uma arquitetura de conjunto de instruções, por qual procedimento ou protocolo, se houver, eles seguem ao designar determinados códigos binários como instruções. Por exemplo, se eu tenho um ISA que diz 10110 é uma instrução de carga, de onde veio esse número binário? Foi modelado a partir de uma tabela de estados para uma máquina de estados finitos representando uma operação de carregamento?
Edit: Depois de fazer mais pesquisas, acredito que o que estou tentando perguntar se preocupa como os códigos de operação das várias instruções da CPU são atribuídos. ADD pode ser designado com um código de operação 10011; uma instrução de carga pode ser designada como 10110. Qual é o processo de pensamento para atribuir esses códigos opcionais binários ao conjunto de instruções?
fonte
Respostas:
Em muitos casos, a escolha é bastante arbitrária ou baseada em "onde for melhor", à medida que os ISAs crescem com o tempo. No entanto, o MOS 6502 é um exemplo maravilhoso de chip em que o design do ISA foi fortemente influenciado pela tentativa de extrair o máximo possível de transistores limitados.
Confira este vídeo explicando como o 6502 foi modificado com engenharia reversa , principalmente a partir das 34:20.
O 6502 é um microprocessador de 8 bits lançado em 1975. Embora tivesse 60% menos portas do que o Z80, era duas vezes mais rápido e, embora fosse mais restrito (em termos de registros etc.), compensava isso com um conjunto de instruções elegante.
Ele contém apenas 3510 transistores, que foram desenhados à mão por uma pequena equipe de pessoas rastejando sobre grandes folhas de plástico que foram posteriormente reduzidas opticamente, formando as várias camadas do 6502.
Como você pode ver abaixo, o 6502 passa o código de operação da instrução e os dados de temporização para a ROM de decodificação e os passa para um componente de "lógica de controle aleatório", cujo objetivo provavelmente é anular a saída da ROM em determinadas situações complexas.
Às 37:00 do vídeo, você pode ver uma tabela da ROM de decodificação que mostra quais condições as entradas devem atender para obter um "1" para uma determinada saída de controle. Você também pode encontrá-lo nesta página .
Você pode ver que a maioria das coisas nesta tabela tem Xs em várias posições. Vamos pegar, por exemplo
Isso significa que os 3 primeiros bits do código de operação devem ser 011 e G deve ser 2; nada mais importa. Nesse caso, a saída denominada RORRORA será verdadeira. Todos os opcodes ROR começam com 011; mas há outras instruções que começam com 011 também. Provavelmente, eles precisam ser filtrados pela unidade "lógica de controle aleatório".
Então, basicamente, os opcodes foram escolhidos para que as instruções que precisavam fazer a mesma coisa tivessem algo em comum em seu padrão de bits. Você pode ver isso olhando para uma tabela opcode ; todas as instruções OR começam com 000, todas as instruções da loja começam com 010, todas as instruções que usam o endereçamento de página zero têm o formato xxxx01xx. Obviamente, algumas instruções parecem não se encaixar, porque o objetivo não é ter um formato de código de operação completamente regular, mas fornecer um conjunto de instruções poderoso. E é por isso que a "lógica de controle aleatório" era necessária.
A página que mencionei acima diz que algumas das linhas de saída na ROM aparecem duas vezes: "Assumimos que isso tenha sido feito porque eles não tinham como rotear a saída de alguma linha para onde queriam, então colocaram a mesma linha em um local diferente. localização novamente. " Posso imaginar os engenheiros desenhando à mão esses portões um a um e subitamente percebendo uma falha no design e tentando encontrar uma maneira de evitar o reinício de todo o processo.
fonte
Depende da idade do ISA.
Nos primórdios do design manual, e ainda mais quando as CPUs eram montadas a partir de lógica discreta, o design lógico teria sido o primeiro e seria amplamente minimizado, e então os padrões de bits ISA teriam sido os valores necessários para tornar o mínimo trabalho lógico.
Portanto, pode haver um padrão específico de sinais de controle que permita que alguns multiplexadores conectem a saída da ALU à entrada do arquivo de registro GP, mais alguns sinais de controle que instruem a ALU a adicionar, subtrair, AND, OR etc. e alguns bits de endereço no arquivo de registro. Esses três grupos de sinais formarão campos dentro da instrução. Cada grupo será mantido junto, e seu significado detalhado surge do design dessa unidade (ALU etc.), mas os grupos podem estar em qualquer ordem, até você projetar o decodificador de instruções. (o x86 tem idade suficiente para detectar um pouco disso, se você olhar no lugar certo - não era um design totalmente novo, mas foi extraído do antigo 8080)
Os ISAs posteriores podem ser "limpos" e tornados mais regulares e mais simples de usar, com hardware para traduzir entre eles e os sinais de controle reais no nível do hardware, às vezes via "microcódigo". Eles são chamados de "CISC" ou "Código de conjunto de instruções complexo". O prefixo da instrução "Rep" x86 é um exemplo simples disso - faz com que a instrução a seguir seja repetida várias vezes, para economizar a necessidade de gravar um loop FOR.
Mais tarde ainda (nos anos 80), voltou-se para um estilo mais simples de codificação direta (RISC - Reduced Instruction Set Coding), que você pode ver nos processadores ARM. Isso foi motivado pelo pequeno tamanho dos ASICs na época e pelo desejo de colocar CPUs de 32 bits neles, portanto, não havia capacidade disponível para decodificadores complexos de conjuntos de instruções, para reduzir o CPU completo para cerca de 20.000 portas. (Houve também um aumento temporário no desempenho, porque as pessoas ainda não haviam desenvolvido técnicas para acelerar os decodificadores CISC - que ocorreram em 1995 com o Pentium Pro)
E hoje em dia não importa - as CPUs leem várias instruções de uma só vez e dedicam milhões de transistores a decodificá-las, reordená-las e executar o maior número possível de uma só vez, para acelerar programas que podem ter sido escritos para os mais antigos estilo do ISA.
fonte
Se você agrupar instruções semelhantes, surgirão padrões. Isso é muito óbvio no ARM, onde o manual ISA realmente mostra qual parte da palavra de instrução corresponde à função, escolha de registro, etc. Mas também pode ser inferida para o X86 .
Por fim, a parte "função" dos códigos de operação entra em algum decodificador binário-para-um que realmente ativa uma função ou sequência específica de operações em pipeline. Geralmente, eles não estão relacionados ao conteúdo de nenhuma máquina de estado, a menos que consideremos instruções de comprimento variável que exigem a decodificação de uma máquina de estado.
fonte
Alguém em algum momento sentou-se e os definiu.
Um bom ISA tornará o decodificador o mais simples possível.
Por exemplo, com uma instrução ALU, você pode permitir que alguns bits do código op sejam enviados diretamente para as linhas de controle da ALU.
fonte
Normalmente, você dividiria seu ISA em grupos funcionais. Faz sentido (para otimização lógica ou apenas para ser organizado) que os pares complementares sejam diferenciados por uma única alteração de bit (carga versus armazenamento) e que você tenha alguma hierarquia de bits que afeta a árvore de decisão de decodificação.
No final do dia, uma alocação arbitrária de bits para o bloco de funções (em vez de colocar os campos "dados" na instrução terá apenas um pequeno impacto na eficiência geral do projeto - mas você tem muitas opções sobre como 'otimize' sua codificação ISA, dependendo do que você considera um parâmetro importante.
fonte
A codificação de instruções é um compromisso feio entre.
Simplificando a decodificação, para isso, você deseja um conjunto simples de campos, cada um dos quais pode ser decodificado separadamente e roteado para uma parte separada do mecanismo de execução.
Empacotar o máximo de funcionalidade possível em um tamanho limitado da palavra de instrução. Isso leva a coisas como formatos constantes especiais que podem codificar uma variedade de números comuns.
Compatibilidade para frente e para trás. Se você atribuir funcionalidade a todo código de operação possível, não terá espaço para expandir a arquitetura posteriormente. Se você estiver adicionando a uma arquitetura existente, precisará inserir suas novas instruções nos códigos de operação sobressalentes.
fonte
A excelente arte de montagem de Randy Hyde entra em detalhes sobre o conjunto de instruções x86 no capítulo 3.3.4 A unidade de controle e os conjuntos de instruções e seguintes.
Ele então demonstra bastante cativante e detalhadamente como o primeiro par de plugues representa a instrução, os próximos plugs codificam a origem e o destino. É claro que hoje ninguém mais "se conecta", mas para os ISA realmente antigos, os bits no código de operação basicamente fazem o mesmo trabalho que os plugs anteriores.
Você acaba com algo assim:
fonte