En el diseño de procesadores , el microcódigo sirve como una capa intermedia situada entre el hardware de la unidad central de procesamiento (CPU) y la arquitectura del conjunto de instrucciones visible para el programador de una computadora, también conocida como su código de máquina . [1] [ página necesaria ] Consiste en un conjunto de instrucciones a nivel de hardware que implementan las instrucciones de código de máquina de nivel superior o controlan la secuenciación interna de la máquina de estados finitos en muchos componentes de procesamiento digital . Si bien el microcódigo se utiliza en las CPU de propósito general de Intel y AMD en las computadoras de escritorio y portátiles contemporáneas, funciona solo como una ruta de respaldo para escenarios que la unidad de control cableada más rápida no puede manejar. [2]
El microcódigo, alojado en una memoria especial de alta velocidad, traduce instrucciones de máquina, datos de máquina de estados u otra entrada en secuencias de operaciones detalladas a nivel de circuito. Separa las instrucciones de máquina de la electrónica subyacente , lo que permite una mayor flexibilidad en el diseño y la modificación de instrucciones. Además, facilita la construcción de instrucciones complejas de varios pasos, al tiempo que reduce simultáneamente la complejidad de los circuitos informáticos. El acto de escribir microcódigo se suele denominar microprogramación , y el microcódigo en una implementación de procesador específica a veces se denomina microprograma .
Mediante una amplia microprogramación, las microarquitecturas de menor escala y simplicidad pueden emular arquitecturas más robustas con longitudes de palabra más amplias , unidades de ejecución adicionales , etc. Este enfoque proporciona un método relativamente sencillo para garantizar la compatibilidad de software entre diferentes productos dentro de una familia de procesadores.
Algunos proveedores de hardware, en particular IBM / Lenovo , utilizan el término microcódigo indistintamente con el de firmware . En este contexto, todo el código dentro de un dispositivo se denomina microcódigo, ya sea microcódigo o código de máquina. Por ejemplo, las actualizaciones del microcódigo de una unidad de disco duro a menudo incluyen actualizaciones tanto de su microcódigo como de su firmware. [3]
A nivel de hardware, los procesadores contienen una serie de áreas separadas de circuitos, o "unidades", que realizan diferentes tareas. Las unidades que se encuentran comúnmente incluyen la unidad aritmético lógica (ALU), que realiza instrucciones como la suma o la comparación de dos números, circuitos para leer y escribir datos en la memoria externa y pequeñas áreas de memoria integrada para almacenar estos valores mientras se procesan. En la mayoría de los diseños, se utiliza memoria adicional de alto rendimiento, el archivo de registros , para almacenar valores temporales, no solo los que necesita la instrucción actual. [4]
Para ejecutar correctamente una instrucción, los distintos circuitos deben activarse en orden. Por ejemplo, no es posible sumar dos números si aún no se han cargado desde la memoria. En los diseños RISC , el orden correcto de estas instrucciones depende en gran medida del programador, o al menos del compilador del lenguaje de programación que esté utilizando. Por lo tanto, para sumar dos números, por ejemplo, el compilador puede generar instrucciones para cargar uno de los valores en un registro, el segundo en otro, llamar a la función de suma en la ALU y luego escribir el resultado nuevamente en la memoria. [4]
Como la secuencia de instrucciones necesaria para completar este concepto de nivel superior, "sumar estos dos números en la memoria", puede requerir múltiples instrucciones, esto puede representar un cuello de botella en el rendimiento si esas instrucciones se almacenan en la memoria principal . Leer esas instrucciones una por una consume tiempo que podría usarse para leer y escribir los datos reales. Por esta razón, es común que los diseños no RISC tengan muchas instrucciones diferentes que difieren en gran medida en dónde almacenan los datos. Por ejemplo, el MOS 6502 tiene ocho variaciones de la instrucción de suma, ADC
, que difieren solo en dónde buscan encontrar los dos operandos. [5]
El uso de la variación de la instrucción, o " código de operación ", que más se acerque a la operación final puede reducir el número de instrucciones a una, ahorrando memoria utilizada por el código de programa y mejorando el rendimiento al dejar el bus de datos abierto para otras operaciones. Sin embargo, internamente, estas instrucciones no son operaciones separadas, sino secuencias de las operaciones que las unidades realmente realizan. Convertir una única instrucción leída desde la memoria en la secuencia de acciones internas es tarea de la unidad de control , otra unidad dentro del procesador. [6]
La idea básica detrás del microcódigo es reemplazar la lógica de hardware personalizada que implementa la secuencia de instrucciones con una serie de instrucciones simples que se ejecutan en un "motor de microcódigo" en el procesador. Mientras que un sistema lógico personalizado puede tener una serie de diodos y puertas que emiten una serie de voltajes en varias líneas de control, el motor de microcódigo está conectado a estas líneas, y estas se encienden y apagan a medida que el motor lee las instrucciones del microcódigo en secuencia. Las instrucciones del microcódigo a menudo están codificadas en bits para esas líneas, por ejemplo, si el bit 8 es verdadero, eso podría significar que la ALU debe pausarse esperando datos. En este sentido, el microcódigo es algo similar a los rollos de papel de una pianola , donde los agujeros representan qué tecla debe presionarse.
La distinción entre lógica personalizada y microcódigo puede parecer pequeña: uno utiliza un patrón de diodos y puertas para decodificar la instrucción y producir una secuencia de señales, mientras que el otro codifica las señales como microinstrucciones que se leen en secuencia para producir los mismos resultados. La diferencia fundamental es que en un diseño de lógica personalizada, los cambios en los pasos individuales requieren que se rediseñe el hardware. Al utilizar microcódigo, todo lo que cambia es el código almacenado en la memoria que contiene el microcódigo. Esto hace que sea mucho más fácil solucionar los problemas en un sistema de microcódigo. También significa que no hay un límite efectivo para la complejidad de las instrucciones, solo está limitada por la cantidad de memoria que uno esté dispuesto a utilizar.
La capa más baja de la pila de software de un ordenador está formada tradicionalmente por instrucciones en código máquina sin procesar para el procesador. En los procesadores microcodificados, la obtención y decodificación de esas instrucciones, y su ejecución, se puede realizar mediante microcódigo. Para evitar confusiones, cada elemento relacionado con un microprograma se diferencia por el prefijo micro : microinstrucción, microensamblador, microprogramador, etc. [7]
Los procesadores digitales complejos también pueden emplear más de una unidad de control (posiblemente basada en microcódigo) para delegar subtareas que deben realizarse esencialmente de forma asincrónica en paralelo. Por ejemplo, el VAX 9000 tiene una unidad IBox cableada para buscar y decodificar instrucciones, que entrega a una unidad EBox microcodificada para que las ejecute [8], y el VAX 8800 tiene tanto una IBox microcodificada como una EBox microcodificada [9] .
Un programador de alto nivel, o incluso un programador en lenguaje ensamblador , normalmente no ve ni modifica el microcódigo. A diferencia del código de máquina, que suele conservar cierta compatibilidad con versiones anteriores entre los distintos procesadores de una familia, el microcódigo solo se ejecuta en el circuito electrónico exacto para el que está diseñado, ya que constituye una parte inherente del diseño del procesador en sí.
Los ingenieros normalmente escriben el microcódigo durante la fase de diseño de un procesador, almacenándolo en una memoria de solo lectura (ROM) o una matriz lógica programable (PLA) [10] , o en una combinación de ambas. [11] Sin embargo, también existen máquinas que tienen parte o la totalidad del microcódigo almacenado en una memoria estática de acceso aleatorio (SRAM) o en una memoria flash . Esto se denomina tradicionalmente almacén de control escribible en el contexto de las computadoras, que puede ser de solo lectura o de lectura y escritura . En este último caso, el proceso de inicialización de la CPU carga el microcódigo en el almacén de control desde otro medio de almacenamiento, con la posibilidad de alterar el microcódigo para corregir errores en el conjunto de instrucciones o para implementar nuevas instrucciones de la máquina.
Los microprogramas consisten en una serie de microinstrucciones que controlan la CPU a un nivel muy fundamental de circuitos de hardware. Por ejemplo, una única microinstrucción horizontal típica podría especificar las siguientes operaciones:
Para controlar simultáneamente todas las funciones del procesador en un ciclo, la microinstrucción suele tener más de 50 bits; por ejemplo, 128 bits en un 360/85 con una función de emulador. Los microprogramas se diseñan y optimizan cuidadosamente para lograr la ejecución más rápida posible, ya que un microprograma lento daría como resultado una instrucción de máquina lenta y un rendimiento degradado para los programas de aplicación relacionados que utilizan dichas instrucciones.
El microcódigo se desarrolló originalmente como un método más simple para desarrollar la lógica de control de una computadora. Inicialmente, los conjuntos de instrucciones de la CPU estaban cableados . Cada paso necesario para obtener, decodificar y ejecutar las instrucciones de la máquina (incluidos los cálculos de direcciones de operandos, lecturas y escrituras) se controlaba directamente mediante lógica combinacional y circuitos de máquina de estados secuenciales bastante mínimos . Si bien estos procesadores cableados eran muy eficientes, la necesidad de conjuntos de instrucciones potentes con direccionamiento de múltiples pasos y operaciones complejas ( ver más abajo ) los hacía difíciles de diseñar y depurar; las instrucciones altamente codificadas y de longitud variada también pueden contribuir a esto, especialmente cuando se utilizan codificaciones muy irregulares.
El microcódigo simplificó el trabajo al permitir que gran parte del comportamiento del procesador y del modelo de programación se definieran mediante rutinas de microprogramas en lugar de circuitos dedicados. Incluso en una etapa avanzada del proceso de diseño, el microcódigo podía modificarse fácilmente, mientras que los diseños de CPU cableados eran muy engorrosos de modificar. Por lo tanto, esto facilitó enormemente el diseño de CPU.
Desde la década de 1940 hasta finales de la década de 1970, una gran parte de la programación se hacía en lenguaje ensamblador ; las instrucciones de nivel superior implican una mayor productividad del programador, por lo que una ventaja importante del microcódigo era la relativa facilidad con la que se podían definir instrucciones de máquina potentes. La máxima extensión de esto son los diseños de "lenguaje de alto nivel directamente ejecutable", en los que cada instrucción de un lenguaje de alto nivel como PL/I se ejecuta completa y directamente mediante microcódigo, sin compilación. El proyecto IBM Future Systems y el procesador Fountainhead de Data General son ejemplos de esto. Durante la década de 1970, las velocidades de la CPU crecieron más rápidamente que las velocidades de la memoria y se utilizaron numerosas técnicas como la transferencia de bloques de memoria , la precarga de memoria y las cachés de varios niveles para aliviar esto. Las instrucciones de máquina de alto nivel, posibilitadas por el microcódigo, ayudaron aún más, ya que menos instrucciones de máquina más complejas requieren menos ancho de banda de memoria. Por ejemplo, una operación en una cadena de caracteres se puede realizar como una sola instrucción de máquina, evitando así múltiples recuperaciones de instrucciones.
Las arquitecturas con conjuntos de instrucciones implementados por microprogramas complejos incluyeron el IBM System/360 y el Digital Equipment Corporation VAX . El enfoque de conjuntos de instrucciones implementados por microcódigo cada vez más complejos se denominó posteriormente computadora de conjunto de instrucciones complejas (CISC). Un enfoque alternativo, utilizado en muchos microprocesadores , es utilizar una o más matrices lógicas programables (PLA) o memoria de solo lectura (ROM) (en lugar de lógica combinacional) principalmente para la decodificación de instrucciones, y dejar que una máquina de estados simple (sin mucho o ningún microcódigo) haga la mayor parte de la secuenciación. El MOS Technology 6502 es un ejemplo de un microprocesador que utiliza una PLA para la decodificación y secuenciación de instrucciones. La PLA es visible en fotomicrografías del chip, [12] y su funcionamiento se puede ver en la simulación a nivel de transistor .
La microprogramación todavía se utiliza en los diseños de CPU modernos. En algunos casos, después de depurar el microcódigo en la simulación, se sustituyen las funciones lógicas por el almacén de control. [ cita requerida ] Las funciones lógicas suelen ser más rápidas y menos costosas que la memoria de microprograma equivalente.
Los microprogramas de un procesador funcionan en una arquitectura más primitiva, totalmente diferente y mucho más orientada al hardware que las instrucciones de ensamblaje visibles para los programadores normales. En coordinación con el hardware, el microcódigo implementa la arquitectura visible para el programador. El hardware subyacente no necesita tener una relación fija con la arquitectura visible. Esto hace que sea más fácil implementar una arquitectura de conjunto de instrucciones dada en una amplia variedad de microarquitecturas de hardware subyacentes.
El IBM System/360 tiene una arquitectura de 32 bits con 16 registros de propósito general, pero la mayoría de las implementaciones del System/360 utilizan hardware que implementa una microarquitectura subyacente mucho más simple; por ejemplo, el System/360 Modelo 30 tiene rutas de datos de 8 bits a la unidad lógica aritmética (ALU) y la memoria principal e implementó los registros de propósito general en una unidad especial de memoria central de mayor velocidad , y el System/360 Modelo 40 tiene rutas de datos de 8 bits a la ALU y rutas de datos de 16 bits a la memoria principal y también implementó los registros de propósito general en una unidad especial de memoria central de mayor velocidad. El Modelo 50 tiene rutas de datos completas de 32 bits e implementa los registros de propósito general en una unidad especial de memoria central de mayor velocidad. [13] Los modelos 65 a 195 tienen rutas de datos más grandes e implementan los registros de propósito general en circuitos de transistores más rápidos. [ cita requerida ] De esta manera, la microprogramación permitió a IBM diseñar muchos modelos System/360 con hardware sustancialmente diferente y que abarcaban una amplia gama de costos y rendimiento, al mismo tiempo que los hacía compatibles arquitectónicamente. Esto reduce drásticamente la cantidad de programas de software de sistema únicos que deben escribirse para cada modelo.
Digital Equipment Corporation (DEC) utilizó un enfoque similar en su familia de computadoras VAX. Como resultado, los distintos procesadores VAX utilizan microarquitecturas diferentes, pero la arquitectura visible para el programador no cambia.
La microprogramación también reduce el costo de los cambios de campo para corregir defectos ( errores ) en el procesador; un error a menudo se puede solucionar reemplazando una parte del microprograma en lugar de realizar cambios en la lógica y el cableado del hardware .
En 1947, el diseño del MIT Whirlwind introdujo el concepto de un almacén de control como una forma de simplificar el diseño de computadoras e ir más allá de los métodos ad hoc . El almacén de control es una matriz de diodos : una red bidimensional, donde una dimensión acepta "pulsos de tiempo de control" del reloj interno de la CPU, y la otra se conecta a las señales de control en las puertas y otros circuitos. Un "distribuidor de pulsos" toma los pulsos generados por el reloj de la CPU y los divide en ocho pulsos de tiempo separados, cada uno de los cuales activa una fila diferente de la red. Cuando la fila se activa, activa las señales de control conectadas a ella. [14]
En 1951, Maurice Wilkes [15] mejoró este concepto añadiendo la ejecución condicional , un concepto similar al condicional en el software informático. Su implementación inicial consistía en un par de matrices: la primera generaba señales a la manera del almacén de control Whirlwind, mientras que la segunda matriz seleccionaba qué fila de señales (la palabra de instrucción del microprograma, por así decirlo) invocar en el siguiente ciclo. Los condicionales se implementaron proporcionando una forma en la que una sola línea en el almacén de control podía elegir entre alternativas en la segunda matriz. Esto hacía que las señales de control fueran condicionales a la señal interna detectada. Wilkes acuñó el término microprogramación para describir esta característica y distinguirla de un simple almacén de control.
El microcódigo siguió siendo relativamente raro en el diseño de computadoras, ya que el costo de la ROM necesaria para almacenar el código no era significativamente diferente al de usar un almacén de control personalizado. Esto cambió a principios de la década de 1960 con la introducción de la memoria central producida en masa y la memoria central , que era mucho menos costosa que la lógica dedicada basada en matrices de diodos o soluciones similares. El primero en aprovechar esto realmente fue IBM en su serie System/360 de 1964. Esto permitió que las máquinas tuvieran un conjunto de instrucciones muy complejo, incluidas operaciones que coincidían con construcciones de lenguaje de alto nivel como formatear valores binarios como cadenas decimales, almacenando la serie compleja de instrucciones necesarias para esta tarea en una memoria de bajo costo. [16]
Pero el valor real de la línea 360 era que se podía construir una serie de máquinas que eran completamente diferentes internamente, pero que ejecutaban la misma ISA. Para una máquina de gama baja, se podía utilizar una ALU de 8 bits que requería varios ciclos para completar una única suma de 32 bits, mientras que una máquina de gama alta podía tener una ALU completa de 32 bits que realizaba la misma suma en un único ciclo. Estas diferencias se podían implementar en la lógica de control, pero el coste de implementar un decodificador completamente diferente para cada máquina sería prohibitivo. El uso de microcódigo significaba que todo lo que cambiaba era el código en la ROM. Por ejemplo, una máquina podía incluir una unidad de punto flotante y, por lo tanto, su microcódigo para multiplicar dos números podía ser de sólo unas pocas líneas, mientras que en la misma máquina sin la FPU este sería un programa que hiciera lo mismo utilizando múltiples sumas, y todo lo que cambiaría era la ROM. [16]
El resultado de este diseño fue que los clientes podían utilizar un modelo de gama baja de la familia para desarrollar su software, sabiendo que si alguna vez necesitaban más rendimiento, podían pasar a una versión más rápida y nada más cambiaría. Esto redujo la barrera de entrada y el 360 fue un éxito rotundo. A finales de la década, el uso de microcódigo era de rigor en toda la industria de mainframes.
Las primeras minicomputadoras eran demasiado simples como para requerir microcódigo y eran más similares a las mainframes anteriores en términos de sus conjuntos de instrucciones y la forma en que se decodificaban. Pero no pasó mucho tiempo antes de que sus diseñadores comenzaran a utilizar circuitos integrados más potentes que permitían ISA más complejas. A mediados de la década de 1970, la mayoría de las nuevas minicomputadoras y superminicomputadoras también usaban microcódigo, como la mayoría de los modelos de la PDP-11 y, más notablemente, la mayoría de los modelos de la VAX , que incluían instrucciones de alto nivel no muy diferentes a las que se encontraban en la 360. [17]
La misma evolución básica ocurrió también con los microprocesadores . Los primeros diseños eran extremadamente simples, e incluso los diseños de 8 bits más potentes de mediados de la década de 1970, como el Zilog Z80, tenían conjuntos de instrucciones que eran lo suficientemente simples como para implementarse en una lógica dedicada. En ese momento, la lógica de control podía diseñarse en el mismo chip que la CPU, lo que hacía que la diferencia de costo entre la ROM y la lógica fuera un problema menor. Sin embargo, no pasó mucho tiempo antes de que estas empresas también se enfrentaran al problema de introducir diseños de mayor rendimiento pero que aún quisieran ofrecer compatibilidad con versiones anteriores . Entre los primeros ejemplos de microcódigo en micros se encontraba el Intel 8086. [ 6]
Entre las últimas implementaciones de microcódigo en microprocesadores se encuentra el Motorola 68000. Este ofrecía un conjunto de instrucciones altamente ortogonal con una amplia variedad de modos de direccionamiento , todos implementados en microcódigo. Esto no se produjo sin costo, según los primeros artículos, aproximadamente el 20% de la superficie del chip (y, por lo tanto, el costo) es el sistema de microcódigo. [18] y estimaciones posteriores sugieren que aproximadamente 23.000 de las 68.000 puertas del sistema eran parte del sistema de microcódigo.
Mientras las empresas seguían compitiendo en la complejidad de sus conjuntos de instrucciones, y el uso de microcódigo para implementarlos era incuestionable, a mediados de la década de 1970 un proyecto interno en IBM estaba planteando serias dudas sobre todo el concepto. Como parte de un proyecto para desarrollar un conmutador telefónico totalmente digital de alto rendimiento , un equipo dirigido por John Cocke comenzó a examinar enormes volúmenes de datos de rendimiento de los programas 360 (y System/370 ) de sus clientes . Esto los llevó a notar un patrón curioso: cuando la ISA presentaba múltiples versiones de una instrucción, el compilador casi siempre usaba la más simple, en lugar de la que representaba más directamente el código. Aprendieron que esto se debía a que esas instrucciones siempre se implementaban en hardware y, por lo tanto, se ejecutaban más rápido. El uso de la otra instrucción podría ofrecer un mayor rendimiento en algunas máquinas, pero no había forma de saber en qué máquina se estaban ejecutando. Esto frustraba el propósito de usar microcódigo en primer lugar, que era ocultar estas distinciones. [19]
El equipo llegó a una conclusión radical: "Imponer un microcódigo entre una computadora y sus usuarios supone una sobrecarga costosa a la hora de ejecutar las instrucciones que se ejecutan con mayor frecuencia". [19]
El resultado de este descubrimiento fue lo que hoy se conoce como el concepto RISC . El complejo motor de microcódigo y su ROM asociada se reducen o eliminan por completo, y esos circuitos se dedican en su lugar a cosas como registros adicionales o una ALU más amplia, lo que aumenta el rendimiento de cada programa. Cuando se necesitan secuencias complejas de instrucciones, esto se deja en manos del compilador, que es el propósito principal de usar un compilador en primer lugar. El concepto básico fue rápidamente recogido por investigadores universitarios en California, donde las simulaciones sugirieron que tales diseños superarían trivialmente incluso a los diseños convencionales más rápidos. Fue uno de esos proyectos, en la Universidad de California, Berkeley , el que introdujo el término RISC.
La industria respondió al concepto de RISC con confusión y hostilidad, incluido un famoso artículo despectivo del equipo VAX en Digital. [20] Un punto importante de discordia fue que implementar las instrucciones fuera del procesador significaba que pasaría mucho más tiempo leyendo esas instrucciones desde la memoria, lo que ralentizaría el rendimiento general sin importar cuán rápido funcionara la propia CPU. [20] Los defensores señalaron que las simulaciones mostraban claramente que la cantidad de instrucciones no era mucho mayor, especialmente cuando se consideraba el código compilado. [19]
El debate se prolongó hasta que surgieron los primeros diseños comerciales RISC en la segunda mitad de la década de 1980, que superaron fácilmente a los diseños más complejos de otras empresas. A finales de la década de 1980, se acabó; incluso DEC estaba abandonando el microcódigo para sus diseños DEC Alpha , y los procesadores CISC pasaron a utilizar circuitos cableados, en lugar de microcódigo, para realizar muchas funciones. Por ejemplo, el Intel 80486 utiliza circuitos cableados para buscar y decodificar instrucciones, utilizando microcódigo solo para ejecutar instrucciones; el movimiento de registro a registro y las instrucciones aritméticas requerían solo una microinstrucción, lo que les permitía completarse en un ciclo de reloj. [21] El hardware de búsqueda y decodificación del Pentium Pro busca instrucciones y las decodifica en series de microoperaciones que se pasan a la unidad de ejecución, que programa y ejecuta las microoperaciones, posiblemente haciéndolo fuera de orden . Las instrucciones complejas se implementan mediante microcódigo que consiste en secuencias predefinidas de microoperaciones. [22]
Algunos diseños de procesadores utilizan código de máquina que se ejecuta en un modo especial, con instrucciones especiales, disponibles sólo en ese modo, que tienen acceso al hardware dependiente del procesador, para implementar algunas características de bajo nivel del conjunto de instrucciones. El DEC Alpha, un diseño RISC puro, utilizó PALcode para implementar características como el manejo de errores del buffer de traducción lookaside (TLB) y el manejo de interrupciones, [23] así como para proporcionar, para sistemas basados en Alpha que ejecutan OpenVMS , instrucciones que requieren acceso a memoria entrelazada que son similares a las instrucciones proporcionadas por la arquitectura VAX . [23] Las CPU IBM System/390 CMOS , comenzando con el procesador G4, y las CPU z/Architecture utilizan milicode para implementar algunas instrucciones. [24]
Cada microinstrucción de un microprograma proporciona los bits que controlan los elementos funcionales que componen internamente una CPU. La ventaja con respecto a una CPU cableada es que el control interno de la CPU se convierte en una forma especializada de un programa informático. De este modo, el microcódigo transforma un complejo desafío de diseño electrónico (el control de una CPU) en un desafío de programación menos complejo. Para aprovechar esto, una CPU se divide en varias partes:
También puede haber un registro de dirección de memoria y un registro de datos de memoria , utilizados para acceder al almacenamiento principal del ordenador . Juntos, estos elementos forman una " unidad de ejecución ". La mayoría de las CPU modernas tienen varias unidades de ejecución. Incluso los ordenadores sencillos suelen tener una unidad para leer y escribir en la memoria, y otra para ejecutar el código de usuario. Estos elementos a menudo se podrían reunir como un solo chip. Este chip viene en un ancho fijo que formaría una "rebanada" a través de la unidad de ejecución. Estos se conocen como chips " bit slice ". La familia AMD Am2900 es uno de los ejemplos más conocidos de elementos bit slice. [39] Las partes de las unidades de ejecución y las unidades de ejecución en su conjunto están interconectadas por un haz de cables llamado bus .
Los programadores desarrollan microprogramas, utilizando herramientas de software básicas. Un microensamblador permite a un programador definir la tabla de bits simbólicamente. Debido a su estrecha relación con la arquitectura subyacente, "el microcódigo tiene varias propiedades que dificultan su generación mediante un compilador". [1] Un programa simulador está destinado a ejecutar los bits de la misma manera que la electrónica, y permite mucha más libertad para depurar el microprograma. Una vez que el microprograma está finalizado y probado exhaustivamente, a veces se utiliza como entrada para un programa informático que construye la lógica para producir los mismos datos. [ cita requerida ] Este programa es similar a los utilizados para optimizar una matriz lógica programable . Incluso sin una lógica completamente óptima, la lógica optimizada heurísticamente puede reducir enormemente la cantidad de transistores de la cantidad necesaria para un almacén de control de memoria de solo lectura (ROM). Esto reduce el costo de producción y la electricidad utilizada por una CPU.
El microcódigo se puede caracterizar como horizontal o vertical , haciendo referencia principalmente a si cada microinstrucción controla elementos de la CPU con poca o ninguna decodificación (microcódigo horizontal) [a] o requiere una decodificación extensa mediante lógica combinatoria antes de hacerlo (microcódigo vertical). En consecuencia, cada microinstrucción horizontal es más ancha (contiene más bits) y ocupa más espacio de almacenamiento que una microinstrucción vertical.
"El microcódigo horizontal tiene varias microoperaciones discretas que se combinan en una única microinstrucción para su funcionamiento simultáneo". [1] El microcódigo horizontal suele estar contenido en un almacén de control bastante amplio; no es raro que cada palabra tenga 108 bits o más. En cada tic del reloj de un secuenciador se lee, decodifica y utiliza una palabra de microcódigo para controlar los elementos funcionales que componen la CPU.
En una implementación típica, una palabra de microprograma horizontal comprende grupos de bits bastante definidos. Por ejemplo, una disposición simple podría ser:
Para que este tipo de micromáquina implemente una instrucción JUMP con la dirección a continuación del código de operación, el microcódigo podría requerir dos ticks de reloj. El ingeniero que lo diseñe escribiría un código fuente en microensamblador que se parecería a esto:
# Cualquier línea que comience con un signo de número es un comentario # Esto es solo una etiqueta, la forma habitual en que los ensambladores representan simbólicamente una # dirección de memoria. InstrucciónJUMP : # Para prepararse para la siguiente instrucción, el microcódigo de decodificación de instrucciones ya ha # movido el contador de programa al registro de dirección de memoria. Esta instrucción obtiene # la dirección de destino de la instrucción de salto de la palabra de memoria que sigue al # código de operación de salto, copiando desde el registro de datos de memoria al registro de dirección de memoria. # Esto le da al sistema de memoria dos tics de reloj para obtener la siguiente # instrucción en el registro de datos de memoria para que la use la decodificación de instrucciones. # La instrucción del secuenciador "next" significa simplemente agregar 1 a la dirección de la palabra de control. MDR , NONE , MAR , COPY , NEXT , NONE # Esto coloca la dirección de la siguiente instrucción en la PC. # Esto le da al sistema de memoria un tic de reloj para finalizar la búsqueda iniciada en la # microinstrucción anterior. # La instrucción del secuenciador es saltar al inicio de la decodificación de instrucciones. MAR , 1 , PC , ADD , JMP , InstructionDecode # La decodificación de la instrucción no se muestra, porque suele ser un caos, muy particular # para el procesador exacto que se está emulando. Incluso este ejemplo está simplificado. # Muchas CPU tienen varias formas de calcular la dirección, en lugar de simplemente obtenerla # de la palabra que sigue al código de operación. Por lo tanto, en lugar de solo una # instrucción de salto, esas CPU tienen una familia de instrucciones de salto relacionadas.
Es común encontrar que para cada tick solo se utilizan algunas porciones de la CPU, y que los grupos de bits restantes de la microinstrucción no realizan operaciones. Con un diseño cuidadoso del hardware y del microcódigo, esta propiedad se puede aprovechar para paralelizar operaciones que utilizan diferentes áreas de la CPU; por ejemplo, en el caso anterior, la ALU no es necesaria durante el primer tick, por lo que podría utilizarse potencialmente para completar una instrucción aritmética anterior.
En el microcódigo vertical, cada microinstrucción está codificada de forma significativa, es decir, los campos de bits generalmente pasan por una lógica combinatoria intermedia que, a su vez, genera las señales de control y secuenciación para los elementos internos de la CPU (ALU, registros, etc.). Esto contrasta con el microcódigo horizontal, en el que los campos de bits producen directamente las señales de control y secuenciación o solo están codificados mínimamente. En consecuencia, el microcódigo vertical requiere longitudes de instrucción más pequeñas y menos almacenamiento, pero requiere más tiempo para decodificar, lo que resulta en un reloj de CPU más lento. [40]
Algunos microcódigos verticales son simplemente el lenguaje ensamblador de una computadora convencional simple que emula una computadora más compleja. Algunos procesadores, como los procesadores DEC Alpha y los microprocesadores CMOS en los mainframes IBM posteriores System/390 y z/Architecture , usan código de máquina, ejecutándose en un modo especial que le da acceso a instrucciones especiales, registros especiales y otros recursos de hardware no disponibles para el código de máquina regular, para implementar algunas instrucciones y otras funciones, [41] [42] como los recorridos de tabla de páginas en los procesadores Alpha. [43] Esto se llama PALcode en los procesadores Alpha y millicode en los procesadores mainframe IBM.
Otra forma de microcódigo vertical tiene dos campos:
El campo select selecciona qué parte de la CPU será controlada por esta palabra del almacén de control. El campo value controla esa parte de la CPU. Con este tipo de microcódigo, un diseñador elige explícitamente hacer una CPU más lenta para ahorrar dinero al reducir los bits no utilizados en el almacén de control; sin embargo, la complejidad reducida puede aumentar la frecuencia de reloj de la CPU, lo que disminuye el efecto de un mayor número de ciclos por instrucción.
A medida que los transistores se volvieron más baratos, el microcódigo horizontal pasó a dominar el diseño de CPU que utilizaban microcódigo, mientras que el microcódigo vertical se utilizó con menos frecuencia.
Cuando se utilizan tanto microcódigos verticales como horizontales, el microcódigo horizontal puede denominarse nanocódigo o picocódigo . [44]
Se construyeron algunas computadoras que utilizaban microcódigo escribible . En este diseño, en lugar de almacenar el microcódigo en la ROM o en una lógica cableada, el microcódigo se almacena en una RAM llamada almacén de control escribible o WCS . A este tipo de computadora a veces se la denomina computadora con conjunto de instrucciones escribibles (WISC). [45]
Muchos prototipos de computadoras experimentales utilizan almacenes de control grabables; también hay máquinas comerciales que utilizan microcódigo grabable, como los Burroughs Small Systems , las primeras estaciones de trabajo Xerox , la familia DEC VAX 8800 ( Nautilus ), las máquinas L y G de Symbolics , varias implementaciones IBM System/360 y System/370 , algunas máquinas DEC PDP-10 , [46] y el Data General Eclipse MV/8000 . [47]
El IBM System/370 incluye una función denominada Carga inicial de microprogramas ( IML o IMPL ) [48] que se puede invocar desde la consola, como parte del reinicio de encendido ( POR ) o desde otro procesador en un complejo multiprocesador estrechamente acoplado .
Algunas máquinas comerciales, por ejemplo IBM 360/85, [49] [50] tienen un almacenamiento de solo lectura y un almacenamiento de control escribible para microcódigo.
WCS ofrece varias ventajas, entre ellas, la facilidad para aplicar parches al microprograma y, para ciertas generaciones de hardware, un acceso más rápido que el que pueden proporcionar las ROM. WCS programable por el usuario permite que este optimice la máquina para fines específicos.
A partir del Pentium Pro en 1995, varias CPU x86 tienen microcódigo Intel escribible . [51] [52] Esto, por ejemplo, ha permitido que los errores en los microcódigos Intel Core 2 e Intel Xeon se solucionen mediante parches de sus microprogramas, en lugar de requerir que se reemplacen los chips completos. Un segundo ejemplo destacado es el conjunto de parches de microcódigo que Intel ofreció para algunas de sus arquitecturas de procesadores de hasta 10 años de antigüedad, en un intento de contrarrestar las vulnerabilidades de seguridad descubiertas en sus diseños ( Spectre y Meltdown ), que se hicieron públicos a principios de 2018. [53] [54] Se puede instalar una actualización de microcódigo mediante Linux, [55] FreeBSD , [56] Microsoft Windows, [57] o el BIOS de la placa base. [58]
Algunas máquinas ofrecen como opción almacenes de control programables por el usuario, entre ellas las minicomputadoras HP 2100 , DEC PDP-11/60 , TI-990 /12, [59] [60] y Varian Data Machines serie V-70 .
La tendencia de diseño hacia procesadores altamente microcodificados con instrucciones complejas comenzó a principios de la década de 1960 y continuó hasta aproximadamente mediados de la década de 1980. En ese momento, la filosofía de diseño RISC comenzó a adquirir mayor importancia.
Una CPU que utiliza microcódigo generalmente tarda varios ciclos de reloj en ejecutar una sola instrucción, un ciclo de reloj para cada paso del microprograma correspondiente a esa instrucción. Algunos procesadores CISC incluyen instrucciones que pueden tardar mucho tiempo en ejecutarse. Estas variaciones interfieren tanto con la latencia de las interrupciones como, lo que es mucho más importante en los sistemas modernos, con la segmentación .
Al diseñar un nuevo procesador, un RISC de control cableado tiene las siguientes ventajas sobre el CISC microcodificado:
También hay contrapuntos:
Muchos procesadores RISC y VLIW están diseñados para ejecutar cada instrucción (siempre que esté en la caché) en un solo ciclo. Esto es muy similar a la forma en que las CPU con microcódigo ejecutan una microinstrucción por ciclo. Los procesadores VLIW tienen instrucciones que se comportan de manera similar a un microcódigo horizontal muy amplio, aunque normalmente sin un control tan detallado sobre el hardware como el que proporciona el microcódigo. Las instrucciones RISC a veces son similares al microcódigo vertical estrecho.
El microcódigo ha sido popular en procesadores de aplicaciones específicas, como procesadores de red , procesadores de señales digitales , controladores de canal , controladores de disco , controladores de interfaz de red , controladores de memoria flash , unidades de procesamiento de gráficos y en otro hardware.
Las implementaciones modernas de CISC, como la familia x86 que comienza con NexGen Nx586, Intel Pentium Pro y AMD K5 , decodifican instrucciones en microoperaciones almacenadas dinámicamente con una codificación de instrucciones similar a RISC o al microcódigo tradicional. Una unidad de decodificación de instrucciones cableada emite directamente microoperaciones para instrucciones x86 comunes, pero recurre a una ROM de microcódigo más tradicional que contiene microoperaciones para instrucciones más complejas o raramente utilizadas. [2]
Por ejemplo, un x86 puede buscar microoperaciones en el microcódigo para manejar operaciones complejas de varios pasos, como instrucciones de bucle o de cadena, funciones trascendentales de unidad de punto flotante o valores inusuales como números desnormalizados e instrucciones de propósito especial como CPUID .
de control escribible en SRAM de 4096 x 75 bits: microinstrucción de 74 bits con 1 bit de paridad (18 campos)
{{cite book}}
: CS1 maint: location (link)