Operaciones lógicas en un procesador moderno

1

¿Por qué la mayoría de los procesadores solo proporcionan un número finito de operaciones lógicas (NAND / NOR / XOR) mientras que claramente hay 14 puertas lógicas diferentes disponibles? Entiendo que podemos implementar cualquier lógica booleana solo con NAND / NOR. Pero en la práctica, proporcionar menos compuertas hace que operaciones como NIMPLY / IMPLY requieran más de 1 ciclo para terminar, ya que necesitamos implementarlas con la composición de otras compuertas. Me parece que si ALU proporciona todo el conjunto de compuertas lógicas optimizadas para hardware, podríamos optimizar el rendimiento del software. El fanout puede ser un problema si todas las salidas de las puertas lógicas controlan el mismo bus, pero parece que las operaciones lógicas no siempre son el cuello de botella de un procesador moderno, ya que existen operaciones que requieren mucho más tiempo, como la multiplicación que limita el ciclo del reloj. Entonces, mi pregunta es ¿por qué rara vez vemos que los procesadores proporcionan el conjunto completo de puertas lógicas? ¿Cuáles son las consideraciones involucradas? ¿Cómo alcanzan los diseñadores de procesadores el número óptimo de operaciones lógicas diferentes que la ALU va a proporcionar?

    
pregunta Eagle Shou

2 respuestas

5

Si desea comprender cómo los diseñadores de procesadores alcanzan su conjunto de instrucciones "óptimo", puede consultar algunos libros, por ejemplo, " Arquitectura de computadora, un enfoque cuantitativo " por Hennessy & Patterson

Hay bastantes documentos disponibles gratuitamente en la web sobre arquitectura de computadoras y Arquitectura de conjuntos de instrucciones (ISA).

Le sugiero que lea los documentos y vea los videos en enlace

Como ejemplo concreto, consulte el Manual de conjuntos de instrucciones comprimidas RISC-V

Su proceso para el "Manual de conjuntos de instrucciones comprimidas RISC-V" fue reunir conjuntos de programas reconocidos, representativos y de 'referencia', en lenguajes de alto nivel como C, y realizar análisis a través de ellos. Por ejemplo, podrían usar un compilador de C existente, modificar su generación de código para generar su prototipo ISA, pasar sus programas de referencia a través de él y analizar los resultados. Eso se basa en cierta medida en que el compilador tiene un modelo lo suficientemente rico como para hacer uso de las instrucciones de su ISA.

En el caso específico de ese análisis de conjunto de instrucciones comprimidas, querían identificar qué instrucciones eran lo suficientemente comunes, que proporcionar una instrucción comprimida habría reducido significativamente el código. Sin embargo, ese análisis utiliza técnicas que se han aplicado anteriormente.

El análisis del conjunto de instrucciones comprimidas mostró que solo 31 instrucciones representaron la gran mayoría del código, por lo que al comprimirlas en un 50%, se redujo el tamaño total del programa en un 25%. Dado que gran parte del código son datos, eso sugiere que muchas instrucciones se usan raramente.

Recuerde, agregar más instrucciones y expandir la ALU no es necesariamente gratis. Para maximizar el rendimiento (es decir, realizar un trabajo útil), intentamos obtener un equilibrio entre la latencia (retardo) a través de la ALU, el consumo de energía y el tiempo de instrucción general. Agregar una instrucción que podría hacer que la CPU se ejecute un 5% más lento en cada instrucción, ya que el 0.1% del código para ejecutarse 2 veces más rápido no tiene sentido.

Esta es una versión de Ley de Amdahl , que esencialmente dice que no importa cuánta parte de un sistema sea mejorado, si solo representa el 1% de los recursos (de un programa) (tiempo o espacio), entonces la mejora solo puede beneficiar el rendimiento del sistema en un 1%.

