Por que o MIPS incluiu shamt e distinguiu funct / opcode?

15

Estou confuso sobre o motivo pelo qual os projetistas do MIPS incluem 5 bits dedicados à mudança e têm código de operação e bits de função separados.

Como o MIPS é tão RISC, presumo que apenas a troca seria feita em algumas instruções, de modo que esses 5 bits parecem estar perdendo espaço quando poderiam ser colocados no imediato. Suponho que opcodes e funct sejam separados para distinguir instruções dos tipos R e I, mas isso pode ser feito estendendo o código de operação em 1 bit. Com ambas as instruções do tipo R, pode ser de 22 bits. Isso não funcionará se as instruções tipo I e tipo J quiserem manter seus endereços e endereços imediatos, mas ambas parecem desnecessárias.

qwr
fonte

Respostas:

10

Existem algumas vantagens e desvantagens aqui.

Primeiro, queremos que as instruções tenham largura fixa (32 bits). Isso garante que as instruções estejam alinhadas com o bloco de cache e a página, o que simplifica as verificações de presença e permissão de cache e página.

Segundo, queremos que os vários campos de instrução ( opcode/ source regs/ immediates) tenham largura e posição fixas. Isso os torna mais rápidos / menos lógicos para decodificar e são necessários nos estágios iniciais do pipeline. (O destinationregistro não é necessário até o final do pipeline, para que possa estar em diferentes locais Re Iinstruções.) A posição e a largura do functioncampo são um pouco menos porque isso precisa controlar a função da ULA, mas isso é necessário. no terceiro estágio do pipeline, para que você tenha um pouco de tempo para trabalhar com ele, se necessário.

IJJ228.228.Iinstruções também são boas para escritores de compilador / vinculador. (No SPARC, onde o campo imediato era de apenas 12 bits, eles tinham que adicionar uma load-highclasse de instrução especial inteira com um imediato de 20 bits.)

26=64JRI

Mas isso deixa espaço de manobra com as Rinstruções. Além do código de operação de 6 bits, eles precisam apenas de 15 bits adicionais para a especificação do registro, o que deixa 11 bits para o código de operação estendido e / ou a quantidade de turno.

Você deve pensar no functioncampo como sendo um código de operação estendido para a Rinstrução. Existe apenas um Rcódigo de operação da instrução, mas existem 64 diferentes functionsque a Rinstrução pode executar.

OK. Temos 60 Iinstruções diferentes e 64 Rinstruções diferentes , então onde devemos colocar as instruções de mudança imediata?

Bem, não apenas existem menos Iinstruções, mas também há muito mais coisas que queremos fazer com as I instruções. Lembre-se de que todas as instruções de ramificação precisam ser Iinstruções porque elas têm um deslocamento relativo (imediato). Além disso, todas as instruções de carregamento e armazenamento estão Ino formato MIPS. E, finalmente, precisamos da instrução load-upper-imediato para ser uma Iinstrução. Não apenas isso, mas as Rinstruções ainda possuem 5 bits adicionais não utilizados (que é o que precisamos para o imediato de um turno imediato nesta arquitetura), portanto, isso incentiva ainda mais a transformar os imediatos do turno em Rinstruções especiais (estranhas) .

Muitas dessas decisões são mais arte do que ciência, mas há uma lógica subjacente que pode ser discernida. O objetivo principal não é tornar o número de instruções o menor possível, é criar um desempenho de alto desempenho.pipeline ajustado em um único chip (para que pequenas empresas, como MIPS e Sun estivessem na década de 1980, pudessem competir com a IBM e a DEC). (O nome RISC, inventado por David Patterson, é um tanto infeliz. Ele pegou porque era fofo, não porque "instruções reduzidas" é uma descrição precisa do que as arquiteturas MIPS e SPARC estavam realmente tentando fazer.) instruções largura fixa (e relativamente pequena para que você obtenha um melhor comportamento de cache em I) para tornar a busca, a paginação e a decodificação mais simples e rápidas. Você deseja que as partes da instrução que precisam ser decodificadas mais cedo (oopcode, as duas fontes de registro e o imediato estendido por sinal) tenham uma largura fixa e uma posição fixa. Você deseja que o imediato seja o maior tempo possível e o maior número possível de instruções, conforme todas as outras restrições.

