La respuesta corta
Los pasos para decodificar y ejecutar la instrucción se ejecutan en paralelo con el siguiente paso de la instrucción anterior. Esta técnica se conoce como tubería. Ver en los procesadores RISC a continuación.
Una arquitectura RISC de un solo problema generalmente promediará un poco menos de una instrucción por ciclo debido a los estados de espera y el tiempo necesario para las operaciones de carga / almacenamiento que afectan la memoria en lugar de simplemente registrarse para registrarse. Las ranuras de retraso le brindan un gancho arquitectónico que puede permitirle recuperar parte de este tiempo. Ver en los procesadores RISC a continuación.
Un ciclo de instrucciones es el tiempo necesario para ejecutar una instrucción. Esto variará con la arquitectura y (en algunos casos) las instrucciones. Por ejemplo, la mayoría de las instrucciones sobre algo como un MIPS R2000 / 3000 toman un ciclo. Las instrucciones que involucran el acceso a la memoria (carga / almacenamiento, ramificación) toman más de un ciclo, aunque las ranuras de retraso significan que puede ejecutar algo más (posiblemente solo un NOP) en la ranura de retraso. Las arquitecturas no canalizadas pueden tener ciclos de instrucción de varios ciclos de reloj, que a menudo varían con el modo de direccionamiento. Ver procesadores RISC En las arquitecturas tradicionales, CISC y Cableados Arquitecturas continuación.
Los diseños de múltiples problemas pueden difuminar este concepto al ejecutar más de una instrucción en paralelo.
Los procesadores CISC pueden tener instrucciones que toman diferentes períodos de tiempo. El número exacto de ciclos de reloj depende de la arquitectura y las instrucciones. El número variable de ciclos de reloj tomados en CISC ISA es una de las razones por las que son difíciles de construir en arquitecturas muy canalizadas. Vea las arquitecturas CISC tradicionales a continuación.
La respuesta más larga
Para un solo problema MIPS, SPARC u otra CPU, todas las instrucciones (para una primera aproximación) se emiten en un ciclo, aunque pueden tener algo conocido como un "intervalo de retraso".
En procesadores RISC
En este contexto, una CPU de un solo problema es aquella en la que la CPU no realiza ningún análisis de dependencia sobre la marcha y la emisión paralela de instrucciones en la forma en que lo hacen las CPU modernas, es decir, tienen una sola unidad de ejecución que ejecuta las instrucciones en El orden en que se leen de la memoria. Más sobre esto más tarde.
La mayoría de los procesadores RISC más antiguos son diseños de un solo problema, y estos tipos todavía se usan ampliamente en sistemas embebidos. Se puede implementar un núcleo RISC entero de un solo problema de 32 bits en alrededor de 25,000-30,000 puertas, por lo que los núcleos de CPU de este tipo tienen un consumo de energía muy bajo y huellas muy pequeñas. Esto los hace fáciles y económicos de integrar en productos SOC (sistema en chip).
Los diseños de CPU RISC se canalizan: el procesamiento de la instrucción se realiza en varias etapas, y cada instrucción se pasa por la tubería a la siguiente etapa en cada ciclo de reloj. En la mayoría de los casos, una CPU canalizada de un solo problema ejecutará algo cercano a una instrucción por ciclo de reloj.
Algunas arquitecturas tienen instrucciones como ramificar o cargar / almacenar desde la memoria donde el ciclo adicional tomado por el acceso a la memoria es visible para el código.
Por ejemplo, en un diseño SPARC V7 / V8 , la siguiente instrucción después de que una rama se ejecute realmente antes de que la rama tenga lugar. Por lo general, colocaría un NOP en la ranura después de la bifurcación, pero podría poner otra instrucción si pudiera encontrar algo útil que hacer.
La arquitectura MIPS R2000 / R3000 tenía una ranura de retardo similar en las instrucciones de carga / almacenamiento. Si cargó un valor de la memoria, en realidad no aparecerá en el registro para otro ciclo. Puede colocar un NOP en la ranura o hacer otra cosa si puede encontrar algo útil que no dependa de la operación de carga que acaba de emitir.
Si la memoria era más lenta que la CPU, que a menudo era el caso, podría obtener estados de espera adicionales en los accesos a la memoria. Los estados de espera congelan la CPU durante uno o más ciclos de reloj hasta que se completa el acceso a la memoria. En la práctica, estos estados de espera y tiempo extra para acceder a la memoria significan que los diseños de CPU de un solo problema promedian un poco menos de una instrucción por ciclo de reloj. Las ranuras de retardo le brindan algunas oportunidades posibles para optimizar el código ejecutando alguna otra instrucción mientras se lleva a cabo una operación de memoria.
Procesadores CISC tradicionales
Los procesadores CISC eran diseños que podían tener instrucciones que tomaban diferentes períodos de tiempo. A menudo tenían instrucciones más complejas implementadas directamente en hardware que tendrían que hacerse en software en una CPU RISC.
La mayoría de las arquitecturas de mainframe y casi todos los diseños de PC hasta el M68K e Intel 386 eran CPU CISC microcodificadas tradicionales. Estos diseños demostraron ser más lentos por reloj y usaron más compuertas que las CPU RISC.
Microcódigo
Un ejemplo de una arquitectura microcodificada (MOS 6502) se puede ver en la emulación aquí . El microcódigo se puede ver en la parte superior de la imagen.
Microcode controla los flujos de datos y las acciones activadas dentro de la CPU para ejecutar instrucciones. Al recorrer los pasos del microcódigo, puede activar las partes de una CPU, mover datos a través de ALU o realizar otros pasos. Los componentes reutilizables en la CPU se pueden coordinar en múltiples ciclos de reloj para ejecutar una instrucción. En el caso del 6502, el microcódigo también podría ejecutar algunas acciones canalizadas.
Los diseños microcodificados utilizaron menos silicio que los chips cableados a costa de potencialmente tomar varios ciclos de reloj para completar una instrucción. Dependiendo del diseño, estas CPU tomarían diferentes períodos de tiempo por instrucción.
Arquitecturas cableadas
Los diseños cableados (no necesariamente mutuamente excluyentes con microcódigo) ejecutan una instrucción sincrónicamente, o pueden tener sus propios coordinadores para hacer algo en múltiples ciclos de reloj. Por lo general, son más rápidos a expensas de un hardware más dedicado y, por lo tanto, son más caros de implementar que un diseño microcodificado de funcionalidad equivalente.
Un ejemplo famoso de esto fue la CPU original Amdahl 470/6 , que fue un reemplazo directo para la CPU en ciertos modelos IBM System / 370. La CPU Amdahl era un diseño cableado en un momento en que las 370 CPU de IBM estaban fuertemente basadas en microcódigo. La CPU Amdahl fue aproximadamente 3 veces más rápida que las CPU de IBM que reemplazaron.
Huelga decir que IBM no se divirtió y esto dio lugar a una batalla judicial que terminó obligando a IBM a abrir su arquitectura mainframe hasta que el decreto de consentimiento expiró hace unos años.
Por lo general, un diseño cableado de este tipo todavía no era tan rápido reloj por reloj como una CPU RISC, ya que los diferentes tiempos y formatos de instrucción no permitían tanto margen para la canalización como lo hace un diseño RISC.
Diseños de problemas múltiples
La mayoría de las CPU modernas son arquitecturas de múltiples problemas que pueden procesar más de una instrucción a la vez dentro de un solo hilo. El chip puede hacer un análisis de dependencia dinámico en el flujo de instrucciones entrantes y emitir instrucciones en paralelo donde no hay dependencia del resultado de un cálculo anterior.
El rendimiento de estos chips depende de cuánto paralelismo se puede lograr en el código, pero la mayoría de las CPU modernas promediarán varias instrucciones por ciclo en la mayoría del código.
Las CPU modernas Intel y otras CPU x86 / X64 ISA tienen una capa que interpreta el conjunto de instrucciones CISC de la vieja escuela en micro instrucciones que se pueden alimentar a través de un núcleo de múltiples problemas al estilo RISC. Esto agrega algo de sobrecarga que no está presente en las CPU con ISA que están diseñadas para canalizar (es decir, arquitecturas RISC como ARM o PowerPC).
Diseños VLIW
Los diseños VLIW, de los cuales el Intel Itanium es quizás el más conocido, nunca despegaron como arquitecturas convencionales, pero IIRC hay una serie de arquitecturas DSP que utilizan este tipo de diseño. Un diseño VLIW hace explícita la emisión múltiple con una palabra de instrucción que contiene más de una instrucción que se emite en paralelo.
Estos dependían de buenos compiladores optimizadores, que identificaban dependencias y oportunidades para el paralelismo, colocando instrucciones en los múltiples espacios disponibles en cada palabra de instrucción.
Las arquitecturas VLIW funcionan bastante bien para aplicaciones numéricas, ya que las operaciones de matriz / matriz tienden a ofrecer oportunidades para un amplio paralelismo. El Itanium tuvo un nicho de mercado en aplicaciones de supercomputación durante un tiempo, y hubo al menos una arquitectura de supercomputadora, la Multiflow TRACE , que se produjo utilizando un ISA de este tipo.
Memoria y almacenamiento en caché
Las CPU modernas son mucho, mucho más rápidas que la memoria, por lo que las lecturas directas de la memoria pueden generar cientos de estados de espera que bloquean la CPU hasta que se completa el acceso a la memoria. El almacenamiento en caché, ahora realizado en varias capas, contiene las ubicaciones de memoria utilizadas más recientemente en la memoria caché. Como las CPU generalmente pasan la gran mayoría del tiempo ejecutando código en bucles, esto significa que obtienes buenas tasas de éxito al reutilizar ubicaciones de memoria que has usado recientemente. Esta propiedad se llama 'localidad de referencia'.
Donde obtiene la localidad de referencia, la CPU puede operar a una velocidad cercana a la óptima. La memoria caché pierde hasta el siguiente nivel incurrir en una serie de estados de espera; la memoria caché se pierde en la memoria principal puede generar cientos.
Por lo tanto, el rendimiento real de los chips de la CPU puede depender en gran medida de la eficiencia de los patrones de acceso a la memoria. Se han escrito libros completos sobre cómo optimizar el código para esto, y es un tema complejo por derecho propio.