La gran mayoría de las instrucciones ejecutadas por un programa son cargas, almacenes, aritmética simple, saltos y ramas condicionales. Siempre y cuando se ejecuten bien, agregar algunas instrucciones especializadas para hacer que las operaciones poco utilizadas sean más rápidas no hará prácticamente ninguna diferencia. Peor aún, si la adición de instrucciones especializadas ralentiza las instrucciones comunes en una pequeña cantidad, es probable que sea mejor eliminarlas.

Para obtener más información, busque documentos de investigación de RISC más antiguos (1980). Tal vez comience con John L. Hennessy y David Patterson ya que eran editores bastante prolíficos, y Hennesey fundó MIPS, y el trabajo de Patterson se convirtió en SUN SPARC.

    
respondido por el gbulmer
3

Hay dieciséis operaciones lógicas básicas bitwise disponibles con 0, 1 o 2 entradas. (Las entradas cero constituyen los valores constantes 0 y 1). La 74LS181 ALU de 4 bits , utilizada en este clásico computadoras como la PDP-11, VAX 11/780 y muchas otras computadoras implementaron todas ellas. Estoy utilizando este chip como ejemplo porque su hoja de datos expone los circuitos internos y otros detalles de la ALU. Dicha información generalmente no está disponible para microprocesadores en la actualidad. Las dieciséis operaciones (enumeradas en el orden en que se abordan en el 74LS181) son:

~A          NOT A
~(A&B)      NAND
~A+B        A IMPLY B     can also be written ~(A & ~B)
1           constant 1
~(A+B)      NOR
~B          NOT B
~(A^B)      XNOR
A+~B        B IMPLY A     can also be written ~(~A & B) 
~A&B        B NIMPLY A
A^B         XOR
B           B
A+B         OR
0           constant 0
A&~B        A NIMPLY B
A&B         AND
A           A 

donde ~ = bit a bit NO, & = Y, | = O, y ^ = XOR como se usa en C y otros idiomas.

IMPLICAR y NIMPLY son instrucciones bastante especializadas que se utilizan principalmente en biología; ver por ejemplo este documento y también este . En hardware, se ven así:

No estoy seguro de si las ALU modernas proporcionan las dieciséis operaciones, ya que no hay forma de llegar a muchas de ellas a través de los conjuntos de instrucciones de sus procesadores.

Prácticamente todos los procesadores proporcionan las cuatro operaciones lógicas básicas a nivel de bits NOT, AND, OR y XOR en sus conjuntos de instrucciones a nivel de máquina, ya que todas las demás operaciones se pueden construir a partir de ellos, como se muestra en la tabla anterior.

Por lo tanto, un compilador que genera un código para la declaración de alto nivel:

C = A & ~B;     // A NIMPLY B

podría generar algo como (utilizando un conjunto de instrucciones hipotéticas):

mov   R0, A    ; A => R0
mov   R1, B    ; B => R1
not   R1       ; ~R1 => R1
and   R0, R1   ; R0 & R1 => R0
mov   C, R0    ; R0 => C

Ahora sería bueno que un compilador reconociera un patrón como C = A & ~ B pudo generar una instrucción para decirle a la ALU que realice el A & ~ Operación B en un ciclo (evitando tener que complementar B primero):

mov   R0, A    ; A => R0
mov   R1, B    ; B => R1
nimply R0, R1  ; R0 NIMPLY R1 => R0
mov   C, R0    ; R0 => C

pero sin la instrucción de máquina para NIMPLY, no puede hacer esto. Sin embargo, al hacerlo solo se guarda una instrucción, ¿vale la pena?

Con la excepción de la familia 80x86, cuyo CISC (conjunto de instrucciones complejas) se remonta a casi 40 años (1978), la mayoría de los procesadores de hoy usan alguna versión de RISC (conjunto de instrucciones reducido). Por lo tanto, las instrucciones especializadas y poco utilizadas como IMPLY y NIMPLY no tienen lugar en los procesadores RISC.

    
respondido por el tcrosley

Lea otras preguntas en las etiquetas