¿Por qué MIPS incluyó shamt y distinguió funct / opcode?

15

Estoy confundido sobre por qué los diseñadores de MIPS incluirían 5 bits dedicados al cambio y tienen códigos de operación y bits de función separados.

Debido a que MIPS es tan RISC, supongo que solo se realizarán cambios en unas pocas instrucciones, por lo que esos 5 bits parecen estar desperdiciando espacio cuando podrían colocarse de inmediato. Supongo que los códigos de operación y la función están separados para distinguir las instrucciones de tipo R e I, pero esto podría hacerse extendiendo el código de operación en 1 bit. Con estas dos instrucciones de tipo R podría tener 22 bits de longitud. Esto no funcionará si las instrucciones de tipo I y tipo J quieren mantener su dirección y dirección inmediatas, pero ambas parecen innecesarias.

qwr
fuente

Respuestas:

10

Aquí hay algunas compensaciones diferentes.

Primero, queremos que las instrucciones sean de ancho fijo (32 bits). Esto garantiza que las instrucciones estén bloqueadas en caché y alineadas en la página, lo que simplifica la presencia de caché y presencia de página y las verificaciones de permisos.

En segundo lugar, queremos que los diversos campos de instrucciones ( opcode/ source regs/ immediates) tengan un ancho fijo y una posición fija. Esto los hace más rápidos / menos lógicos para decodificar y son necesarios en las primeras etapas de la tubería. (El destinationregistro no es necesario hasta el final de la tubería, por lo que puede estar en diferentes lugares Re Iinstrucciones). La posición y el ancho del functioncampo son un poco menos importantes porque eso necesita controlar la función de la ALU, pero eso es en la tercera etapa de canalización, por lo que tiene un poco de tiempo para trabajar con ella si es necesario.

Pero ahora tenemos una tensión entre el número de instrucciones posibles y los tamaños de los inmediatos. Queremos que lo inmediato en las instrucciones Ie Jsea ​​lo más largo posible. Esta es una arquitectura de 32 bits, y la Jinstrucción solo tiene una dirección de 26 bits. Se le agregan dos bits de orden inferior cero (otro beneficio de las instrucciones de ancho fijo) pero aún así solo puede saltar una distancia máxima de bytes, lo que dificulta la vida del enlazador. (Una llamada de un procedimiento que está a más de bytes de distancia debe hacerse con una instrucción triple: carga-superior-inmediata, adición-inmediata, salto-y-enlace-registro, en lugar de solo un salto- y-enlace.) El inmediato de 16 bits en228228Ilas instrucciones también son buenas para los escritores compiladores / enlazadores. (En el SPARC, donde el campo inmediato era de solo 12 bits, tuvieron que agregar una load-highclase de instrucción especial completa con un inmediato de 20 bits).

Por lo tanto, realmente no queremos que el código de operación sea de 7 bits (porque se cortará en inmediatos), pero con 6 bits solo tenemos posibles instrucciones diferentes, lo cual es muy poco. El compromiso es: hay exactamente dos instrucciones de tipo (salto y salto y enlace), y solo una o dos instrucciones de tipo , con los 60 códigos de operación restantes que se utilizan para las instrucciones.26 6=64JRI

Pero eso deja un margen de maniobra con las Rinstrucciones. Además del código de operación de 6 bits, estos solo necesitan 15 bits adicionales para la especificación del registro, lo que deja 11 bits para el código de operación extendido y / o la cantidad de desplazamiento.

Debe pensar en el functioncampo como un código de operación extendido para la Rinstrucción. Solo hay un Rcódigo de operación de instrucción, pero hay 64 diferentes functionsque la Rinstrucción puede realizar.

Bueno. Tenemos 60 Iinstrucciones diferentes y 64 Rinstrucciones diferentes , entonces, ¿dónde debemos poner las instrucciones inmediatas de turno?

Bueno, no solo hay menos Iinstrucciones, sino que hay muchas más cosas que queremos hacer con las I instrucciones. Recuerde que todas las instrucciones de ramificación deben ser Iinstrucciones porque tienen un desplazamiento relativo (inmediato). Además, todas las instrucciones de carga y almacenamiento están Iformateadas en MIPS. Y finalmente necesitamos que la instrucción load-upper-inmediate sea una Iinstrucción. No solo eso, sino que las Rinstrucciones todavía tienen 5 bits adicionales no utilizados (que es lo que necesitamos para el inmediato de un cambio inmediato en esta arquitectura), por lo que esto da un mayor incentivo para convertir el cambio inmediato en Rinstrucciones especiales (extrañas) .