Lógica Errante
fonte
Obrigado por sua resposta informativa, especialmente a parte sobre os objetivos dos designers de arquitetura. Acho interessante comparar o MIPS com o MOS 6502, porque se o entendi corretamente, o 6502 nunca teve vergonha (ainda estou tentando entender os formatos das instruções).
Qr1
11
O 6502 era um projeto de microprocessador de primeira geração (pré-CISC), embora previsse o pipelining, pois podia registrar o write-back ao mesmo tempo em que carregava a próxima instrução. O 6502 tinha códigos de bytes, como a maioria dos micros de 8 bits. Outra arquitetura a considerar é o ARM, que foi projetado por vários engenheiros eletrônicos de nível superior que leram os documentos do Berkeley RISC e visitaram a fábrica do MOS e decidiram "ei, nós podemos fazer isso".
Pseudônimo
Eu me pergunto quais seriam as implicações se houvesse um padrão de bits shamt que significasse "não execute a instrução a seguir, mas use os 32 bits que foram buscados como o operando de origem para esta instrução"? Como alternativa ou além disso, pergunto-me se seria prático ter um bom espaço de código de código dedicado a pares de instruções simples e ininterruptas - um conceito parecido com Thumb, mas livremente intercalável com instruções de 32 bits e sem a capacidade de pular diretamente para a segunda instrução de uma palavra?
supercat 08/02
5

Para entender os formatos de instruções do MIPS I, você precisa entender o pipeline do MIPS e também pensar na tecnologia de implementação da CPU por volta de 1985. Se você olhar o diagrama (você conhece esse), verá que a leitura do arquivo de registro está na Estágio de identificação, logo após o IF.

Para os fins de uma instrução do tipo R, o estágio ID precisa executar as seguintes tarefas:

  1. Determine que na verdade é uma instrução do tipo R.
  2. Nesse caso, diga ao arquivo de registro para carregar valores dos registros.

Para os fins desta discussão, é a primeira tarefa em que você precisa pensar. Se houver muito trabalho de decodificação de instruções que você precisa fazer para resolver, mesmo se precisar de algum valor dos registros, isso aumenta o atraso antes que você possa iniciar as leituras do registro. Também aumenta a complexidade do estágio de ID. Ao reservar um único código de operação para todas as instruções do tipo R, você reduz a complexidade ao mínimo.

Parece um pouco estranho que você dedique cinco bits apenas à mudança. Eu posso pensar em algumas explicações possíveis. Uma é que simplifica o roteamento (esses cinco bits são SEMPRE alimentados diretamente no arquivo de registro, esses cinco bits são SEMPRE alimentados no shifter de barril, esses seis bits são SEMPRE encaminhados para a ULA para determinar qual função executar).

Eles podem estar pensando em introduzir instruções combinadas de mudança de esquerda e adição no futuro. Presumivelmente, isso teria a forma:

$d = $s + ($t << shamt)

2s+1 1s

Hoje, provavelmente não pensamos duas vezes em ter um estágio de decodificação mais complexo, especialmente porque os acessos a arquivos de registro tendem a acontecer mais tarde no pipeline de uma CPU superscalar típica. Muitas CPUs modernas até decodificam grosseiramente as instruções no momento em que uma instrução é inserida no cache L1 . Você torna as linhas do cache I um pouco mais largas para armazenar informações extras (graças à Lei de Moore, você tem muitos transistores a serem desperdiçados) para tornar a decodificação "adequada" das instruções mais simples e rápida.

Uma razão pela qual eles provavelmente queriam manter o campo opcode o menor possível é para que não penalizasse indevidamente as instruções do tipo J. Como você provavelmente sabe, as instruções do tipo J usam endereçamento pseudo-direto. Para o benefício de qualquer um que esteja tocando em casa, explicarei brevemente.

O campo de endereço de uma instrução do tipo J é 26 bits. Como as instruções estão sempre alinhadas em 4 bytes, você não precisa armazenar os dois bits menos significativos, o que significa que você possui efetivamente 28 bits de endereço. No entanto, o espaço de endereço no MIPS I é de 32 bits. Portanto, os quatro bits principais do local do salto são retirados do contador do programa.

Isso significa que você não pode pular diretamente para um local onde os quatro bits mais significativos do local do PC são diferentes. Você precisaria fazer um salto de três instruções mais caro em um registro de rascunho:

lui $r,target >> 16
    ori $r,$r,target & 0xFFFF
    jr $r

Hoje não é tão ruim assim, mas em 1985 são muitos ciclos de relógio.

Roubar um pouco do campo de endereço reduziria ainda mais o alcance efetivo de um salto direto. Você pode ver como esse preço pode ser alto demais para pagar.

Pseudônimo
fonte
"instruções combinadas shift-left-and-add" do tipo visto posteriormente no ARM?
Damian Yerrick 06/02