Muchas de estas decisiones son más arte que ciencia, pero existe una lógica subyacente que se puede discernir. El objetivo clave no es hacer que el número de instrucciones sea lo más pequeño posible, es hacer un alto rendimientoLa tubería encaja en un solo chip (para que pequeñas empresas, como MIPS y Sun en la década de 1980, pudieran competir con IBM y DEC). (El nombre RISC, inventado por David Patterson, es algo desafortunado. Se dio cuenta porque era lindo, no porque las "instrucciones reducidas" es una descripción precisa de lo que las arquitecturas MIPS y SPARC realmente estaban tratando de hacer). ancho fijo de instrucciones (y relativamente pequeño para que obtenga un mejor comportamiento de I-cache) para hacer que la búsqueda, la paginación y la decodificación sean más simples y rápidas. Desea las partes de la instrucción que deben decodificarse temprano (elopcode, los dos registros de origen y el signo (extendido inmediato) deben tener un ancho fijo y una posición fija. Desea que los inmediatos sean lo más largos posible, y desea tantos tipos diferentes de instrucciones como quepan, dadas todas esas otras restricciones.

Lógica Errante
fuente
Gracias por su respuesta informativa, especialmente la parte sobre los objetivos de los diseñadores de arquitectura. Encuentro interesante comparar MIPS con el MOS 6502, porque si lo entiendo correctamente, el 6502 nunca tuvo fallas (todavía estoy tratando de entender los formatos de instrucciones).
qwr
1
El 6502 era un diseño de microprocesador de primera generación (pre-CISC), aunque anticipaba la canalización, ya que podía registrar la reescritura al mismo tiempo que cargaba la siguiente instrucción. El 6502 tenía códigos de operación de bytes, como la mayoría de los micros de 8 bits. Otra arquitectura a considerar es la ARM, que fue diseñada por un grupo de ingenieros electrónicos de nivel superior que leyeron los documentos de Berkeley RISC y visitaron la fábrica de MOS y decidieron "oye, podemos hacer eso".
Seudónimo
Me pregunto cuáles habrían sido las implicaciones si hubiera un patrón de bits simulado que significara "no ejecute la siguiente instrucción, sino que utilice los 32 bits que se han obtenido como el operando de origen para esta instrucción". Alternativamente o además, me pregunto si hubiera sido práctico tener una buena cantidad de espacio de código de operación dedicado a pares de instrucciones simples e ininterrumpidas, un concepto algo parecido al Pulgar, pero libremente intercalable con instrucciones de 32 bits, y sin la capacidad de saltar directamente a la segunda instrucción de una palabra?
supercat
5

Para comprender los formatos de instrucción MIPS I, debe comprender la canalización de MIPS y también volver a pensar en la tecnología de implementación de la CPU alrededor de 1985. Si observa el diagrama (ya sabe cuál), verá que la lectura del archivo de registro está en el Etapa de identificación, justo después de IF.

Para el propósito de una instrucción de tipo R, la etapa de ID debe realizar las siguientes tareas:

  1. Determine que en realidad es una instrucción de tipo R.
  2. Si es así, dígale al archivo de registro que cargue los valores de los registros.

Para el propósito de esta discusión, es la primera tarea en la que debe pensar. Si hay mucho trabajo de decodificación de instrucciones que tiene que hacer para incluso resolver si necesita algún valor de los registros, esto aumenta el retraso antes de que pueda comenzar las lecturas del registro. También aumenta la complejidad de la etapa de identificación. Al reservar un único código de operación para todas las instrucciones de tipo R, mantiene la complejidad al mínimo.

Parece un poco extraño que dediques cinco bits solo al cambio. Se me ocurren algunas explicaciones posibles. Una es que simplifica el enrutamiento (esos cinco bits SIEMPRE se introducen directamente en el archivo de registro, esos cinco bits SIEMPRE se introducen en la palanca de cambios de barril, esos seis bits SIEMPRE se enrutan a través de la ALU para determinar qué función realizar).

Es posible que hayan estado pensando en introducir instrucciones combinadas shift-left-and-add en el futuro. Esto presumiblemente sería de la forma:

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

2s+1s

Hoy, probablemente no lo pensaríamos dos veces antes de tener una etapa de decodificación más compleja, especialmente porque los accesos a los archivos de registro tienden a ocurrir más tarde en la tubería de una CPU superescalar típica. Muchas CPU modernas incluso realizan una descodificación de instrucciones aproximada en el momento en que se inserta una instrucción en el caché L1 . Hace que las líneas I-cache sean un poco más anchas para almacenar la información adicional (gracias a la Ley de Moore, tiene muchos transistores que desperdiciar) para que la decodificación de instrucciones "correctas" sea más simple y rápida.

Una razón por la que probablemente querían mantener el campo de código de operación lo más pequeño posible es para que no penalizara indebidamente las instrucciones de tipo J. Como probablemente sepa, las instrucciones de tipo J usan direccionamiento pseudo-directo. Para beneficio de cualquiera que juegue en casa, lo explicaré brevemente.

El campo de dirección de una instrucción de tipo J es de 26 bits. Debido a que las instrucciones siempre están alineadas con 4 bytes, no necesita almacenar los dos bits menos significativos, lo que significa que efectivamente tiene 28 bits de dirección. Sin embargo, el espacio de direcciones en MIPS I es de 32 bits. Entonces, los cuatro bits superiores de la ubicación de salto se toman del contador del programa.

Esto significa que no puede saltar directamente a una ubicación donde los cuatro bits más significativos de la ubicación de la PC son diferentes. Tendría que hacer un salto de tres instrucciones más costoso a través de un registro de cero en su lugar:

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

Eso no está tan mal hoy, pero en 1985, son muchos ciclos de reloj.

Robar un poco del campo de dirección reduciría aún más el alcance efectivo de un salto directo. Puede ver cómo esto podría ser un precio demasiado alto para pagar.

Seudónimo
fuente
¿"instrucciones combinadas shift-left-and-add" del tipo que luego se vio en ARM?
Damian Yerrick